using lambda, binding happens immediately?

S

Sam Larbi

Note: parts of this message were removed by the gateway to make it a legal Usenet post.

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 Larbi
 
R

Robert Klemme

2007/11/19 said:
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

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
 
S

Sam Larbi

Note: parts of this message were removed by the gateway to make it a legal Usenet post.

Thanks Robert,

I have some more questions / responses below.


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 Larbi
 
R

Robert Klemme

2007/11/20 said:
Thanks Robert,

I have some more questions / responses below.




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
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
 
S

Sam Larbi

Note: parts of this message were removed by the gateway to make it a legal Usenet post.

Robert,

2007/11/20 said:
Thanks Robert,

I have some more questions / responses below.




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
 
R

Robert Klemme

2007/11/20 said:
Robert,

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.

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,198
Latest member
JaimieWan8

Latest Threads

Top