# \[Proposal\] Add Hash#transform\_value to ActiveSupport (Hash-only #bury)

**URL:** <https://discuss.rubyonrails.org/t/proposal-add-hash-transform-value-to-activesupport-hash-only-bury/81787>\
**Category:** rubyonrails-core\
**Tags:** feature, activesupport\
**Created:** [November 19, 2022, 12:13pm UTC](https://discuss.rubyonrails.org/t/proposal-add-hash-transform-value-to-activesupport-hash-only-bury/81787 "2022-11-19T12:13:33Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![pavelb](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/pavelb/32/9026_2.png) [@pavelb](https://discuss.rubyonrails.org/u/pavelb)\
**Post date:** [November 19, 2022, 12:13pm UTC](https://discuss.rubyonrails.org/t/proposal-add-hash-transform-value-to-activesupport-hash-only-bury/81787/1 "2022-11-19T12:13:33Z")

</div>

Hey everyone, there is a closed [proposal](https://bugs.ruby-lang.org/issues/11747) about adding `bury` method into Ruby, which is an opposite of `dig`. The issue with it is that it can’t work for both `Array` and `Hash` classes as `dig` does.

But `Hash`-only usecase still looks very relevant to me, that is why I thought that adding something like this to `ActiveSupport` may be concidered.

I think this method shouldn’t be named `bury` to not cause confusion about it being the opposite of `dig`. For me `Hash#transform_value` or `Hash#deep_transform_value` seems to be a good name.

Some usecases:

- Adding nested value:

```ruby
{}.transform_value(:a, :b) { 'c' }
# => { :a => { :b => "c" } }

```

- Updating nested value:

```ruby
{ a: { b: '1' } }.transform_value(:a, :b) { |value| value.to_i }
# => { :a => { :b => 1 } }

```

What do you think about this?

---

<div class="post-metadata">

**Author:** ![e\_a](https://avatars.discourse-cdn.com/v4/letter/e/9fc348/32.png) [@e\_a](https://discuss.rubyonrails.org/u/e_a)\
**Post date:** [November 22, 2022, 10:04pm UTC](https://discuss.rubyonrails.org/t/proposal-add-hash-transform-value-to-activesupport-hash-only-bury/81787/2 "2022-11-22T22:04:35Z")

</div>

IMHO, the `transform` part of your proposed names don’t seem obvious to me.

In the case where you are adding a new nested value there is no transformation happening at all. In the case of updating a nested value the caller could use the argument of the block to transform the value. Or they might just have the block return something unrelated to the existing value (much like with adding a value).

I.E. transforming seems like a nice feature of such a function but it seems to be a secondary feature and therefore I wouldn’t put it in the name of the method. I would think something like `deep_set` or `deep_insert` or something might be better.

* * *

Separate from naming there is also the question of does having a special method like this provide enough value over the current options in Ruby.

For updating an existing value we can obviously do that pretty well with:

```ruby
hsh[:a][:b] = 'foo'

```

Even transforming we can do in limited ways. For example:

```ruby
hsh[:a][:b].upcase!
hsh[:a][:b] += 1

```

If the value cannot mutate its state or there isn’t a syntax shortcut like `+=` it becomes a bit more verbose:

```ruby
hsh[:a][:b] = hsh[:a][:b].to_i

```

While there is a bit of redundancy here it doesn’t seem that the following is significantly better:

```ruby
hsh.deep_set :a, :b, &:to_i

```

With regard to deep inserting a new value I think your proposal has more value. There is one existing solution out there to consider. We can use the hash default value to auto-create nested hashes for us:

```ruby
class RecursiveHash < Hash
  def initialize
    super() { |h, k| h[k] = RecursiveHash.new }
  end
end

```

With this we can now do things like:

```ruby
hsh = RecursiveHash.new
hsh[:a][:b] = 'c'

```

You could even upgrade an existing hash by changing it’s `default_proc`:

```ruby
hsh = {}
hsh.default_proc = proc { |k, v| k[v] = RecursiveHash.new }
hsh[:a][:b] = 'c'

```

This isn’t really the same thing as what you have designed. It auto-creates hashes as part of the intrinsic nature of the hash vs it being a one-time operation. But there might be overlap between what you have designed and this sort of structure making it a suitable replacement in some situations.

Just my two cents. If such a method was added I wouldn’t find it problematic but I also would probably rarely if ever use it as I don’t think I typically do that sort of deep setting as often as I do deep getting.

---

<div class="post-metadata">

**Author:** ![pavelb](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/pavelb/32/9026_2.png) [@pavelb](https://discuss.rubyonrails.org/u/pavelb)\
**Post date:** [November 23, 2022, 2:03pm UTC](https://discuss.rubyonrails.org/t/proposal-add-hash-transform-value-to-activesupport-hash-only-bury/81787/3 "2022-11-23T14:03:51Z")

</div>

I agree that `Hash#deep_set` or `Hash#deep_insert` are more clear.

The real world use-case that made me think about this method was a little bit different, it was similar to this (but keys were longer 😁):

```ruby
hash[:some_key] ||= {}
hash[:some_key][:some_nested_key] = hash[:some_key][:some_nested_key]&.to_i || default_value 

```

Using this method it can be rewritten to:

```ruby
hash.deep_set(:some_key, :some_nested_key) { _1&.to_i || default_value }  

```
