On Thu, Apr 23, 2009 at 6:33 PM, Tom Cloyd <tomcloyd / comcast.net> wrote:
> Rick DeNatale wrote:
>>
>> On Thu, Apr 23, 2009 at 3:09 AM, Joel VanderWerf
>> <vjoel / path.berkeley.edu> wrote:
>>
>>>
>>> Tom Cloyd wrote:
>>>
>>
>>
>>>>
>>>> eval( "moduleName.methodName", binding)
>>>>
>>>> Causes *crash* due to by attempt to access a variable which exists in
>>>> the
>>>> calling environment but not in the module. In spite of passing the
>>>> binding,
>>>> the method knows nothing of the variable. It's not working.
>>>>
>>>>
>>>
>>> You've got something like this, right?
>>>
>>> module M
>>> def M.meth
>>>  p x
>>> end
>>> end
>>>
>>> x = 1
>>> eval "M.meth", binding # Undefined variable x
>>>
>>>
>>> The binding that you pass into eval here only affects variables that are
>>> unbound in the string. In this case there are none. The x in M.meth is a
>>> bound variable in the scope of the method.
>>>
>>
>> And to stress the obvious
>>
>> eval "some string"
>>
>> which uses the current binding, is exactly equivalent to
>>
>> eval "some string", binding
>>
>> Assuming that binding is a call to Kernel#binding and not a local
>> variable.
>>
>> So
>>
>> eval "M.meth"
>> and
>> eval "M.meth", binding
>>
>> will both do the same thing, including throwing any exceptions.
>>
>>
>
> So, how do I get M.meth to execute in the namespace of my main? I thought
> 'binding' packaged up that namespace and I could then pass it to the method.

No, it packages it so you can pass it to eval, which is useful if you
want to call eval from a different point than where you capture the
binding.

> I want M.meth to have access to all variables in main's namespace - well,
> instance variables, anyway. How do I do that?

If you want to access instance variables from the calling scope inside
a method call (on a different object), you could pass self from the
calling point as an argument to the method, and use instance_eval in
the method. E.g.:

irb(main):001:0> module M
irb(main):002:1> def M.meth
irb(main):003:2> end
irb(main):004:1> end
=> nil
irb(main):005:0> module M
irb(main):006:1> def M.meth(target)
irb(main):007:2> puts target.instance_eval { @foo }
irb(main):008:2> end
irb(main):009:1> end
=> nil
irb(main):010:0> class C
irb(main):011:1> def initialize(val)
irb(main):012:2> @foo = val
irb(main):013:2> end
irb(main):014:1> def test
irb(main):015:2> M.meth(self)
irb(main):016:2> end
irb(main):017:1> end
=> nil
irb(main):018:0> c = C.new(1)
=> #<C:0x2bbd440 @foo=1>
irb(main):019:0> c.test
1
=> nil