Search code examples
ruby-on-railsrubyhashsend

How to set dynamically value of nested key in Ruby hash


it should be easy, but I couldn't find a proper solution. for the first level keys:

resource.public_send("#{key}=", value)

but for foo.bar.lolo ?

I know that I can get it like the following:

'foo.bar.lolo'.split('.').inject(resource, :send)

or

resource.instance_eval("foo.bar.lolo")

but how to set the value to the last variable assuming that I don't know the nesting level, it may be second or third.

is there a general way to do that for all levels ? for my example I can do it like the following:

resource.public_send("fofo").public_send("bar").public_send("lolo=", value)

Solution

  • Answer for hashes, just out of curiosity:

    hash = { a: { b: { c: 1 } } }
    def deep_set(hash, value, *keys)
      keys[0...-1].inject(hash) do |acc, h|
        acc.public_send(:[], h)
      end.public_send(:[]=, keys.last, value)
    end
    
    deep_set(hash, 42, :a, :b, :c)
    #⇒ 42
    hash
    #⇒ { a: { b: { c: 42 } } }