Access variable hash depth values with square brackets notation

Given this hash:

hash1= { node1: { node2: { node3: { node4: { node5: 1 } } } } }

We access inside nodes with square brackets like this:

hash1[:node1][:node2][:node3][:node4]

Now I have a hash that I know will always be nested as it is an XML response from a SOAP webservice, but neither the depth of the hash nor the names of the nodes stay the same. So it would be nice if I could ask the user of my application for the hash depth and store it in a variable. And then be able to do hash1[:hash_depth] and achieve the same result as above.

I have accomplished what I want by the following code:

str = 'node1,node2,node3,node4'
str_a = str.split(',')
hash_copy = hash1
str_a.each { |s| hash_copy = hash_copy.[](s.to_sym) }
hash_copy
=> {:node5=>1}
hash1[:node1][:node2][:node3][:node4]
=> {:node5=>1}

that is asking the user to enter the hash depth separated by commas, store it in a string, split it, make an array, clone the original hash, go down each level and modify the hash till I get to the desired node. Is there a way to do it with the square brackets notation and using a variable to store the depth without modifying the hash or needing to clone it?

Edit: someone answered with the following (can't see his post anymore???)

hash_depth="[:node1][:node2][:node3][:node4]"
eval "hash1#{hash_depth}"

Upvotes: 1

Views: 235

Answers (2)

sawa
sawa

Reputation: 168269

If this is a webapp, I think you should prepare a list of short textareas, which starts with a single text item, and the user can keep adding a new item to the list by clicking on a button. The areas will be filled by the user, and will be sent.

Then, you will probably receive this through some serialized form. You decode this to get an array of strings:

str_a = ["node1", "node2", "node3", "node4"]

and you can reach the inner element by doing:

str_a.inject(hash1){|h, s| h[s.to_sym]} #=> {:node5 => 1}

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121020

Although eval does everything you need, there is another approach, since you already have the working code for comma-separated list:

hash_depth="[:node1][:node2][:node3][:node4]"
csh = hash_depth.gsub(/\A\[:|\]\[:|\]\Z/, { '][:' => ',' })
#⇒ "node1,node2,node3,node4"

And now you are free to apply your existing function to csh.

Upvotes: 1

Related Questions