From 6c72f8b378fc8743ec1775b3e2d7dd507ec2b394 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 25 Apr 2025 18:50:16 +0900 Subject: [PATCH] class.c (extend_object): remove method; implement Kernel#extend in C --- include/mruby/internal.h | 1 + mrblib/00kernel.rb | 36 ------------------------ src/class.c | 59 ++++++++++++++++++++++++++++++++-------- src/kernel.c | 3 +- test/t/module.rb | 12 -------- 5 files changed, 50 insertions(+), 61 deletions(-) delete mode 100644 mrblib/00kernel.rb diff --git a/include/mruby/internal.h b/include/mruby/internal.h index 23374e29e..1bb746f93 100644 --- a/include/mruby/internal.h +++ b/include/mruby/internal.h @@ -28,6 +28,7 @@ mrb_method_t mrb_vm_find_method(mrb_state *mrb, struct RClass *c, struct RClass mrb_value mrb_mod_const_missing(mrb_state *mrb, mrb_value mod); mrb_value mrb_const_missing(mrb_state *mrb, mrb_value mod, mrb_sym sym); size_t mrb_class_mt_memsize(mrb_state*, struct RClass*); +mrb_value mrb_obj_extend(mrb_state*, mrb_value obj); #endif mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); diff --git a/mrblib/00kernel.rb b/mrblib/00kernel.rb deleted file mode 100644 index b3a7e08a2..000000000 --- a/mrblib/00kernel.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Kernel - ## - # call-seq: - # obj.extend(module, ...) -> obj - # - # Adds to _obj_ the instance methods from each module given as a - # parameter. - # - # module Mod - # def hello - # "Hello from Mod.\n" - # end - # end - # - # class Klass - # def hello - # "Hello from Klass.\n" - # end - # end - # - # k = Klass.new - # k.hello #=> "Hello from Klass.\n" - # k.extend(Mod) #=> # - # k.hello #=> "Hello from Mod.\n" - # - # ISO 15.3.1.3.13 - def extend(*args) - args.reverse! - obj = self - args.each do |m| - m.__send__(:extend_object, obj) - m.__send__(:extended, obj) - end - self - end -end diff --git a/src/class.c b/src/class.c index df3e3bc55..b4caacb49 100644 --- a/src/class.c +++ b/src/class.c @@ -1625,6 +1625,53 @@ mrb_mod_include(mrb_state *mrb, mrb_value mod) return mod; } +/* 15.3.1.3.13 */ +/* + * call-seq: + * obj.extend(module, ...) -> obj + * + * Adds to _obj_ the instance methods from each module given as a + * parameter. + * + * module Mod + * def hello + * "Hello from Mod.\n" + * end + * end + * + * class Klass + * def hello + * "Hello from Klass.\n" + * end + * end + * + * k = Klass.new + * k.hello #=> "Hello from Klass.\n" + * k.extend(Mod) #=> # + * k.hello #=> "Hello from Mod.\n" + * + */ +mrb_value +mrb_obj_extend(mrb_state *mrb, mrb_value obj) +{ + mrb_int argc; + mrb_value *argv; + mrb_sym extended = MRB_SYM(extended); + + mrb_get_args(mrb, "*", &argv, &argc); + + mrb_value cc = mrb_singleton_class(mrb, obj); + while (argc--) { + mrb_value mod = argv[argc]; + mrb_check_type(mrb, mod, MRB_TT_MODULE); + mrb_include_module(mrb, mrb_class_ptr(cc), mrb_class_ptr(mod)); + if (!mrb_func_basic_p(mrb, cc, extended, mrb_do_nothing)) { + mrb_funcall_argv(mrb, cc, extended, 1, &mod); + } + } + return obj; +} + /* 15.2.2.4.28 */ /* * call-seq: @@ -1681,16 +1728,6 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) return result; } -static mrb_value -mrb_mod_extend_object(mrb_state *mrb, mrb_value mod) -{ - mrb_value obj = mrb_get_arg1(mrb); - - mrb_check_type(mrb, mod, MRB_TT_MODULE); - mrb_include_module(mrb, mrb_class_ptr(mrb_singleton_class(mrb, obj)), mrb_class_ptr(mod)); - return mod; -} - static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { @@ -3174,7 +3211,6 @@ mrb_init_class(mrb_state *mrb) init_class_new(mrb, cls); MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); - mrb_define_private_method_id(mrb, mod, MRB_SYM(extend_object), mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_private_method_id(mrb, mod, MRB_SYM(extended), mrb_do_nothing, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ mrb_define_private_method_id(mrb, mod, MRB_SYM(prepended), mrb_do_nothing, MRB_ARGS_REQ(1)); mrb_define_method_id(mrb, mod, MRB_SYM_Q(include), mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */ @@ -3211,7 +3247,6 @@ mrb_init_class(mrb_state *mrb) mrb_define_private_method_id(mrb, mod, MRB_SYM(method_undefined), mrb_do_nothing, MRB_ARGS_REQ(1)); mrb_define_private_method_id(mrb, mod, MRB_SYM(const_added), mrb_do_nothing, MRB_ARGS_REQ(1)); - mrb_undef_method_id(mrb, cls, MRB_SYM(extend_object)); mrb_undef_method_id(mrb, cls, MRB_SYM(module_function)); mrb->top_self = MRB_OBJ_ALLOC(mrb, MRB_TT_OBJECT, mrb->object_class); diff --git a/src/kernel.c b/src/kernel.c index cecb93994..94cc7a2d4 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -591,6 +591,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method_id(mrb, krn, MRB_SYM_Q(eql), mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ mrb_define_method_id(mrb, krn, MRB_SYM(freeze), mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method_id(mrb, krn, MRB_SYM_Q(frozen), mrb_obj_frozen, MRB_ARGS_NONE()); + mrb_define_method_id(mrb, krn, MRB_SYM(extend), mrb_obj_extend, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method_id(mrb, krn, MRB_SYM(hash), mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_private_method_id(mrb, krn, MRB_SYM(initialize_copy), mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method_id(mrb, krn, MRB_SYM(inspect), mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ @@ -611,7 +612,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method_id(mrb, krn, MRB_SYM(to_s), mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method_id(mrb, krn, MRB_SYM(__case_eqq), mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ mrb_define_method_id(mrb, krn, MRB_SYM(__to_int), mrb_ensure_int_type, MRB_ARGS_NONE()); /* internal */ - mrb_define_private_method_id(mrb, krn, MRB_SYM_Q(respond_to_missing), mrb_false, MRB_ARGS_ARG(1,1)); + mrb_define_private_method_id(mrb, krn, MRB_SYM_Q(respond_to_missing), mrb_false, MRB_ARGS_ARG(1,1)); mrb_define_method_id(mrb, krn, MRB_SYM_Q(__inspect_recursive), mrb_obj_inspect_recursive_p, MRB_ARGS_NONE()); mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); diff --git a/test/t/module.rb b/test/t/module.rb index 399de042a..bf4b4a25e 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -295,18 +295,6 @@ assert('Module#const_missing', '15.2.2.4.22') do assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) end -assert('Module#extend_object', '15.2.2.4.25') do - cls = Class.new - mod = Module.new { def foo; end } - a = cls.new - b = cls.new - mod.__send__(:extend_object,b) - assert_false a.respond_to?(:foo) - assert_true b.respond_to?(:foo) - assert_raise(FrozenError) { mod.__send__(:extend_object,cls.new.freeze) } - assert_raise(FrozenError, TypeError) { mod.__send__(:extend_object,1) } -end - assert('Module#include', '15.2.2.4.27') do module Test4Include Const4Include = 42