mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
indifferent access should recurse Hash subclasses
This commit makes Hash subclasses convert to HWIA by default for nested
objects of subclasses of Hash, but allows certain subclasses to prevent nested
conversion by introducing Hash#nested_under_indifferent_access that subclasses
can overwrite.
ActiveSupport::OrderedHash is one such subclass that overwrites
+nested_under_indifferent_access+, since implicitly converting it to HWIA would
remove the ordering of keys and values in Ruby 1.8.
This change is necessary because commit ce9456e
broke nested indifferent access
conversion for all subclasses of Hash.
This commit is contained in:
parent
30db3a82f6
commit
099eb2b3fd
5 changed files with 35 additions and 5 deletions
|
@ -9,4 +9,16 @@ class Hash
|
|||
def with_indifferent_access
|
||||
ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
|
||||
end
|
||||
|
||||
# Called when object is nested under an object that receives
|
||||
# #with_indifferent_access. This method with be called on the current object
|
||||
# by the enclosing object and is aliased to #with_indifferent_access by
|
||||
# default. Subclasses of Hash may overwrite this method to return +self+ if
|
||||
# converting to an +ActiveSupport::HashWithIndifferentAccess+ would not be
|
||||
# desirable.
|
||||
#
|
||||
# b = {:b => 1}
|
||||
# {:a => b}.with_indifferent_access["a"] # calls b.nested_under_indifferent_access
|
||||
#
|
||||
alias nested_under_indifferent_access with_indifferent_access
|
||||
end
|
||||
|
|
|
@ -140,8 +140,8 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def convert_value(value)
|
||||
if value.class == Hash
|
||||
self.class.new_from_hash_copying_default(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) })
|
||||
else
|
||||
|
|
|
@ -43,6 +43,10 @@ module ActiveSupport
|
|||
end
|
||||
end
|
||||
|
||||
def nested_under_indifferent_access
|
||||
self
|
||||
end
|
||||
|
||||
# Hash is ordered in Ruby 1.9!
|
||||
if RUBY_VERSION < '1.9'
|
||||
|
||||
|
|
|
@ -16,6 +16,12 @@ class HashExtTest < Test::Unit::TestCase
|
|||
class SubclassingHash < Hash
|
||||
end
|
||||
|
||||
class NonIndifferentHash < Hash
|
||||
def nested_under_indifferent_access
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@strings = { 'a' => 1, 'b' => 2 }
|
||||
@symbols = { :a => 1, :b => 2 }
|
||||
|
@ -109,9 +115,12 @@ class HashExtTest < Test::Unit::TestCase
|
|||
assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys!
|
||||
end
|
||||
|
||||
def test_hash_subclass
|
||||
flash = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
|
||||
assert_kind_of SubclassingHash, flash["foo"]
|
||||
def test_nested_under_indifferent_access
|
||||
foo = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
|
||||
assert_kind_of ActiveSupport::HashWithIndifferentAccess, foo["foo"]
|
||||
|
||||
foo = { "foo" => NonIndifferentHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
|
||||
assert_kind_of NonIndifferentHash, foo["foo"]
|
||||
end
|
||||
|
||||
def test_indifferent_assorted
|
||||
|
|
|
@ -243,6 +243,11 @@ class OrderedHashTest < Test::Unit::TestCase
|
|||
assert_equal @other_ordered_hash.keys, @ordered_hash.keys
|
||||
end
|
||||
|
||||
def test_nested_under_indifferent_access
|
||||
flash = {:a => ActiveSupport::OrderedHash[:b, 1, :c, 2]}.with_indifferent_access
|
||||
assert_kind_of ActiveSupport::OrderedHash, flash[:a]
|
||||
end
|
||||
|
||||
def test_each_after_yaml_serialization
|
||||
values = []
|
||||
@deserialized_ordered_hash = YAML.load(YAML.dump(@ordered_hash))
|
||||
|
|
Loading…
Reference in a new issue