Bob Hutchison wrote:
> Hi,
>
> On Jul 21, 2006, at 11:10 PM, John W. Long wrote:
>
>> Jamey Cribbs wrote:
>>> The way it works is that in the Plane.find method, I grab the block 
>>> and pass it to #instance_eval.  This executes the block in the Plane 
>>> classes environment, so it knows that when it sees the attribute 
>>> "speed" or "country" in the block, it knows to call Plane.speed and 
>>> Plane.country.  Planes.speed happens to be a reference to a 
>>> SkiplistColumn instance and it knows how to handle the "> 350" 
>>> passed to it.
>>
>> The problem with this approach is that you loose access to instance 
>> variables. For instance:
>>
>>   >> class Object
>>   >>   def with(&block)
>>   >>     instance_eval(&block)
>>   >>   end
>>   >> end
>>   => nil
>>   >> @test = 1
>>   => 1
>>   >> Object.new.with { puts @test }
>>   => nil
>>
>> In the above example @test when used within the context of the with 
>> block is thought to be an instance variable of the object, which is 
>> why it returns nil instead of 1. I consider this behavior undesirable.
>
>
> Is this really a problem? If we write it this way:
>
> class Object
>   def with(&block)
>     instance_eval(&block)
>   end
> end
>
> class Toy
>   def play
>     @test = 'hello there'
>     with { puts "!!!! [#{@test}] !!!!" }
>   end
> end
>
> toy = Toy.new
> toy.play
>
> you get the output:
>
> !!!! [hello there] !!!!
>
> which is using the @test as I think you want.
I think the following code is an example of what John is pointing out:

class Employee
  def self.find(&block)
    instance_eval(&block)
  end
end

class Department
  def initialize
    @dept = 'Accounting'
  end

  def employees
    Employee.find { puts "employee.dept == #{@dept}" }
  end
end

Department.new.employees

Run this and you get:

    employee.dept ==

Replace that instance_eval in Employee.find with a yield statement, run 
it again, and you get:

    employee.dept == Accounting


If I could be sure that everyone would only do a Table.find in Mongoose 
from the top level environment, so that variables that they declared 
would be seen inside the Table class, I would be ok.  But, what happens 
when someone, like the example above, is doing a Table.find from within 
another object?  If I use #instance_eval inside of Table.find, I lose 
access to the instance variables from the calling object.

No, it looks like I will have to go back to doing a yield in Table.find, 
which means the user is going to have to specify a block parameter in 
the #find block.  In other words:

Employee.find { |emp| emp.dept == @dept }

I guess it doesn't look that bad.

Jamey