Files
mruby-mruby/mrbgems/mruby-binding/test/binding.rb
T
dearblue c182903ea0 Fixed finding variables from proc in binding.eval failed
Previously the following code did not produce the expected results:
```ruby
bx = binding
block = bx.eval("a = 1; proc { a }")
bx.eval("a = 2")
p block.call  # Expect 2 but return 1 due to a bug
```

The previous implementation of `Binding#eval` evaluated the code and then merged the top layer variables.
This patch will parse and expand the variable space before making a call to `eval`.
This means that the call to `Binding#eval` will do the parsing twice.

In addition, the following changes will be made:
- Make `mrb_parser_foreach_top_variable()`, `mrb_binding_extract_proc()` and `mrb_binding_extract_env()` functions private global functions.
- Remove the `posthook` argument from `mrb_exec_irep()`.
  The `posthook` argument was introduced to implement the `binding` method.
  This patch is unnecessary because it uses a different implementation method.

ref #5362
fixed #5491
2021-06-26 13:43:36 +09:00

78 lines
2.0 KiB
Ruby

assert("Binding#eval") do
b = nil
1.times { x, y, z = 1, 2, 3; [x,y,z]; b = binding }
assert_equal([1, 2, 3], b.eval("[x, y, z]"))
here = self
assert_equal(here, b.eval("self"))
end
assert("Binding#local_variables") do
block = Proc.new do |a|
b = 1
binding
end
bind = block.call(0)
assert_equal [:a, :b, :bind, :block], bind.local_variables.sort
bind.eval("x = 2")
assert_equal [:a, :b, :bind, :block, :x], bind.local_variables.sort
end
assert("Binding#local_variable_set") do
bind = binding
1.times {
assert_equal(9, bind.local_variable_set(:x, 9))
assert_equal(9, bind.eval("x"))
assert_equal([:bind, :x], bind.eval("local_variables.sort"))
}
end
assert("Binding#local_variable_get") do
bind = binding
x = 1
1.times {
y = 2
assert_equal(1, bind.local_variable_get(:x))
x = 10
assert_equal(10, bind.local_variable_get(:x))
assert_raise(NameError) { bind.local_variable_get(:y) }
bind.eval("z = 3")
assert_equal(3, bind.local_variable_get(:z))
bind.eval("y = 5")
assert_equal(5, bind.local_variable_get(:y))
assert_equal(2, y)
}
end
assert("Binding#source_location") do
skip unless -> {}.source_location
bind, source_location = binding, [__FILE__, __LINE__]
assert_equal source_location, bind.source_location
end
assert "Kernel#binding and .eval from C" do
bind = binding_in_c
assert_equal 5, bind.eval("2 + 3")
assert_nothing_raised { bind.eval("self") }
end
assert "Binding#eval with Binding.new via UnboundMethod" do
assert_raise(NoMethodError) { Class.instance_method(:new).bind_call(Binding) }
end
assert "Binding#eval with Binding.new via Method" do
# The following test is OK if SIGSEGV does not occur
cx = Class.new(Binding)
cx.define_singleton_method(:allocate, &Object.method(:allocate))
Class.instance_method(:new).bind_call(cx).eval("")
assert_true true
end
assert "access local variables into procs" do
bx = binding
block = bx.eval("a = 1; proc { a }")
bx.eval("a = 2")
assert_equal 2, block.call
end