Last updated on Sun Jul 18 12:00:00 CEST 2004
Defining methods with closures
I had forgotten that there are still Rubyists who don’t know the class << self; self end.send(:define_method, :foo){ } idiom. I wrote a short explanation and some hints on how to use define_method.

Module#define_method is my method of choice (har har) to define methods dynamically, since when I am meta-programming I usually need to define them as a closure anyway: this is especially useful when you create a new object, add some singleton methods to it that modify some data in your environment and then perform an instance_eval on a Proc; this is a way to define a restricted language to be used inside that block.

Let’s see a stupid synthetic example:

 require "pp"
 class Foo
     def initialize(state = "initial")
         @state = [state]
     end

     def update(&block)
         magic_obj = Object.new # throw-away obj, only to capture method calls
         state = @state
         class << magic_obj; self end.send(:define_method, :do_magic) do |a|
             puts "This object allows do_magic operations only..."
             puts "i.e. we have restricted the allowable operations inside the block"
             state << a
         end
         magic_obj.instance_eval(&block)
     end
 end

 f = Foo.new
 f.update do
     # this block uses a different "vocabulary", i.e. it can behave as a new,
     # restricted language. This is more general than the <tt>yield self</tt>
     # technique used normally.
     do_magic "foo"
 end
 pp f

I think I’ll probably write a bit more on this (and meta-programming in general) in my Ruby section.

BTW, I use this technique (with a couple additional meta-programming layers though) in rpa-base, which allows me to define a IMHO very good language for the rpafied install.rb files: they are as descriptive and short as it gets; I designed the language first and then implemented it with heavy meta-programming in Ruby…


Copyright © MJFP
batsman dot geo at yahoo dot com