From: Sam Larbi Date: 2007-11-21T01:11:56+09:00 Subject: Re: using lambda, binding happens immediately? ------=_Part_6562_1146116.1195575113583 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline Robert, On Nov 20, 2007 9:27 AM, Robert Klemme wrote: > 2007/11/20, Sam Larbi : > > Thanks Robert, > > > > I have some more questions / responses below. > > > > > > On Nov 20, 2007 6:45 AM, Robert Klemme > wrote: > > > > > 2007/11/19, Sam Larbi : > > > > I have this code: > > > > > > > > > > > > require 'test/unit' > > > > require 'leapyear' > > > > class LeapYearTest < Test::Unit::TestCase > > > > def setup > > > > @ly = LeapYear.new > > > > end > > > > def LeapYearTest.generate_tests > > > > filename = "testdata.dat" > > > > file = File.new(filename, "r") > > > > file.each_line do |line| > > > > year, is_leap = line.split; > > > > code = lambda { assert_equal(is_leap.downcase=="true", @ > ly.isleap > > > ?( > > > > year.to_i)) } > > > > define_method("test_isleap_" + year, code) > > > > end > > > > file.close > > > > end > > > > end > > > > > > > > > > > > What I want to know is why when I use define_method("name") {block;} > > > instead > > > > of define_method("name", lambda{block}) the binding seems to happen > > > later > > > > (after the each_line loop)? > > > > > > > > Is there a reason behind that? > > > > > > I'm not sure I understand you but why don't you just do > > > > > > > Well, the problem is that attaching the block uses only the last "year" > to > > be processed in the loop, never the appropriate one. > > Then you are using "year" outside the block as well and the code you > have shown is not the code you actually run. > I tried your code and as you know, it works fine. I even reconstructed the tests for it, and it still worked fine. The problem I had was over a year old, so I wonder if this was only the case in an older version of Ruby. (Can anyone confirm or deny that?) I'm certain I had the problem before, but obviously we cannot reproduce it in this similar case. If I can find the old code for the LeapYear class I'll give it a shot and get back to you. Sammy Larbi > > $ ruby /cygdrive/c/sc.rb.txt > foo > bar > 16:23:16 $ cat /cygdrive/c/sc.rb.txt > class Foo > def self.create(words) > words.each do |w| > define_method("test_#{w}") { puts w } > end > end > end > Foo.create %w{foo bar} > Foo.new.test_foo > Foo.new.test_bar > 16:23:28 $ ruby /cygdrive/c/sc.rb.txt > bar > bar > 16:24:18 $ cat /cygdrive/c/sc.rb.txt > class Foo > def self.create(words) > w = nil > words.each do |w| > define_method("test_#{w}") { puts w } > end > end > end > Foo.create %w{foo bar} > Foo.new.test_foo > Foo.new.test_bar > 16:24:19 > > > > define_method("test_isleap_" + year) do > > > assert_equal(is_leap.downcase=="true", @ly.isleap?(year.to_i)) > > > end > > > > > > > My understanding is that this would do the same as define_method(...) { > > ...}, so I would expect to have the same problem. > > > > Basically, lets say the file testdata.dat has the following lines: > > > > 2000 true > > 2004 true > > 2001 false > > > > Then running the code above (with leapyear class defined as well) would > use > > 2001 as the date for each of the tests if I used the block attachment as > > opposed to passing through the arguments after using lambda (although > the > > tests would be named correctly). > > > > So basically, It would generate the following: > > > > test_isleap2000 -> but the date inside is 2001 > > test_isleap2004 -> but the date inside is 2001 > > test_isleap2001 -> the test is correct > > > > Then, if I use lambda, the tests are all correct. > > > > Does that make any more sense? > > I am afraid, no (see above). > > Kind regards > > robert > > -- > use.inject do |as, often| as.you_can - without end > > ------=_Part_6562_1146116.1195575113583--