From 927615e1f072d8fff3d9b84660cdce15a239e36c Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 22 Feb 2021 23:32:43 +0900 Subject: Added other methods for `Binding` - Added to `mruby-binding-core` - `Binding#local_variable_defined?` - `Binding#local_variable_get` - `Binding#local_variable_set` - `Binding#local_variables` - `Binding#receiver` - `Binding#source_location` - `Binding#inspect` - Added to `mruby-proc-binding` - `Proc#binding` The reason for separating `Proc#binding` is that core-mrbgems has a method that returns a closure object to minimize possible problems with being able to manipulate internal variables. By separating it as different mrbgem, each user can judge this problem and incorporate it arbitrarily. --- mrbgems/mruby-binding/mrbgem.rake | 3 ++ mrbgems/mruby-binding/test/binding.c | 13 +++++++ mrbgems/mruby-binding/test/binding.rb | 65 +++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 mrbgems/mruby-binding/test/binding.c (limited to 'mrbgems/mruby-binding') diff --git a/mrbgems/mruby-binding/mrbgem.rake b/mrbgems/mruby-binding/mrbgem.rake index 2701c506f..4ad5638ea 100644 --- a/mrbgems/mruby-binding/mrbgem.rake +++ b/mrbgems/mruby-binding/mrbgem.rake @@ -5,4 +5,7 @@ MRuby::Gem::Specification.new('mruby-binding') do |spec| spec.add_dependency('mruby-binding-core', :core => 'mruby-binding-core') spec.add_dependency('mruby-eval', :core => 'mruby-eval') + spec.add_test_dependency('mruby-metaprog', :core => 'mruby-metaprog') + spec.add_test_dependency('mruby-method', :core => 'mruby-method') + spec.add_test_dependency('mruby-proc-ext', :core => 'mruby-proc-ext') end diff --git a/mrbgems/mruby-binding/test/binding.c b/mrbgems/mruby-binding/test/binding.c new file mode 100644 index 000000000..5a37ca043 --- /dev/null +++ b/mrbgems/mruby-binding/test/binding.c @@ -0,0 +1,13 @@ +#include + +static mrb_value +binding_in_c(mrb_state *mrb, mrb_value self) +{ + return mrb_funcall_argv(mrb, mrb_obj_value(mrb->object_class), mrb_intern_lit(mrb, "binding"), 0, NULL); +} + +void +mrb_mruby_binding_gem_test(mrb_state *mrb) +{ + mrb_define_method(mrb, mrb->object_class, "binding_in_c", binding_in_c, MRB_ARGS_NONE()); +} diff --git a/mrbgems/mruby-binding/test/binding.rb b/mrbgems/mruby-binding/test/binding.rb index 73742400f..7dd3fd1dd 100644 --- a/mrbgems/mruby-binding/test/binding.rb +++ b/mrbgems/mruby-binding/test/binding.rb @@ -2,4 +2,69 @@ 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 -- cgit v1.2.3