summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-proc-binding
diff options
context:
space:
mode:
authordearblue <[email protected]>2021-02-22 23:32:43 +0900
committerdearblue <[email protected]>2021-02-22 23:32:43 +0900
commit927615e1f072d8fff3d9b84660cdce15a239e36c (patch)
tree14e14aa860b778176435be8d6d666917d891a9d8 /mrbgems/mruby-proc-binding
parent792f6ac6700469ddf9be8f87ca3376082f9af7f3 (diff)
downloadmruby-927615e1f072d8fff3d9b84660cdce15a239e36c.tar.gz
mruby-927615e1f072d8fff3d9b84660cdce15a239e36c.zip
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.
Diffstat (limited to 'mrbgems/mruby-proc-binding')
-rw-r--r--mrbgems/mruby-proc-binding/mrbgem.rake9
-rw-r--r--mrbgems/mruby-proc-binding/src/proc-binding.c52
-rw-r--r--mrbgems/mruby-proc-binding/test/proc-binding.c14
-rw-r--r--mrbgems/mruby-proc-binding/test/proc-binding.rb22
4 files changed, 97 insertions, 0 deletions
diff --git a/mrbgems/mruby-proc-binding/mrbgem.rake b/mrbgems/mruby-proc-binding/mrbgem.rake
new file mode 100644
index 000000000..425aac847
--- /dev/null
+++ b/mrbgems/mruby-proc-binding/mrbgem.rake
@@ -0,0 +1,9 @@
+MRuby::Gem::Specification.new('mruby-proc-binding') do |spec|
+ spec.license = 'MIT'
+ spec.author = 'mruby developers'
+ spec.summary = 'Proc#binding method'
+
+ spec.add_dependency('mruby-binding-core', :core => 'mruby-binding-core')
+ spec.add_test_dependency('mruby-binding', :core => 'mruby-binding')
+ spec.add_test_dependency('mruby-compiler', :core => 'mruby-compiler')
+end
diff --git a/mrbgems/mruby-proc-binding/src/proc-binding.c b/mrbgems/mruby-proc-binding/src/proc-binding.c
new file mode 100644
index 000000000..82d9d1d51
--- /dev/null
+++ b/mrbgems/mruby-proc-binding/src/proc-binding.c
@@ -0,0 +1,52 @@
+#include <mruby.h>
+#include <mruby/presym.h>
+#include <mruby/proc.h>
+#include <mruby/variable.h>
+
+void mrb_proc_merge_lvar(mrb_state *mrb, mrb_irep *irep, struct REnv *env, int num, const mrb_sym *lv, const mrb_value *stack);
+
+/* provided by mruby-proc-ext */
+mrb_value mrb_proc_source_location(mrb_state *mrb, struct RProc *p);
+
+/* provided by mruby-binding-core */
+mrb_value mrb_binding_alloc(mrb_state *mrb);
+struct RProc *mrb_binding_wrap_lvspace(mrb_state *mrb, const struct RProc *proc, struct REnv **envp);
+
+static mrb_value
+mrb_proc_binding(mrb_state *mrb, mrb_value procval)
+{
+ mrb_value binding = mrb_binding_alloc(mrb);
+ const struct RProc *proc = mrb_proc_ptr(procval);
+ struct REnv *env;
+
+ mrb_value receiver;
+ if (!proc || MRB_PROC_CFUNC_P(proc) || !proc->upper || MRB_PROC_CFUNC_P(proc->upper)) {
+ env = NULL;
+ proc = NULL;
+ receiver = mrb_nil_value();
+ }
+ else {
+ env = MRB_PROC_ENV(proc);
+ mrb_assert(env);
+ proc = proc->upper;
+ receiver = MRB_ENV_LEN(env) > 0 ? env->stack[0] : mrb_nil_value();
+ }
+
+ proc = mrb_binding_wrap_lvspace(mrb, proc, &env);
+ mrb_iv_set(mrb, binding, MRB_SYM(proc), mrb_obj_value((void *)proc));
+ mrb_iv_set(mrb, binding, MRB_SYM(recv), receiver);
+ mrb_iv_set(mrb, binding, MRB_SYM(env), mrb_obj_value(env));
+ mrb_iv_set(mrb, binding, MRB_SYM(source_location), mrb_proc_source_location(mrb, mrb_proc_ptr(procval)));
+ return binding;
+}
+
+void
+mrb_mruby_proc_binding_gem_init(mrb_state *mrb)
+{
+ mrb_define_method(mrb, mrb->proc_class, "binding", mrb_proc_binding, MRB_ARGS_NONE());
+}
+
+void
+mrb_mruby_proc_binding_gem_final(mrb_state *mrb)
+{
+}
diff --git a/mrbgems/mruby-proc-binding/test/proc-binding.c b/mrbgems/mruby-proc-binding/test/proc-binding.c
new file mode 100644
index 000000000..ec071b920
--- /dev/null
+++ b/mrbgems/mruby-proc-binding/test/proc-binding.c
@@ -0,0 +1,14 @@
+#include <mruby.h>
+#include <mruby/compile.h>
+
+static mrb_value
+proc_in_c(mrb_state *mrb, mrb_value self)
+{
+ return mrb_load_string(mrb, "proc { |a, b| a + b }");
+}
+
+void
+mrb_mruby_proc_binding_gem_test(mrb_state *mrb)
+{
+ mrb_define_method(mrb, mrb->object_class, "proc_in_c", proc_in_c, MRB_ARGS_NONE());
+}
diff --git a/mrbgems/mruby-proc-binding/test/proc-binding.rb b/mrbgems/mruby-proc-binding/test/proc-binding.rb
new file mode 100644
index 000000000..b28d8b1dd
--- /dev/null
+++ b/mrbgems/mruby-proc-binding/test/proc-binding.rb
@@ -0,0 +1,22 @@
+assert "Proc#binding" do
+ block = ->(i) {}
+ a, b, c = 1, 2, 3
+ bind = block.binding
+ assert_equal([:a, :b, :bind, :block, :c], bind.local_variables.sort)
+ assert_equal(1, bind.local_variable_get(:a))
+ assert_equal(5, bind.eval("b + c"))
+ bind.local_variable_set(:x, 9)
+ assert_equal(9, bind.local_variable_get(:x))
+end
+
+assert("Binding#source_location after Proc#binding") do
+ skip unless -> {}.source_location
+
+ block, source_location = -> {}, [__FILE__, __LINE__]
+ assert_equal source_location, block.binding.source_location
+end
+
+assert "Proc#binding and .eval from C" do
+ bind = proc_in_c.binding
+ assert_nothing_raised { bind.eval("self") }
+end