1
0
Fork 0
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:
David Lee 2011-05-08 02:21:06 -07:00
parent 30db3a82f6
commit 099eb2b3fd
5 changed files with 35 additions and 5 deletions

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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))