From 44c67385ad552173ece3251fe118e62b390ffca9 Mon Sep 17 00:00:00 2001 From: Seiei Higa Date: Wed, 21 Jan 2015 21:29:52 +0900 Subject: [PATCH] vm_method.c: fix remove refined method. * vm_method.c (remove_method): When remove refined method, raise a NameError if the method is not defined in refined class. But if the method is defined in refined class, it should keep refined method and remove original method. [ruby-core:67722] [Bug #10765] --- test/ruby/test_refinement.rb | 52 ++++++++++++++++++++++++++++++++++++++++++++ vm_method.c | 8 ++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index df16254..cb7c53f 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -1310,6 +1310,58 @@ def undefined_refined_private; end end; end + def test_remove_refined_method + assert_separately([], <<-"end;") + bug10765 = '[ruby-core:67722] [Bug #10765]' + + class C + def foo + "C#foo" + end + end + + module RefinementBug + refine C do + def foo + "RefinementBug#foo" + end + end + end + + using RefinementBug + + class C + remove_method :foo + end + + assert_equal("RefinementBug#foo", C.new.foo, bug10765) + end; + end + + def test_remove_undefined_refined_method + assert_separately([], <<-"end;") + bug10765 = '[ruby-core:67722] [Bug #10765]' + + class C + end + + module RefinementBug + refine C do + def foo + end + end + end + + using RefinementBug + + assert_raise(NameError, bug10765) { + class C + remove_method :foo + end + } + end; + end + private def eval_using(mod, s) diff --git a/vm_method.c b/vm_method.c index b2cff6f..8ad2b72 100644 --- a/vm_method.c +++ b/vm_method.c @@ -766,10 +766,12 @@ remove_method(VALUE klass, ID mid) if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) || !(me = (rb_method_entry_t *)data) || - (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) { + (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) || + UNDEFINED_REFINED_METHOD_P(me->def)) { rb_name_error(mid, "method `%"PRIsVALUE"' not defined in %"PRIsVALUE, rb_id2str(mid), rb_class_path(klass)); } + key = (st_data_t)mid; st_delete(RCLASS_M_TBL(klass), &key, &data); @@ -777,6 +779,10 @@ remove_method(VALUE klass, ID mid) rb_clear_method_cache_by_class(klass); rb_unlink_method_entry(me); + if (me->def->type == VM_METHOD_TYPE_REFINED) { + rb_add_refined_method_entry(klass, mid); + } + CALL_METHOD_HOOK(self, removed, mid); } -- 2.2.1