Forum: Ruby kernal::binding problem

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
D15a45a973443d4562051eb675b60474?d=identicon&s=25 Tom Cloyd (Guest)
on 2009-04-23 08:31
(Received via mailing list)
Trying this for the first time, and, as usual, not quite getting it.

Everything I can find on kernal::binding tells me that I just call it
and will get back a binding object which can be passed in a call to
eval. But...it doesn't work for me.

In my main, I have a module required which contains a method I'm trying
to call. For reasons irrelevant to this current problem, I'm using an
eval of a string to do it, and want the method to execute in the
environment of the main program. So...

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.

All examples I can find just do something like..

def meth_x
y = 1
return binding
end

Then 'y' is accessed using the binding. Well, if one can return a
binding to initialize a variable -

z = meth_x
eval( "y", z )  # => "1"

Then why can't I simply pass 'binding' in an eval call FROM the calling
environment?

I must be missing something, to state the obvious.

Can someone explain?

Thanks,

t.

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2009-04-23 09:10
(Received via mailing list)
Tom Cloyd wrote:
>
> return binding
> end
>
> Then 'y' is accessed using the binding. Well, if one can return a
> binding to initialize a variable -
>
> z = meth_x
> eval( "y", z )  # => "1"
>
> Then why can't I simply pass 'binding' in an eval call FROM the calling
> environment?

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. Compare:

module M
   def M.meth arg
     p arg
   end
end

x = 1
eval "M.meth(x)", binding # ==> 1

Also:

x = 1
eval %{
   p x # ==> 1
   def foo
     p defined?(x)
   end
   foo # ==> nil
}, binding

Of course, it's quite possible I didn't understand the question...

What are you trying to do?
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2009-04-23 15:44
(Received via mailing list)
On Thu, Apr 23, 2009 at 3:09 AM, Joel VanderWerf
<vjoel@path.berkeley.edu> wrote:
> Tom Cloyd wrote:

> module M
> 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.

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
D15a45a973443d4562051eb675b60474?d=identicon&s=25 Tom Cloyd (Guest)
on 2009-04-24 03:30
(Received via mailing list)
Joel VanderWerf wrote:
>> the environment of the main program. So...
>> y = 1
>> calling environment?
> eval "M.meth", binding # Undefined variable x
Yes,
>
>
> The binding that you pass into eval here only affects variables that
> are unbound in the string.
Man. Never read THAT anywhere else. Seems like essential information to
associate with 'binding' method documentation, but it doesn't seem to
be, anywhere I've looked.
> eval "M.meth(x)", binding # ==> 1
Interesting example. But it puzzles me. Why isn't 'x' considered bound
in the scope of self? It's then passed in to M.meth as an argument, so
why is 'binding' needed at all in this case? I don't understand why you
did it this way - can you explain?
> [...]
>
> What are you trying to do?
>
I'm trying to execute a module method in the namespace of my main
program which calls it. In outline:

I have a class which requires two files, each of which contains a
module. I then include each module:

    utilname = '../lib/setnet/Utils_' + File.basename( name ) + '.rb'
#'name' passed in when class in instantiated
    if File.exist?( utilname )  # it may not exist
      require utilname
      include Utils_db
    end
    require '../lib/setnet/Utilities'  # will always exist
    include Utils

While I haven't found any authority who says this, it appears that
'include' can only occur at the top of a class definition. I only just
figured this out, so I have about an hour+ experience with 'include'.

I thought the 'include' would essentially move my module methods into my
main, as if they were physically there already. But that's not
happening. I still have my namespace isolation problem:

When I call a module method from my main, it executes fine, until it
tries to access a variable which would be plainly available of the
module code were physically residing my class. It then crashes, as it
finds only 'nil'.

I don't know how to fix this. I thought using 'include' would do it, but
it seems to have no effect.

I don't want to just pass the method the data it needs, since in theory
I won't know what that is. I want the method to take care of itself - to
just have access to the calling program's namespace, which would solve
all problems.

Can anyone suggest a solution?

Tom
D15a45a973443d4562051eb675b60474?d=identicon&s=25 Tom Cloyd (Guest)
on 2009-04-24 03:35
(Received via mailing list)
Rick DeNatale wrote:
>>> calling environment but not in the module. In spite of passing the binding,
>>
>
> 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. Wrong, apparently.

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

t.
D7463bd611f227cfb2ef4da4a978a203?d=identicon&s=25 Christopher Dicely (Guest)
on 2009-04-24 05:42
(Received via mailing list)
On Thu, Apr 23, 2009 at 6:33 PM, Tom Cloyd <tomcloyd@comcast.net> wrote:
>>>>
>>> You've got something like this, right?
>>>
>>
>>
>> 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
D15a45a973443d4562051eb675b60474?d=identicon&s=25 Tom Cloyd (Guest)
on 2009-04-24 05:51
(Received via mailing list)
Christopher Dicely wrote:
>>>>
>>>>>
>>>>
>>> which uses the current binding, is exactly equivalent to
>>> eval "M.meth", binding
> want to call eval from a different point than where you capture the
> the method. E.g.:
> irb(main):009:1> end
> irb(main):018:0> c = C.new(1)
> => #<C:0x2bbd440 @foo=1>
> irb(main):019:0> c.test
> 1
> => nil
>
>
>
Thanks! That's very interesting, and is exactly what I was looking for.
I was beginning to think it wasn't possible. I would not likely soon
have found this solution on my own, so I'm very grateful for your
assistance. Thanks for taking the time to respond.

t.

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This topic is locked and can not be replied to.