Reputation: 1108
I have a map generated by others with data structure like this:
x = {"city": "London", "country": "England", "region": "Europe"}
I want to manipulate the data in Ruby. So in order to be able to let Ruby understand it's a map, I need to replace all ":"
to "=>"
. Is there a quick way to accomplish this in one line?
Upvotes: 0
Views: 2370
Reputation: 89043
Another alternative, if you wanted to minimize your vulnerability to #eval
(which is a rational thing to do) is to use String#scan
:
quoted = /"(?:\\.|[^\\"])*"/
pairs = '{"city": "London", "country": "England", "region": "Europe"}'.scan(/(#{quoted})\s*:\s*(#{quoted})/)
hash = Hash[ *pairs.flatten.map { |q| eval q } ]
We're still using #eval
, but we know that we're only #eval
'ing something that looks like a quoted string, so we're safe-ish.
Since ruby strings can contain arbitrary code (through the miracle of interpolation), we're still vulnerable, though:
# arbitrary code evaluation
p eval('"one two #{puts %{Give me a three!}; gets.chomp} four"')
The safest alternative is to bypass #eval
entirely, and use a library for unquoting strings that doesn't allow for
interpolation. The JSON library (as previously mentioned) is a great example of that. It may seem slower (since it's
not as optimized as #eval
is), but it's a whole heck of a lot safer.
Upvotes: 0
Reputation: 10676
you need to install this gem json
sudo gem install json
require 'json'
JSON.parse('{"city": "London", "country": "England", "region": "Europe"}')
Upvotes: 13
Reputation: 35379
my_text = 'x = {"city": "London", "country": "England", "region": "Europe"}'
# Replace : with =>
ruby_code = t.gsub(':', '=>')
# Evaluate the string as ruby code
eval ruby_code
# Now you can access the hash
x['city'] # => "London"
Upvotes: 5
Reputation: 410552
'{"city": "London", "country": "England", "region": "Europe"}'.gsub!(/: /, ' => ')
gsub!
does an in-place global substitution on the string.
Upvotes: 2