From b166d4bc7c9710e1b6184659d2f51710228998f6 Mon Sep 17 00:00:00 2001 From: shugo Date: Fri, 23 Sep 2016 11:46:33 +0000 Subject: * eval.c (rb_mod_refine): refine modules as well. [ruby-core:76199] [Feature #12534] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56213 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 ++++ diff | 13 ++++++++++ eval.c | 20 +++++++++++---- test/ruby/test_refinement.rb | 61 +++++++++++++++++++++++++++++++++++++++----- vm_method.c | 8 ++++-- 5 files changed, 93 insertions(+), 14 deletions(-) create mode 100644 diff diff --git a/ChangeLog b/ChangeLog index 87edb68dff..8d4752ef3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri Sep 23 20:36:05 2016 Shugo Maeda + + * eval.c (rb_mod_refine): refine modules as well. + [ruby-core:76199] [Feature #12534] + Fri Sep 23 20:19:09 2016 Akinori MUSHA * man/ruby.1: Update the paragraphs in "Rich Libraries" which diff --git a/diff b/diff new file mode 100644 index 0000000000..b16c897709 --- /dev/null +++ b/diff @@ -0,0 +1,13 @@ +diff --git a/tool/mkconfig.rb b/tool/mkconfig.rb +index 6b6f14c..ee0642c 100755 +--- a/tool/mkconfig.rb ++++ b/tool/mkconfig.rb +@@ -20,7 +20,7 @@ + require "fileutils" + mkconfig = File.basename($0) + +-fast = {'prefix'=>TRUE, 'ruby_install_name'=>TRUE, 'INSTALL'=>TRUE, 'EXEEXT'=>TRUE} ++fast = {'prefix'=>true, 'ruby_install_name'=>true, 'INSTALL'=>true, 'EXEEXT'=>true} + + win32 = /mswin/ =~ arch + universal = /universal.*darwin/ =~ arch diff --git a/eval.c b/eval.c index 1baf914a3a..5f5da2881a 100644 --- a/eval.c +++ b/eval.c @@ -1092,6 +1092,16 @@ rb_mod_prepend(int argc, VALUE *argv, VALUE module) return module; } +static void +ensure_class_or_module(VALUE obj) +{ + if (!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE)) { + rb_raise(rb_eTypeError, + "wrong argument type %"PRIsVALUE" (expected Class or Module)", + rb_obj_class(obj)); + } +} + static VALUE hidden_identity_hash_new(void) { @@ -1106,7 +1116,7 @@ rb_using_refinement(rb_cref_t *cref, VALUE klass, VALUE module) { VALUE iclass, c, superclass = klass; - Check_Type(klass, T_CLASS); + ensure_class_or_module(klass); Check_Type(module, T_MODULE); if (NIL_P(CREF_REFINEMENTS(cref))) { CREF_REFINEMENTS_SET(cref, hidden_identity_hash_new()); @@ -1231,11 +1241,11 @@ add_activated_refinement(VALUE activated_refinements, /* * call-seq: - * refine(klass) { block } -> module + * refine(mod) { block } -> module * - * Refine klass in the receiver. + * Refine mod in the receiver. * - * Returns an overlaid module. + * Returns a module, where refined methods are defined. */ static VALUE @@ -1255,7 +1265,7 @@ rb_mod_refine(VALUE module, VALUE klass) rb_raise(rb_eArgError, "can't pass a Proc as a block to Module#refine"); } - Check_Type(klass, T_CLASS); + ensure_class_or_module(klass); CONST_ID(id_refinements, "__refinements__"); refinements = rb_attr_get(module, id_refinements); if (NIL_P(refinements)) { diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index c3c2dbc61f..4f7918e810 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -345,17 +345,64 @@ class TestRefinement < Test::Unit::TestCase assert_equal([:c, :m1, :m2], x) end - def test_refine_module - m1 = Module.new - assert_raise(TypeError) do - Module.new { - refine m1 do + module RefineModule + module M + def foo + "M#foo" + end + + def bar + "M#bar" + end + + def baz + "M#baz" + end + end + + class C + include M + + def baz + "#{super} C#baz" + end + end + + module M2 + refine M do def foo - :m2 + "M@M2#foo" end + + def bar + "#{super} M@M2#bar" end - } + + def baz + "#{super} M@M2#baz" + end + end end + + using M2 + + def self.call_foo + C.new.foo + end + + def self.call_bar + C.new.bar + end + + def self.call_baz + C.new.baz + end + end + + def test_refine_module + assert_equal("M@M2#foo", RefineModule.call_foo) + assert_equal("M#bar M@M2#bar", RefineModule.call_bar) + assert_equal("M#baz C#baz", RefineModule.call_baz) end def test_refine_neither_class_nor_module diff --git a/vm_method.c b/vm_method.c index b5a6f538d0..c7417de455 100644 --- a/vm_method.c +++ b/vm_method.c @@ -439,13 +439,17 @@ make_method_entry_refined(VALUE owner, rb_method_entry_t *me) } else { struct { - const struct rb_method_entry_struct *orig_me; + struct rb_method_entry_struct *orig_me; VALUE owner; } refined; rb_vm_check_redefinition_opt_method(me, me->owner); - refined.orig_me = rb_method_entry_clone(me); + refined.orig_me = + rb_method_entry_alloc(me->called_id, me->owner, + me->defined_class || owner, + method_definition_addref(me->def)); + METHOD_ENTRY_FLAGS_COPY(refined.orig_me, me); refined.owner = owner; method_definition_set(me, method_definition_create(VM_METHOD_TYPE_REFINED, me->called_id), (void *)&refined); -- cgit v1.2.3