[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

using lambda, binding happens immediately?

Sammy Larbi

11/19/2007 9:10:00 PM

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

5 Answers

Robert Klemme

11/20/2007 12:46:00 PM

0

2007/11/19, Sam Larbi <slarbi@gmail.com>:
> 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

--
use.inject do |as, often| as.you_can - without end

Sammy Larbi

11/20/2007 3:07:00 PM

0

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.


On Nov 20, 2007 6:45 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

> 2007/11/19, Sam Larbi <slarbi@gmail.com>:
> > 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.


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

Robert Klemme

11/20/2007 3:28:00 PM

0

2007/11/20, Sam Larbi <slarbi@gmail.com>:
> Thanks Robert,
>
> I have some more questions / responses below.
>
>
> On Nov 20, 2007 6:45 AM, Robert Klemme <shortcutter@googlemail.com> wrote:
>
> > 2007/11/19, Sam Larbi <slarbi@gmail.com>:
> > > 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.

$ 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

Sammy Larbi

11/20/2007 4:12:00 PM

0

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

Robert,

On Nov 20, 2007 9:27 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

> 2007/11/20, Sam Larbi <slarbi@gmail.com>:
> > Thanks Robert,
> >
> > I have some more questions / responses below.
> >
> >
> > On Nov 20, 2007 6:45 AM, Robert Klemme <shortcutter@googlemail.com>
> wrote:
> >
> > > 2007/11/19, Sam Larbi <slarbi@gmail.com>:
> > > > 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
>
>

Robert Klemme

11/20/2007 4:21:00 PM

0

2007/11/20, Sam Larbi <slarbi@gmail.com>:
> Robert,
>
> On Nov 20, 2007 9:27 AM, Robert Klemme <shortcutter@googlemail.com> wrote:
>
> > 2007/11/20, Sam Larbi <slarbi@gmail.com>:
> > > Thanks Robert,
> > >
> > > I have some more questions / responses below.
> > >
> > >
> > > On Nov 20, 2007 6:45 AM, Robert Klemme <shortcutter@googlemail.com>
> > wrote:
> > >
> > > > 2007/11/19, Sam Larbi <slarbi@gmail.com>:
> > > > > 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.

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

--
use.inject do |as, often| as.you_can - without end