class HashParser def self.parse(s) self.new(s).send(:parse) end private def initialize(s) @s, @i = s, 0 end def parse @s[@i] == "{" or raise "Missing initial '{' in hash literal: #{@s.inspect}" @i += 1 while @i < @s.size && @s[@i] == " " # Skip spaces before first key @i += 1 end pairs = [] while @i < @s.size && @s[@i] !~ /[,\}]/ pairs << extract_key_value extract_element_separator end @s[@i] == "}" or raise "Missing terminating '}' in hash literal: #{@s.inspect}" Hash[*pairs.flatten] end def extract_element_separator while @i < @s.size && @s[@i] =~ /\s/ @i += 1 end if @i < @s.size && @s[@i] == "," @i += 1 while @i < @s.size && @s[@i] =~ /\s/ @i += 1 end end end def extract_key_value key = extract_key extract_separator value = extract_value [key.to_sym, value] end def extract_key key = "" while @i < @s.size && @s[@i] =~ /\w/ key += @s[@i] @i += 1 end key end def extract_separator while @i < @s.size && @s[@i] =~ /[\s:]/ @i += 1 end end def extract_value if @s[@i] =~ /['"]/ extract_quoted_value else extract_unquoted_value end end def extract_quoted_value quot = @s[@i] @i += 1 litt = "" while @i < @s.size && @s[@i] != quot if @s[@i] == "\\" @i += 1 @i < @s.size or raise "Syntax error in hash literal: #{@s.inspect}" case @s[@i] when "\\"; litt += "\\" when quot; litt += quot else litt += "\\" + @s[@i] end else litt += @s[@i] end @i += 1 end @i < @s.size && @s[@i] == quot or raise "Unterminated hash literal: #{@s.inspect}" @i += 1 return litt end def extract_unquoted_value j = @i + 1 while j < @s.size && @s[j] !~ /[,\}]/ j += 1 end litt = @s[@i...j].strip @i = j value = case litt when "nil"; nil when "true"; true when "false"; false when /^\d+$/; litt.to_i else litt.strip end value end end