Chain your calls. Don't update the same variable again and again with very different values.
Just construct a hash straight away with each_with_object
or construct an array of pairs, and turn that into a hash.
Any sort of splitting/scanning is prone to errors if the string contains tokens that aren't part of the syntax. I.e. a nested string with a semicolon in it will be split as though it's a delimiter.
Anyway, you can do this, for instance:
result = Hash[ string.scan(/(\w+):\s+([^;]+)/) ]
though that'll give you string keys.
To avoid that, you could do:
pairs = string.scan(/(\w+):\s+([^;]+)/).map { |k,v| [k.to_sym, v.strip] } result = Hash[pairs]
or
result = string.scan(/(\w+):\s+([^;]+)/).each_with_object({}) do |(k,v), hash| hash[k.to_sym] = v.strip end
Another, much less robust way would be:
pairs = string.split(/[:;]/) .map(&:strip) .each_slice(2) .map { |k,v| [k.strip.to_sym, v.strip] } result = Hash[pairs]
Edit: And the totally unsafe option would be
result = eval("{#{string.tr(';', ',')}}")
On the plus side, your values have proper types (not all strings). On the minus side, eval is evil, and should always be avoided. So, really, don't do this.
JSON.parse
help? The string isn't close to being JSON. Keys would have to be quoted, commas instead of semicolons, braces around everything.\$\endgroup\$result = JSON.parse "{#{string.gsub(/([a-z_]+):/, '"\1":')}}"
was a little cleaner\$\endgroup\$