From 9cb4febaff82902ae928a6532bb78223ca8eb7cf Mon Sep 17 00:00:00 2001 From: Alvaro Bautista Date: Sun, 31 Oct 2010 11:11:06 +0100 Subject: [PATCH] Support for passing a block when merging HashWithIndifferentAccess --- .../active_support/hash_with_indifferent_access.rb | 6 ++-- activesupport/test/core_ext/hash_ext_test.rb | 29 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index c406dd3..f323689 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -58,7 +58,7 @@ module ActiveSupport # hash_1.update(hash_2) # => {"key"=>"New Value!"} # def update(other_hash) - other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) } + other_hash.each_pair { |key, value| regular_writer(convert_key(key), block_given? && include?(key) ? yield(key, self[key], convert_value(value)) : convert_value(value)) } self end @@ -102,8 +102,8 @@ module ActiveSupport # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash # Does not overwrite the existing hash. - def merge(hash) - self.dup.update(hash) + def merge(hash, &block) + self.dup.update(hash, &block) end # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 545fed2..701849d 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -215,6 +215,35 @@ class HashExtTest < Test::Unit::TestCase assert_equal 2, hash['b'] end + def test_indifferent_merging_with_block + hash = HashWithIndifferentAccess.new + hash[:a] = 'failure' + hash['b'] = 'failure' + hash['c'] = 'something' + other = { 'a' => 'should not be a failure', :b => 'fail' } + + merged = hash.merge(other) { |key,oldval,newval| newval.size > oldval.size ? newval : oldval } + + assert_equal HashWithIndifferentAccess, merged.class + assert_equal 'should not be a failure', merged[:a] + assert_equal 'failure', merged['b'] + assert_equal 'something', merged['c'] + + hash.update(other) { |key,oldval,newval| newval.size > oldval.size ? newval : oldval } + + assert_equal 'should not be a failure', hash[:a] + assert_equal 'failure', hash['b'] + assert_equal 'something', hash['c'] + + # Block should be called only for keys existing in the receiver + keys_in_block = [] + merged = hash.merge({ :a => 'not a failure at all', :d => 'not in hash' }) { |key,oldval,newval| keys_in_block << key.to_s; newval } + assert_equal 'not a failure at all', merged[:a] + assert_equal 'not in hash', merged['d'] + assert keys_in_block.include?('a') + assert !keys_in_block.include?('d') + end + def test_indifferent_reverse_merging hash = HashWithIndifferentAccess.new('some' => 'value', 'other' => 'value') hash.reverse_merge!(:some => 'noclobber', :another => 'clobber') -- 1.7.2.2