提交 27411a7c 编写于 作者: C Carlos Antonio da Silva

Merge branch 'hash_with_indifferent_access_fix'

The problem:
Accessing a HashWithIndifferentAccess does not return the the same object
that is stored in the hash (i.e. equal?) causing unexpected results:

    hash = HashWithIndifferentAccess.new {|h, k| h[k] = []}
    hash[:a] << 1  # => [1]
    hash[:a]       # => [], expected [1]

The cause:
When a block is provided to generate default values the generated values
are duped if they are arrays. The duped value is stored in the hash but
the original value is returned when the hash is accessed.

The fix:
The duping is there for allowing frozen arrays containing hashes to be
modified. The fix restricts the duping to this case. Note that if default
function generates a frozen array an error will be raised on assignment
before and after the patch.

Closes #3811
......@@ -164,7 +164,8 @@ def convert_value(value)
if value.is_a? Hash
value.nested_under_indifferent_access
elsif value.is_a?(Array)
value.dup.replace(value.map { |e| convert_value(e) })
value = value.dup if value.frozen?
value.map! { |e| convert_value(e) }
else
value
end
......
......@@ -457,6 +457,13 @@ def test_indifferent_to_hash
assert_equal '1234', roundtrip.default
end
def test_lookup_returns_the_same_object_that_is_stored_in_hash_indifferent_access
hash = HashWithIndifferentAccess.new {|h, k| h[k] = []}
hash[:a] << 1
assert_equal [1], hash[:a]
end
def test_indifferent_hash_with_array_of_hashes
hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
assert_equal "1", hash[:urls][:url].first[:address]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册