String to hash in Ruby without JSON.parse Just for the sake of understanding. I know JSON.parse could do this pretty easily, but without using that, how could this be made cleaner or more efficient?

string = "ounces: 10; contains_toy: false"
result = string.split("; ")
result = result.map{|x| x = x.split(": "); Hash[x.first.to_sym, x.last] }
result = result.reduce(:merge)


Desired result:

{:ounces=&gt;"10", :contains_toy=&gt;"false"}
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(&amp;: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.