1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

HashWithIndifferentAccess#initialize performance improvement

Rails 4 -> Rails 5 introduced a #to_hash call in
HashWithIndifferentAccess#initialize to guarantee access to
the #default and #default_proc methods.  This can be a very
expensive operation for very large HashWithIndifferentAccess
objects.  This commit bypasses this #to_hash call if it is
already a Hash.
This commit is contained in:
Miles Georgi 2018-12-06 19:37:00 +00:00
parent b86f65a816
commit 75a2ca6e9d
2 changed files with 29 additions and 1 deletions

View file

@ -69,7 +69,7 @@ module ActiveSupport
super()
update(constructor)
hash = constructor.to_hash
hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
self.default = hash.default if hash.default
self.default_proc = hash.default_proc if hash.default_proc
else

View file

@ -828,4 +828,32 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase
assert_equal 3, hash_wia[:foo]
assert_equal 3, hash_wia[:bar]
end
def test_should_copy_the_default_when_converting_non_hash_to_hash_with_indifferent_access
non_hash = Object.new
def non_hash.to_hash
h = { foo: :bar }
h.default = :baz
h
end
hash_wia = HashWithIndifferentAccess.new(non_hash)
assert_equal :bar, hash_wia[:foo]
assert_equal :baz, hash_wia[:missing]
end
def test_should_copy_the_default_proc_when_converting_non_hash_to_hash_with_indifferent_access
non_hash = Object.new
def non_hash.to_hash
h = { foo: :bar }
h.default_proc = ->(hash, key) { hash[key] = :baz }
h
end
hash_wia = HashWithIndifferentAccess.new(non_hash)
assert_equal :bar, hash_wia[:foo]
assert_equal :baz, hash_wia[:missing]
end
end