summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-class-ext
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-12-20 20:18:25 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-12-23 10:01:30 +0900
commit8d7e95282c64f482a28e7bc579857e781d03c74b (patch)
tree758f1ffe54df84f99aa21f2dd8ee47969b41822f /mrbgems/mruby-class-ext
parent7fbbd7ab9fdeb9eafe6a37fa7f16b60e41e21ad4 (diff)
downloadmruby-8d7e95282c64f482a28e7bc579857e781d03c74b.tar.gz
mruby-8d7e95282c64f482a28e7bc579857e781d03c74b.zip
Add `#module_exec` and `#class_exec` in `mruby-class-ext` gem.
Diffstat (limited to 'mrbgems/mruby-class-ext')
-rw-r--r--mrbgems/mruby-class-ext/src/class.c38
-rw-r--r--mrbgems/mruby-class-ext/test/module.rb21
2 files changed, 59 insertions, 0 deletions
diff --git a/mrbgems/mruby-class-ext/src/class.c b/mrbgems/mruby-class-ext/src/class.c
index 5506c4829..705db9949 100644
--- a/mrbgems/mruby-class-ext/src/class.c
+++ b/mrbgems/mruby-class-ext/src/class.c
@@ -15,6 +15,42 @@ mrb_mod_singleton_class_p(mrb_state *mrb, mrb_value self)
return mrb_bool_value(mrb_type(self) == MRB_TT_SCLASS);
}
+/*
+ * call-seq:
+ * module_exec(arg...) {|var...| block } -> obj
+ * class_exec(arg...) {|var...| block } -> obj
+ *
+ * Evaluates the given block in the context of the
+ * class/module. The method defined in the block will belong
+ * to the receiver. Any arguments passed to the method will be
+ * passed to the block. This can be used if the block needs to
+ * access instance variables.
+ *
+ * class Thing
+ * end
+ * Thing.class_exec{
+ * def hello() "Hello there!" end
+ * }
+ * puts Thing.new.hello()
+ */
+
+static mrb_value
+mrb_mod_module_exec(mrb_state *mrb, mrb_value self)
+{
+ const mrb_value *argv;
+ mrb_int argc;
+ mrb_value blk;
+
+ mrb_get_args(mrb, "*&", &argv, &argc, &blk);
+
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+
+ mrb->c->ci->target_class = mrb_class_ptr(self);
+ return mrb_yield_cont(mrb, blk, self, argc, argv);
+}
+
void
mrb_mruby_class_ext_gem_init(mrb_state *mrb)
{
@@ -22,6 +58,8 @@ mrb_mruby_class_ext_gem_init(mrb_state *mrb)
mrb_define_method(mrb, mod, "name", mrb_mod_name, MRB_ARGS_NONE());
mrb_define_method(mrb, mod, "singleton_class?", mrb_mod_singleton_class_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, mod, "module_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
+ mrb_define_method(mrb, mod, "class_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
}
void
diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb
index 65abde108..ed6713aac 100644
--- a/mrbgems/mruby-class-ext/test/module.rb
+++ b/mrbgems/mruby-class-ext/test/module.rb
@@ -32,3 +32,24 @@ assert 'Module#singleton_class?' do
assert_false cls.singleton_class?
assert_true scl.singleton_class?
end
+
+assert 'Module#module_eval' do
+ mod = Module.new
+ mod.class_exec(1,2,3) do |a,b,c|
+ assert_equal([1,2,3], [a,b,c])
+ def hi
+ "hi"
+ end
+ end
+ cls = Class.new
+ cls.class_exec(42) do |x|
+ assert_equal(42, x)
+ include mod
+ def hello
+ "hello"
+ end
+ end
+ obj = cls.new
+ assert_equal("hi", obj.hi)
+ assert_equal("hello", obj.hello)
+end