Hi guys,
After messing up with racc for a couple of hours I realized that most of
the
parse functions look pretty much the same, so I thought of stretching my
metaprogramming muscles and I wrote my first meta_parse function.
require ‘strscan’
def meta_parse(*ary)
case_str = <<ENDSTRING
def parse(str)
@q = []
scanner = StringScanner.new str
until scanner.empty?
case
ENDSTRING
ary.each do |type, exp, meth|
if meth
case_str << " when m = scanner.scan(#{exp}) ; @q <<
[:#{type},
m.#{meth}]\n"
else
case_str << " when m = scanner.scan(#{exp}) ; @q <<
[:#{type},
m]\n"
end
end
case_str <<<<END_STRING
end
end
@q << [false,false]
do_parse
end
END_STRING
eval case_str
end
Here is a usage example:
meta_parse [:A, ‘/a/’], [:NUMBER, ‘/\d+/’, :to_i], [:WS, ‘/(\s|\t)+/’]
parse("a aaa 12132 ").each{|type,val| puts “#{type}: ‘#{val}’”}
I would like to hear your comments on it, but please be gentle
Cheers,
Ed
Encontrá a “Tu psicópata favorito” http://tuxmaniac.blogspot.com
Thou shalt study thy libraries and strive not to reinvent them without
cause,
that thy code may be short and readable and thy days pleasant and
productive.
– Seventh commandment for C programmers
After messing up with racc for a couple of hours I realized
that most of the parse functions look pretty much the same,
so I thought of stretching my metaprogramming muscles and I
wrote my first meta_parse function.
I would like to hear your comments on it, but please be
gentle
I usually try to avoid those inline strings. I don’t like them.
As long as you don’t pass a block in the call to the
dynamically defined method, you can use “define_method”
instead. I moved a bit of code and came up with the code below.
(Next time, please provide runnable code… )
gegroet,
Erik V. - http://www.erikveen.dds.nl/
require ‘strscan’
def meta_parse(*ary)
self.class.module_eval do
define_method :parse do |str|
@q = []
scanner = StringScanner.new(str)
until scanner.empty?
ary.each do |type, exp, meth|
if m = scanner.scan(exp)
@q << [type, (meth ? m.send(meth) : m)]
end
end
end
@q << [false,false]
do_parse
end
end
end
def do_parse
p $q
@q
end
meta_parse [:A, /a/], [:NUMBER, /\d+/, :to_i], [:WS, /(\s|\t)+/]
parse("a aaa 12132 ").each{|type,val| puts “#{type}: ‘#{val}’”}
“Erik V.” [email protected] writes:
dynamically defined method, you can use “define_method”
instead. I moved a bit of code and came up with the code below.
I’d just return a block for this case, though.
def meta_parse(*ary)
self.class.module_eval do
define_method :parse do |str|
…
I usually try to avoid those inline strings. I don’t like them.
As long as you don’t pass a block in the call to the
dynamically defined method, you can use “define_method”
instead.
Seconded, metaprogramming code like that will get a major performance
hit if
you whack YARV at it. Unless there’s a shaman embedding voodoo chants
into
YARV code for optimization of variable evals.
(Sidenote: it seems #eval is slightly faster than #define_method in
trivial
benchmarks.)
David V.