Skip to content

Commit

Permalink
Merge pull request #14518 from Peeja/hash-wia-update-respects-to-hash…
Browse files Browse the repository at this point in the history
…-4-1-stable

HashWithIndifferentAccess better respects #to_hash (4-1-stable backport)
  • Loading branch information
rafaelfranca committed Mar 30, 2014
2 parents d5c9fc5 + 939f4ea commit 6e257b0
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
11 changes: 11 additions & 0 deletions activesupport/CHANGELOG.md
@@ -1,3 +1,14 @@
* `HashWithIndifferentAccess` better respects `#to_hash` on objects it's
given. In particular `#update`, `#merge`, `#replace` all accept objects
which respond to `#to_hash`, even if those objects are not Hashes directly.

Currently, if `HashWithIndifferentAccess.new` is given a non-Hash (even if
it responds to `#to_hash`) that object is treated as the default value,
rather than the initial keys and value. Changing that could break existing
code, so it will be updated in the next minor version.

*Peter Jaros*

* Added `Object#presence_in` to simplify value whitelisting.

Before:
Expand Down
Expand Up @@ -72,6 +72,7 @@ def default(key = nil)
end

def self.new_from_hash_copying_default(hash)
hash = hash.to_hash
new(hash).tap do |new_hash|
new_hash.default = hash.default
end
Expand Down Expand Up @@ -125,7 +126,7 @@ def update(other_hash)
if other_hash.is_a? HashWithIndifferentAccess
super(other_hash)
else
other_hash.each_pair do |key, value|
other_hash.to_hash.each_pair do |key, value|
if block_given? && key?(key)
value = yield(convert_key(key), self[key], value)
end
Expand Down
34 changes: 34 additions & 0 deletions activesupport/test/core_ext/hash_ext_test.rb
Expand Up @@ -23,6 +23,16 @@ def nested_under_indifferent_access
end
end

class HashByConversion
def initialize(hash)
@hash = hash
end

def to_hash
@hash
end
end

def setup
@strings = { 'a' => 1, 'b' => 2 }
@nested_strings = { 'a' => { 'b' => { 'c' => 3 } } }
Expand Down Expand Up @@ -411,6 +421,12 @@ 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_to_hash_conversion
hash = HashWithIndifferentAccess.new
hash.update HashByConversion.new({ :a => 1 })
assert_equal hash['a'], 1
end

def test_indifferent_merging
hash = HashWithIndifferentAccess.new
hash[:a] = 'failure'
Expand All @@ -430,6 +446,12 @@ def test_indifferent_merging
assert_equal 2, hash['b']
end

def test_merge_with_to_hash_conversion
hash = HashWithIndifferentAccess.new
merged = hash.merge HashByConversion.new({ :a => 1 })
assert_equal merged['a'], 1
end

def test_indifferent_replace
hash = HashWithIndifferentAccess.new
hash[:a] = 42
Expand All @@ -442,6 +464,18 @@ def test_indifferent_replace
assert_same hash, replaced
end

def test_replace_with_to_hash_conversion
hash = HashWithIndifferentAccess.new
hash[:a] = 42

replaced = hash.replace(HashByConversion.new(b: 12))

assert hash.key?('b')
assert !hash.key?(:a)
assert_equal 12, hash[:b]
assert_same hash, replaced
end

def test_indifferent_merging_with_block
hash = HashWithIndifferentAccess.new
hash[:a] = 1
Expand Down

0 comments on commit 6e257b0

Please sign in to comment.