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

Hash#deep_*_keys(!) recurse into nested arrays.

Following methods now recursively transform nested arrays, too.

* Hash#deep_transform_keys
* Hash#deep_transform_keys!
* Hash#deep_stringify_keys
* Hash#deep_stringify_keys!
* Hash#deep_symbolize_keys
* Hash#deep_symbolize_keys!
This commit is contained in:
OZAWA Sakuro 2013-03-15 01:29:59 +09:00
parent b7f9de27f0
commit ac0b1d835d
3 changed files with 67 additions and 16 deletions

View file

@ -1,3 +1,10 @@
* `Hash#deep_transform_keys` and `Hash#deep_transform_keys!` now transform hashes
in nested arrays. This change also applies to `Hash#deep_stringify_keys`,
`Hash#deep_stringify_keys!`, `Hash#deep_symbolize_keys` and
`Hash#deep_symbolize_keys!`.
*OZAWA Sakuro*
* Override `Time.at` to support the passing of Time-like values when called with a single argument.
*Andrew White*

View file

@ -73,34 +73,26 @@ class Hash
# Return a new hash with all keys converted by the block operation.
# This includes the keys from the root hash and from all
# nested hashes.
# nested hashes and arrays.
#
# hash = { person: { name: 'Rob', age: '28' } }
#
# hash.deep_transform_keys{ |key| key.to_s.upcase }
# # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } }
def deep_transform_keys(&block)
result = {}
each do |key, value|
result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
end
result
_deep_transform_keys_in_object(self, &block)
end
# Destructively convert all keys by using the block operation.
# This includes the keys from the root hash and from all
# nested hashes.
# nested hashes and arrays.
def deep_transform_keys!(&block)
keys.each do |key|
value = delete(key)
self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
end
self
_deep_transform_keys_in_object!(self, &block)
end
# Return a new hash with all keys converted to strings.
# This includes the keys from the root hash and from all
# nested hashes.
# nested hashes and arrays.
#
# hash = { person: { name: 'Rob', age: '28' } }
#
@ -112,14 +104,14 @@ class Hash
# Destructively convert all keys to strings.
# This includes the keys from the root hash and from all
# nested hashes.
# nested hashes and arrays.
def deep_stringify_keys!
deep_transform_keys!{ |key| key.to_s }
end
# Return a new hash with all keys converted to symbols, as long as
# they respond to +to_sym+. This includes the keys from the root hash
# and from all nested hashes.
# and from all nested hashes and arrays.
#
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
#
@ -131,8 +123,38 @@ class Hash
# Destructively convert all keys to symbols, as long as they respond
# to +to_sym+. This includes the keys from the root hash and from all
# nested hashes.
# nested hashes and arrays.
def deep_symbolize_keys!
deep_transform_keys!{ |key| key.to_sym rescue key }
end
private
# support methods for deep transforming nested hashes and arrays
def _deep_transform_keys_in_object(object, &block)
case object
when Hash
object.each_with_object({}) do |(key, value), result|
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
end
when Array
object.map {|e| _deep_transform_keys_in_object(e, &block) }
else
object
end
end
def _deep_transform_keys_in_object!(object, &block)
case object
when Hash
object.keys.each do |key|
value = object.delete(key)
object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
end
object
when Array
object.map! {|e| _deep_transform_keys_in_object!(e, &block)}
else
object
end
end
end

View file

@ -36,6 +36,10 @@ class HashExtTest < ActiveSupport::TestCase
@nested_illegal_symbols = { [] => { [] => 3} }
@upcase_strings = { 'A' => 1, 'B' => 2 }
@nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } }
@string_array_of_hashes = { 'a' => [ { 'b' => 2 }, { 'c' => 3 }, 4 ] }
@symbol_array_of_hashes = { :a => [ { :b => 2 }, { :c => 3 }, 4 ] }
@mixed_array_of_hashes = { :a => [ { :b => 2 }, { 'c' => 3 }, 4 ] }
@upcase_array_of_hashes = { 'A' => [ { 'B' => 2 }, { 'C' => 3 }, 4 ] }
end
def test_methods
@ -72,6 +76,9 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys{ |key| key.to_s.upcase }
assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys{ |key| key.to_s.upcase }
assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys{ |key| key.to_s.upcase }
assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase }
assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase }
assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_transform_keys{ |key| key.to_s.upcase }
end
def test_deep_transform_keys_not_mutates
@ -97,6 +104,9 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
assert_equal @upcase_array_of_hashes, @string_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
assert_equal @upcase_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
assert_equal @upcase_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase }
end
def test_deep_transform_keys_with_bang_mutates
@ -122,6 +132,9 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @nested_symbols, @nested_symbols.deep_symbolize_keys
assert_equal @nested_symbols, @nested_strings.deep_symbolize_keys
assert_equal @nested_symbols, @nested_mixed.deep_symbolize_keys
assert_equal @symbol_array_of_hashes, @string_array_of_hashes.deep_symbolize_keys
assert_equal @symbol_array_of_hashes, @symbol_array_of_hashes.deep_symbolize_keys
assert_equal @symbol_array_of_hashes, @mixed_array_of_hashes.deep_symbolize_keys
end
def test_deep_symbolize_keys_not_mutates
@ -147,6 +160,9 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @nested_symbols, @nested_symbols.deep_dup.deep_symbolize_keys!
assert_equal @nested_symbols, @nested_strings.deep_dup.deep_symbolize_keys!
assert_equal @nested_symbols, @nested_mixed.deep_dup.deep_symbolize_keys!
assert_equal @symbol_array_of_hashes, @string_array_of_hashes.deep_dup.deep_symbolize_keys!
assert_equal @symbol_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_symbolize_keys!
assert_equal @symbol_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_symbolize_keys!
end
def test_deep_symbolize_keys_with_bang_mutates
@ -192,6 +208,9 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @nested_strings, @nested_symbols.deep_stringify_keys
assert_equal @nested_strings, @nested_strings.deep_stringify_keys
assert_equal @nested_strings, @nested_mixed.deep_stringify_keys
assert_equal @string_array_of_hashes, @string_array_of_hashes.deep_stringify_keys
assert_equal @string_array_of_hashes, @symbol_array_of_hashes.deep_stringify_keys
assert_equal @string_array_of_hashes, @mixed_array_of_hashes.deep_stringify_keys
end
def test_deep_stringify_keys_not_mutates
@ -217,6 +236,9 @@ class HashExtTest < ActiveSupport::TestCase
assert_equal @nested_strings, @nested_symbols.deep_dup.deep_stringify_keys!
assert_equal @nested_strings, @nested_strings.deep_dup.deep_stringify_keys!
assert_equal @nested_strings, @nested_mixed.deep_dup.deep_stringify_keys!
assert_equal @string_array_of_hashes, @string_array_of_hashes.deep_dup.deep_stringify_keys!
assert_equal @string_array_of_hashes, @symbol_array_of_hashes.deep_dup.deep_stringify_keys!
assert_equal @string_array_of_hashes, @mixed_array_of_hashes.deep_dup.deep_stringify_keys!
end
def test_deep_stringify_keys_with_bang_mutates