Daily Code Reading #4 – Facets Hash#reverse_merge

Rails uses Hashes a lot for passing options to methods. I typically use Hash#merge to add any default options to them but I’ve always hated the syntax and frequently got it backwards.

1
options = {:value => 'default', :size => 30}.merge(options)

Facets has a Hash#reverse_merge that gets the order right. And the implementation is so simple, I’m kicking myself for not using it sooner.

The Code

1
2
3
4
# File lib/core/facets/hash/merge.rb, line 15
  def reverse_merge(other)
    other.merge(self)
  end

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/ruby -wKU
#
# Code Reading #4
require '../base'
require "facets/hash/merge"
 
class Example
  def self.create
    {
      :users => [:edavis],
      :servers => [:app1, :app2, :app3]
    }
  end
end
 
ap(Example.create.reverse_merge({
                                  :shell => '/bin/bash',
                                  :users => [:rails]
                                }))
 
class HashReverseMerge  '/bin/bash'})
 
    assert_equal '/bin/bash', @example[:shell]
    assert_equal [:edavis], @example[:users]
  end
 
  def test_should_let_the_caller_win
    @example = Example.create.reverse_merge({
                                              :shell => '/bin/bash',
                                              :users => [:rails]
                                            })
 
    assert_equal '/bin/bash', @example[:shell]
    assert_equal [:edavis], @example[:users]
  end
end

On github

Review

Now I can rewrite the default options like:

1
options = options.reverse_merge({:value => 'default', :size => 30})

(There are also bang versions, #merge! and #reverse_merge!)