Using lambda, binding happens immediately?

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?

Thanks,
Sammy L.

2007/11/19, Sam L. [email protected]:

 filename = "testdata.dat"

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

define_method(“test_isleap_” + year) do
assert_equal(is_leap.downcase==“true”, @ly.isleap?(year.to_i))
end

Btw, I’d also use the block form of File.open because it is more
robust than the idiom you are using.

Kind regards

robert

Thanks Robert,

I have some more questions / responses below.

On Nov 20, 2007 6:45 AM, Robert K. [email protected]
wrote:

def LeapYearTest.generate_tests
end

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.

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?

Btw, I’d also use the block form of File.open because it is more
robust than the idiom you are using.

Thanks for pointing that out - I do like how it closes for you, so you
don’t
have to remember to do it.

Sammy L.

2007/11/20, Sam L. [email protected]:

  year, is_leap = line.split;

What I want to know is why when I use define_method(“name”) {block;}
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.

$ 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

2000 true
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

Robert,

On Nov 20, 2007 9:27 AM, Robert K. [email protected]
wrote:

I have this code:
file = File.new(filename, “r”)
end
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 L.

2007/11/20, Sam L. [email protected]:

On Nov 20, 2007 6:45 AM, Robert K. [email protected]

 @ly = LeapYear.new
  define_method("test_isleap_" + year, code)

(after the each_line loop)?
Then you are using “year” outside the block as well and the code you

If I can find the old code for the LeapYear class I’ll give it a shot and
get back to you.

IMHO even older Ruby version should behave the same, i.e. when the
variable is used inside the block only then you get multiple copies of
it and thus your created methods won’t share them.

Kind regards

robert