summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--test/ruby/test_refinement.rb52
-rw-r--r--vm_method.c8
3 files changed, 71 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index f3b7609..3496c87 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Tue Feb 3 15:23:58 2015 Shugo Maeda <shugo@ruby-lang.org>
+
+ * 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.
+
+ Patch by Seiei Higa. [ruby-core:67722] [Bug #10765]
+
Tue Feb 3 14:04:47 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* dir.c (glob_helper): obtain real name with FindFirstFile API
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 @@ class TestRefinement < Test::Unit::TestCase
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);
}