Skip to content

Commit

Permalink
Merge pull request #36880 from freeletics/multiple-merge
Browse files Browse the repository at this point in the history
Support multiple arguments in `HashWithIndifferentAccess` for `merge` and update methods
  • Loading branch information
rafaelfranca committed Aug 8, 2019
2 parents 1200161 + 8674417 commit 6ebdab3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 13 deletions.
5 changes: 5 additions & 0 deletions activesupport/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
39 changes: 26 additions & 13 deletions activesupport/lib/active_support/hash_with_indifferent_access.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def []=(key, value)

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 arguments:
#
# hash_1 = ActiveSupport::HashWithIndifferentAccess.new
# hash_1[:key] = 'value'
Expand All @@ -106,7 +106,10 @@ def []=(key, value)
#
# 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
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
# In either case the merge respects the semantics of indifferent access.
#
Expand All @@ -121,18 +124,15 @@ def []=(key, value)
# 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
Expand Down Expand Up @@ -259,8 +259,8 @@ def dup
# 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
Expand Down Expand Up @@ -393,6 +393,19 @@ def set_defaults(target) # :doc:
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

Expand Down
16 changes: 16 additions & 0 deletions activesupport/test/hash_with_indifferent_access_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,14 @@ def test_indifferent_update
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)
Expand All @@ -274,6 +282,14 @@ def test_indifferent_merging
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)
Expand Down

0 comments on commit 6ebdab3

Please sign in to comment.