From 0438134476b05d14dffbb28f84eac582bd3cfa8f Mon Sep 17 00:00:00 2001 From: Corey Ward Date: Sat, 2 Nov 2013 17:03:43 -0500 Subject: =?UTF-8?q?Fix=20Hash#deep=5Fmerge=20bug=20and=20improve=20documen?= =?UTF-8?q?tation=20=E2=80=94=20resolves=20#12738?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously merging into a hash with a falsy value would not result in the merge-block being called. The fix is simply to check for presence of the key in the hash. The documentation example for `deep_merge` now appropriately demonstrates what a deep merge does. --- .../lib/active_support/core_ext/hash/deep_merge.rb | 32 ++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'activesupport/lib/active_support/core_ext') diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb index dc86c92003..b53fa524c6 100644 --- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb @@ -1,25 +1,35 @@ class Hash # Returns a new hash with +self+ and +other_hash+ merged recursively. # - # h1 = { x: { y: [4, 5, 6] }, z: [7, 8, 9] } - # h2 = { x: { y: [7, 8, 9] }, z: 'xyz' } + # h1 = { a: true, b: { c: [1,2,3] } } + # h2 = { a: false, b: { x: [3,4,5] } } # - # h1.deep_merge(h2) # => {x: {y: [7, 8, 9]}, z: "xyz"} - # h2.deep_merge(h1) # => {x: {y: [4, 5, 6]}, z: [7, 8, 9]} - # h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) } - # # => {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]} + # h1.deep_merge(h2) #=> { a: false, b: { c: [1,2,3], x: [3,4,5] } } + # + # Like with Hash#merge in the standard library, a block can be provided + # to merge values: + # + # h1 = { a: 100, b: 200, c: { c1: 100 } } + # h2 = { b: 250, c: { c1: 200 } } + # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val } + # # => { a: 100, b: 450, c: { c1: 300 } } def deep_merge(other_hash, &block) dup.deep_merge!(other_hash, &block) end # Same as +deep_merge+, but modifies +self+. def deep_merge!(other_hash, &block) - other_hash.each_pair do |k,v| - tv = self[k] - if tv.is_a?(Hash) && v.is_a?(Hash) - self[k] = tv.deep_merge(v, &block) + other_hash.each_pair do |current_key, other_value| + this_value = self[current_key] + + self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash) + this_value.deep_merge(other_value, &block) else - self[k] = block && tv ? block.call(k, tv, v) : v + if block_given? && key?(current_key) + block.call(current_key, this_value, other_value) + else + other_value + end end end self -- cgit v1.2.3