Skip to content

Instantly share code, notes, and snippets.

@v2e4lisp
Last active December 21, 2015 18:59
Show Gist options
  • Select an option

  • Save v2e4lisp/6350775 to your computer and use it in GitHub Desktop.

Select an option

Save v2e4lisp/6350775 to your computer and use it in GitHub Desktop.
parsing json-like data. Designed for cli use. It's far from effient. The funny thing is you can customize the special mark of the json-like data.
module Fakeit
extend self
attr_accessor :array_mark, :hash_mark
@array_mark = '[ ]'
@hash_mark = '{:,}'
# Not effient way to parse json-like structure
# The problem is `split` is called too many times.
# The better way to do it, is something like the original js json parser .
# It's done by using only one pass.
def parse str=''
str = str.strip
case str[0]
when '"', "'"
string str[1..-1]
when array_mark[0]
array str[1..-1]
when hash_mark[0]
hash str[1..-1]
else
str
end
end
def string str
raise 'String parse error !' unless ["'", '"'].include?(str[-1])
return str[0...-1]
end
def array str
raise 'Array parse error !' if str[-1] != array_mark[-1]
split(str, :array).map { |x| parse(x) }
end
def hash str
raise 'Hash parse error !' if str[-1] != hash_mark[-1]
Hash[split(str, :hash).map { |e| key_value e.strip }]
end
def key_value str
key, value = str.split(hash_mark[1], 2)
return [key, parse(value)]
end
def split str, init_state
target = if init_state == :array
array_mark[1]
elsif init_state == :hash
hash_mark[2]
end
state = [init_state]
state.instance_eval { def lookup; self.last; end }
ret = []
last = 0
str.split("").each_with_index do |x, i|
case x
when "'"
case state.lookup
when :str1; state.pop
when :str2; next
else; state.push :str1
end
when '"'
case state.lookup
when :str2; state.pop
when :str1; next
else; state.push :str2
end
when array_mark[0]
case state.lookup
when :str1, :str2; next
else; state.push :array
end
when array_mark[-1]
case state.lookup
when :str1, :str2; next
when :array; state.pop
else; raise 'error'
end
when hash_mark[0]
case state.lookup
when :str1, :str2; next
else; state.push :hash
end
when hash_mark[-1]
case state.lookup
when :str1, :str2; next
when :hash; state.pop
else; raise 'error'
end
when target
if state.lookup == init_state
ret << str[last...i]
last = i+1
end
end
end
raise 'error state' if state.any?
ret << str[last...-1]
return ret
end
end
Fakeit.array_mark = '(,)'
Fakeit.hash_mark = '{:,}'
p Fakeit.parse(ARGV.first)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment