# Meta\_parse: my first metaprogram

**URL:** <https://www.ruby-forum.com/t/meta-parse-my-first-metaprogram/53993>\
**Category:** Ruby\
**Created:** [February 19, 2006, 6:57pm UTC](https://www.ruby-forum.com/t/meta-parse-my-first-metaprogram/53993 "2006-02-19T18:57:13Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Edgardo\_H](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/c68b51/32.png) [@Edgardo\_H](https://www.ruby-forum.com/u/Edgardo_H)\
**Post date:** [February 19, 2006, 6:57pm UTC](https://www.ruby-forum.com/t/meta-parse-my-first-metaprogram/53993/1 "2006-02-19T18:57:13Z")

</div>

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](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

---

<div class="post-metadata">

**Author:** ![Edgardo\_H](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/c68b51/32.png) [@Edgardo\_H](https://www.ruby-forum.com/u/Edgardo_H)\
**Post date:** [February 19, 2006, 7:39pm UTC](https://www.ruby-forum.com/t/meta-parse-my-first-metaprogram/53993/2 "2006-02-19T19:39:45Z")

</div>

> 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/](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}’”}

---

<div class="post-metadata">

**Author:** ![Edgardo\_H](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/c68b51/32.png) [@Edgardo\_H](https://www.ruby-forum.com/u/Edgardo_H)\
**Post date:** [February 19, 2006, 8:55pm UTC](https://www.ruby-forum.com/t/meta-parse-my-first-metaprogram/53993/3 "2006-02-19T20:55:40Z")

</div>

“Erik V.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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|  
> …

---

<div class="post-metadata">

**Author:** ![Edgardo\_H](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/c68b51/32.png) [@Edgardo\_H](https://www.ruby-forum.com/u/Edgardo_H)\
**Post date:** [February 19, 2006, 7:54pm UTC](https://www.ruby-forum.com/t/meta-parse-my-first-metaprogram/53993/4 "2006-02-19T19:54:55Z")

</div>

> 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.
