Ruby Tuesday – Hash#merge

Today’s Ruby Tuesday covers Hash#merge.

Hash#merge takes a hash as it’s argument, and returns a new hash with the combined items from both hashes.

{a: 1, b: 2, c: 3}.merge({d: 1, e: 2, f: 3})
# {:a=>1, :b=>2, :c=>3, :d=>1, :e=>2, :f=>3}

Hash#merge has the ability to take a block which allows you to specify behavior of what you would like to happen when key collisions are encountered.

{a: 1, b: 2, c: 3, d: 4}.merge({a: 4, s: 3, d: 2, f: 1}) {|key, val1, val2| val1 * val2 }
# {:a=>4, :b=>2, :c=>3, :d=>8, :s=>3, :f=>1}
{a: 1, b: 2, c: 3, d: 4}.merge({a: 4, s: 3, d: 2, f: 1}) {|key, val1, val2| [val1, val2] }
# {:a=>[1, 4], :b=>2, :c=>3, :d=>[4, 2], :s=>3, :f=>1}

If a key is present in both hashes and no block is given, Hash#merge takes the value for the key from the hash that is passed into the merge method. This behaves as if you passed a block that returned the value for the second hash.

{a: 1, b: 2, c: 3, d: 4}.merge({a: 4, s: 3, d: 2, f: 1})
# {:a=>4, :b=>2, :c=>3, :d=>2, :s=>3, :f=>1}
{a: 1, b: 2, c: 3, d: 4}.merge({a: 4, s: 3, d: 2, f: 1}) {|key, val1, val2| val2 }
# {:a=>4, :b=>2, :c=>3, :d=>2, :s=>3, :f=>1}

If you would rather have the value from the hash that merge is being called on in the case of a key collision, you can provide a block that returns the value from the first hash.

{a: 1, b: 2, c: 3, d: 4}.merge({a: 4, s: 3, d: 2, f: 1})
# {:a=>4, :b=>2, :c=>3, :d=>2, :s=>3, :f=>1}
{a: 1, b: 2, c: 3, d: 4}.merge({a: 4, s: 3, d: 2, f: 1}) {|key, val1, val2| val1 }
# {:a=>1, :b=>2, :c=>3, :d=>4, :s=>3, :f=>1}

Hash#merge is especially useful if you take in an options hash of values because you don’t want to force the consumer of the method to have to specify every single property that someone could possibly want.

By using Hash#merge, your method can have a hash that represents the defaults, which you merge with the options that they passed in to get a complete list of all of the possible options.

defaults = {happy: true, hungry: false, sleepy: false}
# {:happy=>true, :hungry=>false, :sleepy=>false}
method_args = {hungry: true}
# {:hungry=>true}
settings = defaults.merge(method_args)
# {:happy=>true, :hungry=>true, :sleepy=>false}

–Proctor