tags:

views:

343

answers:

3

I have a string which looks like a hash:

"{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }"

How do I get a Hash out of it? like:

{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }

The string can have any depth of nesting. It has all the properties how a valid Hash is typed in Ruby.

+4  A: 

Quick and dirty method would be

eval("{ :key_a => { :key_1a => 'value_1a', :key_2a => 'value_2a' }, :key_b => { :key_1b => 'value_1b' } }").

But it has severe security implications.
It executes whatever it is passed, you must be 110% sure (as in, at least no user input anywhere along the way) it would contain only properly formed hashes or unexpected bugs/horrible creatures from outer space might start popping up.

Toms Mikoss
I have a light saber with me. I can take care of those creatures and bugs. :)
Waseem
+6  A: 

The string created by calling Hash#inspect can be turned back into a hash by calling eval on it. However, this requires the same to be true of all of the objects in the hash.

If I start with the hash {:a => Object.new}, then its string representation is "{:a=>#<Object:0x7f66b65cf4d0>}", and I can't use eval to turn it back into a hash because #<Object:0x7f66b65cf4d0> isn't valid Ruby syntax.

However, if all that's in the hash is strings, symbols, numbers, and arrays, it should work, because those have string representations that are valid Ruby syntax.

Ken Bloom
"if all that's in the hash is strings, symbols, and numbers,". This says a lot. So I can check the validity of a string to be `eval`uated as a hash by making sure that the above statement is valid for that string.
Waseem
Yes, but in order to do that you either need a full Ruby parser, or you need to know where the string came from in the first place and know that it can only generate strings, symbols, and numbers. (See also Toms Mikoss's answer about trusting the contents of the string.)
Ken Bloom
+2  A: 

Maybe YAML.load ?

silent
(load method supports strings)
silent
That requires a totally different string representation, but it much, much safer. (And the string representation is just as easy to generate -- just call #to_yaml, rather than #inspect)
Ken Bloom