Skip to content

Instantly share code, notes, and snippets.

@yoshrote
Created July 8, 2020 19:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yoshrote/f24f84c1e010a1296f1178849ef5ef34 to your computer and use it in GitHub Desktop.
Save yoshrote/f24f84c1e010a1296f1178849ef5ef34 to your computer and use it in GitHub Desktop.
sketch of a parser
# a parser which will parse a string into key-value pairs
# it respects quotes around values and coerces the values to expected types using a spec
# example at the bottom
require 'strscan'
class Parser
# Parse key-value pairs while respecting quotes and coercing values
def parse_by_spec(spec, raw_arguments)
processed_args = {}
s = StringScanner.new(raw_arguments)
until s.eos?
# get the key, remove '=' and extra whitespace
current_key = s.scan_until(/=/)
break if current_key.nil?
current_key = current_key[0..-2].strip
# grab value accounting for any quotes
terminating_string = case s.peek(1)
when "'"
s.skip(/'/)
/'/
when '"'
s.skip(/"/)
/"/
else
/ /
end
processed_args[current_key.to_sym] = if s.exist?(terminating_string)
# grab everything before the next instance of the terminating character
s.scan_until(terminating_string)[0..-2]
else
# this is probably wrong unless we were expecting a space, but hit eos
s.rest
end
end
# only pass on expected parameters. dropping input silently is kindda bad though
processed_spec = {}
spec.each do |key, value|
# coerce to the expected type
processed_spec[key] = case value.fetch(:type, 'string')
when :int
processed_args[key].to_i
when :float
processed_args[key].to_f
when :bool
# open to better ways to coerce string -> boolean
['t', 'T', '1', 'true', 'True', 'TRUE'].include?(processed_args[key])
else
# assuming it is a string
processed_args[key]
end
end
processed_spec
end
end
Parser.parse_by_spec(
{
sentence: {type: :string},
count: {type: :int},
test: {type: :string},
foobar: {type: :string},
},
' sentence=foo count=1 test="multistring message" foobar=\'this thing\''
)
# => {:sentence=>"foo", :count=>1, :test=>"multistring message", :foobar=>"this thing"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment