Created
July 8, 2020 19:31
-
-
Save yoshrote/f24f84c1e010a1296f1178849ef5ef34 to your computer and use it in GitHub Desktop.
sketch of a parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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