Skip to content
Permalink
Browse files
Add 'Hash#deep_transform_values', and 'Hash#deep_transform_values!'
  • Loading branch information
guilleiguaran committed Feb 8, 2019
1 parent 5f9e050 commit b8dc06b8fdc16874160f61dcf58743fcc10e57db
@@ -12,6 +12,10 @@

*Stefan Schüßler*

* Add `Hash#deep_transform_values`, and `Hash#deep_transform_values!`.

*Guillermo Iguaran*

## Rails 6.0.0.beta1 (January 18, 2019) ##

* Remove deprecated `Module#reachable?` method.
@@ -2,6 +2,7 @@

require "active_support/core_ext/hash/conversions"
require "active_support/core_ext/hash/deep_merge"
require "active_support/core_ext/hash/deep_transform_values"
require "active_support/core_ext/hash/except"
require "active_support/core_ext/hash/indifferent_access"
require "active_support/core_ext/hash/keys"
@@ -0,0 +1,52 @@
# frozen_string_literal: true

class Hash
# Returns a new hash with all keys converted by the block operation.
# This includes the keys from the root hash and from all
# nested hashes and arrays.
#
# hash = { person: { name: 'Rob', age: '28' } }
#
# hash.deep_transform_values{ |value| value.to_s.upcase }
# # => {person: {name: "ROB", age: "28"}}
def deep_transform_values(&block)
_deep_transform_values_in_object(self, &block)
end

# Destructively converts all values by using the block operation.
# This includes the values from the root hash and from all
# nested hashes and arrays.
def deep_transform_values!(&block)
_deep_transform_values_in_object!(self, &block)
end

private
# support methods for deep transforming nested hashes and arrays
def _deep_transform_values_in_object(object, &block)
case object
when Hash
object.each_with_object({}) do |(key, value), result|
result[key] = _deep_transform_values_in_object(value, &block)
end
when Array
object.map { |e| _deep_transform_values_in_object(e, &block) }
else
yield(object)
end
end

def _deep_transform_values_in_object!(object, &block)
case object
when Hash
object.keys.each do |key|
value = object.delete(key)
object[key] = _deep_transform_values_in_object!(value, &block)
end
object
when Array
object.map! { |e| _deep_transform_values_in_object!(e, &block) }
else
yield(object)
end
end
end
Empty file.
@@ -33,6 +33,8 @@ def test_methods
h = {}
assert_respond_to h, :deep_transform_keys
assert_respond_to h, :deep_transform_keys!
assert_respond_to h, :deep_transform_values
assert_respond_to h, :deep_transform_values!
assert_respond_to h, :symbolize_keys
assert_respond_to h, :symbolize_keys!
assert_respond_to h, :deep_symbolize_keys
@@ -78,6 +80,31 @@ def test_deep_transform_keys_with_bang_mutates
assert_equal({ "a" => { b: { "c" => 3 } } }, @nested_mixed)
end

def test_deep_transform_values
assert_equal({ "a" => "1", "b" => "2" }, @strings.deep_transform_values{ |value| value.to_s })
assert_equal({ "a" => { "b" => { "c" => "3" } } }, @nested_strings.deep_transform_values { |value| value.to_s })
assert_equal({ "a" => [ { "b" => "2" }, { "c" => "3" }, "4" ] }, @string_array_of_hashes.deep_transform_values { |value| value.to_s })
end

def test_deep_transform_values_not_mutates
transformed_hash = @nested_mixed.deep_dup
transformed_hash.deep_transform_values { |value| value.to_s }
assert_equal @nested_mixed, transformed_hash
end

def test_deep_transform_values!
assert_equal({ "a" => "1", "b" => "2" }, @strings.deep_transform_values!{ |value| value.to_s })
assert_equal({ "a" => { "b" => { "c" => "3" } } }, @nested_strings.deep_transform_values! { |value| value.to_s })
assert_equal({ "a" => [ { "b" => "2" }, { "c" => "3" }, "4" ] }, @string_array_of_hashes.deep_transform_values! { |value| value.to_s })
end

def test_deep_transform_values_with_bang_mutates
transformed_hash = @nested_mixed.deep_dup
transformed_hash.deep_transform_values! { |value| value.to_s }
assert_equal({ "a" => { b: { "c" => "3" } } }, transformed_hash)
assert_equal({ "a" => { b: { "c" => 3 } } }, @nested_mixed)
end

def test_symbolize_keys
assert_equal @symbols, @symbols.symbolize_keys
assert_equal @symbols, @strings.symbolize_keys

0 comments on commit b8dc06b

Please sign in to comment.