I am trying to understanding eval and binding contexts in Ruby.
Consinder the following in irb
irb(main):001:0> eval "a = 42"
=> 42
irb(main):002:0> a
NameError: undefined local variable or method `a' for main:Object
from (irb):2
from /Users/niels/.rbenv/versions/2.1.3/bin/irb:11:in `<main>'
irb(main):003:0>
Why is a not defined?
If I declare a prior to evalling, the value 42 is assigned to a.
It appears to me that some sort of block scope applies where local variables are available inside the eval context, but any variables declared are only declared in the block scope.
How do I eval code without creating a new scope?
Why is
anot defined?
a is defined within the binding of the eval'd code, but not outside of it. That's just how local variables work. They are local to the scope they are defined in. That's why they are called "local" variables, after all.
If I declare
aprior to evalling, the value 42 is assigned toa.
Yes, eval's scope nests, just like block scope.
How do I eval code without creating a new scope?
You can't. In Ruby 1.8 and prior, eval would indeed leak variables into the surrounding scope, but that leak was fixed in 1.9 and onwards.
That is because a is not on the same context than irb.
look at this code
2.2.1 :001 > eval "a = 42"
=> 42
2.2.1 :002 > a
NameError: undefined local variable or method `a' for main:Object
from (irb):2
from /home/hbranciforte/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'
it's the same as blocks
2.2.1 :001 > 1.times{|a| b=1}
=> 1
2.2.1 :002 > b
NameError: undefined local variable or method `b' for main:Object
from (irb):2
from /home/hbranciforte/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'
But...
2.2.1 :001 > a=nil
=> nil
2.2.1 :002 > eval "a = 42"
=> 42
2.2.1 :003 > a
=> 42
it's like
2.2.1 :001 > b=nil
=> nil
2.2.1 :002 > 1.times{|a| b=1}
=> 1
2.2.1 :003 > b
=> 1
2.2.1 :004 >
Instances variables work because it is part of "self"
2.2.1 :001 > eval "@b = 42"
=> 42
2.2.1 :002 > @b
=> 42
2.2.1 :003 >
Take a look how to context could be sent to a method. from http://ruby-doc.org/core-2.2.0/Binding.html
def get_binding(param)
return binding
end
b = get_binding("hello")
b.eval("param") #=> "hello"
I don't know if I was clear but, that I want to say is that the real thing that really matters is the context (or scope) where ruby will allocate/deallocate memory and his access.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With