From: "Jesús Gabriel y Galán" Date: 2010-03-03T01:37:33+09:00 Subject: Re: Compute value inside define_method On Tue, Mar 2, 2010 at 5:25 PM, Karl wrote: > On Mar 2, 9:15 am, Jesús Gabriel y Galán > wrote: >> On Tue, Mar 2, 2010 at 5:00 PM, Karl wrote: >> > I know there is a 'trick' for forcing a value to compute, but I can't >> > seem to remember or find it. The following routine needs to computer >> > the value of 'register += 1' and not insert it literally. >> >> > into.class_eval do >> >              define_method "#{dow}_#{tod}_time" do >> >                @registers.get_value( "#{register += 1}"to_i ) >> >              end >> >    ...snip... >> > end >> >> > You can see my attempt above, but it doesn't work. Neither does >> > 'eval("register += 1")' >> >> > What's the trick? or should I approach the problem from a different >> > angle? >> >> What is register in your code above? Because this should work: >> >> irb(main):005:0> register = 0 >> => 0 >> irb(main):006:0> "#{register += 1}".to_i >> => 1 >> irb(main):008:0> register >> => 1 >> irb(main):009:0> "#{register += 1}".to_i >> => 2 >> >> On the other hand, if register is already and int and the get_value >> method receives an int, why not just: >> >> @registers.get_value(register += 1) >> >> ? >> >> Jesus. > > 'register' is an int. > > The problem is one of scope. When this is wrapped in the define_method > it carries as a variable int object when it is included in a class. > Thus, when executed via MyClass.weekeday_morning_time two consecutive > times, 'register += 1' increments. I don't want it to increment when > called, I just need it to increment when it is *defining* the method. > > This is part of a dynamic method creation loop, and the register > values are fixed. The dynamic method creation allows me to create > several hundred methods accessing consecutive registers without > writing all that code. So if I'm defining a method 'weekday_day_time' > it is 'get_value' from register 21. The 'register += 1' is just > incrementing the counter through the creation loop. > > Make sense? I know, this is a bit obscure. It's not a problem of scope. The problem is that define_method receives a block that closes over the register variable. The block passed to define_method is not executed when the define_method is executed, but when the method is invoked, as you have observed. All defined methods carry the binding to the same register variable and so every invocation of one of those methods will increment the same variable. One way to avoid that is force the execution of evaluating the register variable when defining the method, for example like: irb(main):012:0> 3.times do |i| irb(main):013:1* instance_eval "def test_#{i}; #{i};end" irb(main):014:1> end => 3 irb(main):015:0> test_0 => 0 irb(main):016:0> test_1 => 1 irb(main):018:0> test_2 => 2 The *eval method family can also receive a String, which is obviously not a closure, and so my #{i} above is executed when the instance_eval is executed. Maybe someone can come up with a cleaner solution. Translated to your problem (untested): into.class_eval do instance_eval <