def args_eval(line)
tokens = []
while(data = line.match(/\[.*\]/))
data.pre_match.split(',').each {|s| tokens << s}
tokens << tokens.pop + data[0]
line = data.post_match
end
line.split(',').each {|s| tokens << s}
hash_tokens = []
tokens.reverse.each do |token|
break unless token =~ /=>/
hash_tokens << tokens.pop
end
if tokens.empty?
tokens = hash_tokens.pop.split(/=>/)
end
line_eval("[#{tokens.join(',')}#{', ' unless tokens.empty? || hash_tokens.empty?}#{hash_tokens.empty? ? '' : "{#{hash_tokens.reverse.join(',')}}"}]")
end
Refactorings
No refactoring yet !
michiel
October 23, 2007, October 23, 2007 11:33, permalink
And you don't use "eval" because you don't trust the caller? What does "line_eval" do?
Also, use "scan" to break up the entire line in tokens (square brackets, commas, => and others).
You could even use something like Racc (http://i.loveruby.net/en/projects/racc/doc/) to generate a parser for you. Overkill, I know, but a nice exercise, and with only four tokens it can't be hard.
this code evaluates a string as the argument array. so ":abc, :def => 123" would be sent to line_eval as [:abc, {:def => 123}]. The while loop makes sure ":abc, [:def, :ghi], :jkl" is evaluated as [:abc, [:def, :ghi], :jki], not [:abc, :def, :ghi, :jkl]. It's dirty.