Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running eval without creating a block scope

Tags:

ruby

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?

like image 755
Niels B. Avatar asked Dec 31 '25 09:12

Niels B.


2 Answers

Why is a not 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 a prior to evalling, the value 42 is assigned to a.

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.

like image 198
Jörg W Mittag Avatar answered Jan 02 '26 01:01

Jörg W Mittag


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.

like image 45
Horacio Avatar answered Jan 02 '26 03:01

Horacio