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!
Blocks in Ruby are closures: the block you pass to
define_methodcaptures the variablenameitself–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_methodis the block itself. Basically, it converts aProcobject (the block passed to it) into aMethodobject, 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 ... inconstruction actually creates a new local variable, which the corresponding[ ... ].each {|name| ... }construction would not do. That is, yourfor ... inloop is equivalent to the following (in Ruby 1.8 anyway):