From 8674417358b56d382f5615b9a4a464e9c862969c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Wn=C4=99trzak?= Date: Wed, 7 Aug 2019 18:31:33 +0200 Subject: [PATCH] Support multiple arguments in `HashWithIndifferentAccess` for `merge` and `update` methods It follows Ruby 2.6 addition https://github.com/ruby/ruby/pull/1951 --- activesupport/CHANGELOG.md | 5 +++ .../hash_with_indifferent_access.rb | 39 ++++++++++++------- .../test/hash_with_indifferent_access_test.rb | 16 ++++++++ 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index dad7005eb1..ce5a22bea6 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,8 @@ +* Support multiple arguments in `HashWithIndifferentAccess` for `merge` and `update` methods, to + follow Ruby 2.6 addition. + + *Wojciech Wnętrzak* + * Allow initializing `thread_mattr_*` attributes via `:default` option class Scraper diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 6acf64cb39..9f4d3e6ef3 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -96,7 +96,7 @@ module ActiveSupport alias_method :store, :[]= - # Updates the receiver in-place, merging in the hash passed as argument: + # Updates the receiver in-place, merging in the hashes passed as argument: # # hash_1 = ActiveSupport::HashWithIndifferentAccess.new # hash_1[:key] = 'value' @@ -106,7 +106,10 @@ module ActiveSupport # # hash_1.update(hash_2) # => {"key"=>"New Value!"} # - # The argument can be either an + # hash = ActiveSupport::HashWithIndifferentAccess.new + # hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 } + # + # The arguments can be either an # ActiveSupport::HashWithIndifferentAccess or a regular +Hash+. # In either case the merge respects the semantics of indifferent access. # @@ -121,18 +124,15 @@ module ActiveSupport # hash_1[:key] = 10 # hash_2['key'] = 12 # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22} - def update(other_hash) - if other_hash.is_a? HashWithIndifferentAccess - super(other_hash) + def update(*other_hashes, &block) + if other_hashes.one? + update_with_single_argument(other_hashes.first, block) else - other_hash.to_hash.each_pair do |key, value| - if block_given? && key?(key) - value = yield(convert_key(key), self[key], value) - end - regular_writer(convert_key(key), convert_value(value)) + other_hashes.each do |other_hash| + update_with_single_argument(other_hash, block) end - self end + self end alias_method :merge!, :update @@ -259,8 +259,8 @@ module ActiveSupport # This method has the same semantics of +update+, except it does not # modify the receiver but rather returns a new hash with indifferent # access with the result of the merge. - def merge(hash, &block) - dup.update(hash, &block) + def merge(*hashes, &block) + dup.update(*hashes, &block) end # Like +merge+ but the other way around: Merges the receiver into the @@ -393,6 +393,19 @@ module ActiveSupport target.default = default end end + + def update_with_single_argument(other_hash, block) + if other_hash.is_a? HashWithIndifferentAccess + regular_update(other_hash, &block) + else + other_hash.to_hash.each_pair do |key, value| + if block && key?(key) + value = block.call(convert_key(key), self[key], value) + end + regular_writer(convert_key(key), convert_value(value)) + end + end + end end end diff --git a/activesupport/test/hash_with_indifferent_access_test.rb b/activesupport/test/hash_with_indifferent_access_test.rb index af96231801..921a5c115d 100644 --- a/activesupport/test/hash_with_indifferent_access_test.rb +++ b/activesupport/test/hash_with_indifferent_access_test.rb @@ -249,6 +249,14 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert [updated_with_strings, updated_with_symbols, updated_with_mixed].all? { |h| h.keys.size == 2 } end + def test_update_with_multiple_arguments + hash = HashWithIndifferentAccess.new + hash.update({ "a" => 1 }, { "b" => 2 }) + + assert_equal 1, hash["a"] + assert_equal 2, hash["b"] + end + def test_update_with_to_hash_conversion hash = HashWithIndifferentAccess.new hash.update HashByConversion.new(a: 1) @@ -274,6 +282,14 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert_equal 2, hash["b"] end + def test_merging_with_multiple_arguments + hash = HashWithIndifferentAccess.new + merged = hash.merge({ "a" => 1 }, { "b" => 2 }) + + assert_equal 1, merged["a"] + assert_equal 2, merged["b"] + end + def test_merge_with_to_hash_conversion hash = HashWithIndifferentAccess.new merged = hash.merge HashByConversion.new(a: 1)