hoodwink.d enhanced


Eval-less Metaprogramming #

by why in bits

I often find myself resorting to eval when writing class methods for metaprogramming, simply because define_method hasn’t penetrated my brain basket yet. No more!

Here goes Florian GroBB changing Ruby as I know it—yet again—with his implementation of an eval-less has_many class method:

 class Meta
   def self.has_many( sym )
     ivar = :"@#{ sym }" 
     define_method( sym.to_sym ) do
       new_value = instance_variable_get( ivar ) || []
       instance_variable_set( ivar, new_value )

Even though has_many is a sorta poor name (we’re not talking about databases here), this method acts like an attr method, but the attribute is always an Array.

 class Person < Meta
   attr_accessor :name
   has_many :friends
   def initialize( name ); @name = name; end

 >> fred = Person.new( "Fred" )
 >> joe = Person.new( "Joe" )
 >> teagle = Person.new( "T. Eagle" )
 >> teagle.friends << fred
 >> teagle.friends << joe
 => [#<Person:0x80f3ebc @name="Fred">, #<Person:0x81fd404 @name="Joe">]
said on 29 Mar 2005 at 16:25

Man, that is nice. Goodbye heredocs.

said on 29 Mar 2005 at 17:56

Hrmm, I wonder why the “at” sign is forced on the symbol. That seems like the syntax sugar is in the wrong place. We’ve already telling it we’re looking for an instance variable by our choice in the method we’re calling.

Still, there’s no real reason to resort to eval. The other day I scribbled out an example of runtime aspect oriented programming in ruby using ObjectSpace and method_define. I had to use send in order to “go meta” and sidestep the private nature of method_define. In real code you’d probibly put a wrapping api in a module that defined methods for aspect hooks, then just include that in object if you really did want it to apply to everything.

said on 29 Mar 2005 at 18:34

Ahh, and that’s what I’ve been looking for. The eval business just seemed so … un-Rubyesque, but I wasn’t aware there was a better way yet.

Is this something worth exploring in Dwemthy’s Array, perhaps?

said on 29 Mar 2005 at 19:04

GroBB? Am I a bulletin board now? ;)

said on 29 Mar 2005 at 20:24

JasonWatkins: Yeah, the private checking on define_method is screwy.

MenTaLguY: Dwemthy’s Array is metaprogramming two stairs down. It creates a traits class method, which must create instance methods for each trait. I would need to resort to using send like Jason described, which.. eh.. I dunno.. maybe.. but goshhhh.

said on 29 Mar 2005 at 20:59

Oh man, that’s so the name of my Rails-based BB software now.

said on 30 Mar 2005 at 01:46

Looks like Dwemthys array needs to be repolished!

said on 30 Mar 2005 at 07:48

JasonWatkins: Look at the implementation of instance variables to see why prefixing with @ is required.

said on 30 Mar 2005 at 15:35

Why, why would send be necessary? At worst you can instance_eval/class_eval, can’t you?

said on 30 Mar 2005 at 16:01

That is, eval with blocks rather than strings (I’ve managed to confuse myself badly here…). Anyway, c.f. my poignant-stiffs post. Turns out variable scoping isn’t a problem.

said on 30 Mar 2005 at 16:29

I think .send() is to be prefered over .instance_eval() for calling private methods as it has less side effects.

said on 04 Apr 2005 at 13:27

eval has always annoyed me (try reading the RSS library sometime), good to see there are better alternatives.

Comments are closed for this entry.