Bug #16251
closedEvaluation in binding differs from ruby execution
Description
In specific situation, I found that result of string evaluation in Binding returns different from ruby execution result.
In following sample code, ruby evaluates method_or_local_var
as method call and returns "method"
.
However, binding.eval
evaluates method_or_local_var
as local variable and returns nil
.
Here is sample code.
def method_or_local_var
'method'
end
if true
puts "execute method_or_local_var:"
p method_or_local_var #=> "method"
puts "execute method_or_local_var by bind.eval('method_or_local_var'):"
p binding.eval('method_or_local_var') #=> nil
else
method_or_local_var = 'local variable'
end
and here is results of execute sample code.
❯ ruby sample_code.rb
execute method_or_local_var:
"method"
execute method_or_local_var by bind.eval('method_or_local_var'):
nil
I expect evaluation result of method_or_local_var
in binding to be method, and returns "method"
.
Is this the expected behavior?
Updated by mame (Yusuke Endoh) about 5 years ago
I have no idea whether this is a spec or undefined behavior, but the current implementation is actually intentional.
def x
"x"
end
def foo
eval("x = 1") # foo has no variable named x, so 1 is assigned to a temporal variable
p eval("x") #=> "x" # there is no variable named x in this scope, so it is regarded as a method call
end
foo
def bar
eval("x = 1") # foo has a variable named x, so 1 is assigned to the variable
p eval("x") #=> 1 # foo has a variable named x, so it is regarded as a variable reference
x = nil
end
bar
IMO, you'd better not to depend upon the behavior in any way.
Updated by Eregon (Benoit Daloze) about 5 years ago
Local variables are "hoisted" to the beginning of the method/block in Ruby (and start with value nil
).
With that in mind, I think the behavior is logical. IMHO, it is spec.
Updated by jeremyevans0 (Jeremy Evans) about 5 years ago
- Status changed from Open to Closed
Updated by kernigh (George Koehler) about 5 years ago
This is a simpler example of the behavior:
$ ruby -e 'p x; x = 6'
Traceback (most recent call last):
-e:1:in `<main>': undefined local variable or method `x' for main:Object (NameError)
$ ruby -e 'p eval("x"); x = 6'
nil
$ ruby -e 'p binding.eval("x"); x = 6'
nil
A plain x
raises NameError, but an eval("x")
or binding.eval("x")
fetches nil from the local variable x. I expect this behavior, because Ruby parses a script before running it:
- Ruby parses
x = 6
and adds x to the binding. - Ruby runs
eval("x")
with x in the binding. - Ruby runs
x = 6
and changes the value of x from nil to 6.
Binding#local_variables reveals the local variable named x:
$ ruby -e 'p binding.local_variables; x = 6'
[:x]
Because x exists, binding.eval("x")
has the expected behavior, so there is no bug.