The problem is that for loop expressions do not create a new scope. The only things that create new areas in Ruby are script bodies, module bodies, class bodies, method bodies, and blocks.
If you really look at the behavior of for loop expressions in a draft of the Ruby ISO specification, you will find that the for loop expression executes exactly like each iterator, except that it does not create a new scope.
No Rubyist would ever use a for loop, anyway: instead they would use an iterator that takes a block and thereby creates a new scope.
If you use an idiomatic iterator, everything works as expected:
class Object %w[new create destroy].each do |name| define_method "test_#{name}" do puts name end end end require 'test/unit' require 'stringio' class TestDynamicMethods < Test::Unit::TestCase def setup; @old_stdout, $> = $>, (@fake_logdest = StringIO.new) end def teardown; $> = @old_stdout end def test_that_the_test_create_method_prints_create Object.new.test_create assert_equal "create\n", @fake_logdest.string end def test_that_the_test_destroy_method_prints_destroy Object.new.test_destroy assert_equal "destroy\n", @fake_logdest.string end def test_that_the_test_new_method_prints_new Object.new.test_new assert_equal "new\n", @fake_logdest.string end end
source share