How are variables bound to the body of a define_method?

metaprogramming, reflection, ruby

Solution

Blocks in Ruby are closures: the block you pass to `define_method` captures the variable `name` itself–not its value—so that it remains in scope whenever that block is called. That's the first piece of the puzzle.

The second piece is that the method defined by `define_method` is the block itself. Basically, it converts a `Proc` object (the block passed to it) into a `Method` object, and binds it to the receiver.

So what you end up with is a method that has captured (is closed over) the variable `name`, which by the time your loop completes is set to `:destroy`.

Addition: The `for ... in` construction actually creates a new local variable, which the corresponding `[ ... ].each {|name| ... }` construction would not do. That is, your `for ... in` loop is equivalent to the following (in Ruby 1.8 anyway):

name = nil
[ :new, :create, :destroy ].each do |name|
  define_method("test_#{name}") do
    puts name
  end
end
name # => :destroy

Problem

While trying to brush up my Ruby skills I keep running across this case which I can't figure out an explanation for by just reading the API docs. An explanation would be greatly appreciated. Here's the example code: ``` for name in [ :new, :create, :destroy ] define_method("test_#{name}") do puts name end end ``` What I want/expect to happen is that the `name` variable will be bound to the block given to `define_method` and that when `#test_new` is called it will output "new". Instead each defined method outputs "destroy" -- the last value assigned to the name variable. What am I misunderstanding about `define_method` and its blocks? Thanks!

Original source