summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_module.rb105
-rw-r--r--vm_method.c135
2 files changed, 153 insertions, 87 deletions
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb
index 08254605cf..15a39346dd 100644
--- a/test/ruby/test_module.rb
+++ b/test/ruby/test_module.rb
@@ -468,17 +468,42 @@ class TestModule < Test::Unit::TestCase
end
def test_method_defined?
- assert !User.method_defined?(:wombat)
- assert User.method_defined?(:mixin)
- assert User.method_defined?(:user)
- assert User.method_defined?(:user2)
- assert !User.method_defined?(:user3)
+ [User, Class.new{include User}, Class.new{prepend User}].each do |klass|
+ [[], [true]].each do |args|
+ assert !klass.method_defined?(:wombat, *args)
+ assert klass.method_defined?(:mixin, *args)
+ assert klass.method_defined?(:user, *args)
+ assert klass.method_defined?(:user2, *args)
+ assert !klass.method_defined?(:user3, *args)
- assert !User.method_defined?("wombat")
- assert User.method_defined?("mixin")
- assert User.method_defined?("user")
- assert User.method_defined?("user2")
- assert !User.method_defined?("user3")
+ assert !klass.method_defined?("wombat", *args)
+ assert klass.method_defined?("mixin", *args)
+ assert klass.method_defined?("user", *args)
+ assert klass.method_defined?("user2", *args)
+ assert !klass.method_defined?("user3", *args)
+ end
+ end
+ end
+
+ def test_method_defined_without_include_super
+ assert User.method_defined?(:user, false)
+ assert !User.method_defined?(:mixin, false)
+ assert Mixin.method_defined?(:mixin, false)
+
+ User.const_set(:FOO, c = Class.new)
+
+ c.prepend(User)
+ assert !c.method_defined?(:user, false)
+ c.define_method(:user){}
+ assert c.method_defined?(:user, false)
+
+ assert !c.method_defined?(:mixin, false)
+ c.define_method(:mixin){}
+ assert c.method_defined?(:mixin, false)
+
+ assert !c.method_defined?(:userx, false)
+ c.define_method(:userx){}
+ assert c.method_defined?(:userx, false)
end
def module_exec_aux
@@ -974,8 +999,8 @@ class TestModule < Test::Unit::TestCase
end
def test_method_defined
- c = Class.new
- c.class_eval do
+ cl = Class.new
+ def_methods = proc do
def foo; end
def bar; end
def baz; end
@@ -983,33 +1008,47 @@ class TestModule < Test::Unit::TestCase
protected :bar
private :baz
end
+ cl.class_eval(&def_methods)
+ sc = Class.new(cl)
+ mod = Module.new(&def_methods)
+ only_prepend = Class.new{prepend(mod)}
+ empty_prepend = cl.clone
+ empty_prepend.prepend(Module.new)
+ overlap_prepend = cl.clone
+ overlap_prepend.prepend(mod)
- assert_equal(true, c.public_method_defined?(:foo))
- assert_equal(false, c.public_method_defined?(:bar))
- assert_equal(false, c.public_method_defined?(:baz))
+ [[], [true], [false]].each do |args|
+ [cl, sc, only_prepend, empty_prepend, overlap_prepend].each do |c|
+ always_false = [sc, only_prepend].include?(c) && args == [false]
- # Test if string arguments are converted to symbols
- assert_equal(true, c.public_method_defined?("foo"))
- assert_equal(false, c.public_method_defined?("bar"))
- assert_equal(false, c.public_method_defined?("baz"))
+ assert_equal(always_false ? false : true, c.public_method_defined?(:foo, *args))
+ assert_equal(always_false ? false : false, c.public_method_defined?(:bar, *args))
+ assert_equal(always_false ? false : false, c.public_method_defined?(:baz, *args))
- assert_equal(false, c.protected_method_defined?(:foo))
- assert_equal(true, c.protected_method_defined?(:bar))
- assert_equal(false, c.protected_method_defined?(:baz))
+ # Test if string arguments are converted to symbols
+ assert_equal(always_false ? false : true, c.public_method_defined?("foo", *args))
+ assert_equal(always_false ? false : false, c.public_method_defined?("bar", *args))
+ assert_equal(always_false ? false : false, c.public_method_defined?("baz", *args))
- # Test if string arguments are converted to symbols
- assert_equal(false, c.protected_method_defined?("foo"))
- assert_equal(true, c.protected_method_defined?("bar"))
- assert_equal(false, c.protected_method_defined?("baz"))
+ assert_equal(always_false ? false : false, c.protected_method_defined?(:foo, *args))
+ assert_equal(always_false ? false : true, c.protected_method_defined?(:bar, *args))
+ assert_equal(always_false ? false : false, c.protected_method_defined?(:baz, *args))
- assert_equal(false, c.private_method_defined?(:foo))
- assert_equal(false, c.private_method_defined?(:bar))
- assert_equal(true, c.private_method_defined?(:baz))
+ # Test if string arguments are converted to symbols
+ assert_equal(always_false ? false : false, c.protected_method_defined?("foo", *args))
+ assert_equal(always_false ? false : true, c.protected_method_defined?("bar", *args))
+ assert_equal(always_false ? false : false, c.protected_method_defined?("baz", *args))
- # Test if string arguments are converted to symbols
- assert_equal(false, c.private_method_defined?("foo"))
- assert_equal(false, c.private_method_defined?("bar"))
- assert_equal(true, c.private_method_defined?("baz"))
+ assert_equal(always_false ? false : false, c.private_method_defined?(:foo, *args))
+ assert_equal(always_false ? false : false, c.private_method_defined?(:bar, *args))
+ assert_equal(always_false ? false : true, c.private_method_defined?(:baz, *args))
+
+ # Test if string arguments are converted to symbols
+ assert_equal(always_false ? false : false, c.private_method_defined?("foo", *args))
+ assert_equal(always_false ? false : false, c.private_method_defined?("bar", *args))
+ assert_equal(always_false ? false : true, c.private_method_defined?("baz", *args))
+ end
+ end
end
def test_top_public_private
diff --git a/vm_method.c b/vm_method.c
index 8cf7cf7204..c4f41bc118 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -1278,14 +1278,44 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
return mod;
}
+static rb_method_visibility_t
+check_definition_visibility(VALUE mod, int argc, VALUE *argv)
+{
+ const rb_method_entry_t *me;
+ VALUE mid, include_super, lookup_mod = mod;
+ int inc_super;
+ ID id;
+
+ rb_scan_args(argc, argv, "11", &mid, &include_super);
+ id = rb_check_id(&mid);
+ if (!id) return METHOD_VISI_UNDEF;
+
+ if (argc == 1) {
+ inc_super = 1;
+ } else {
+ inc_super = RTEST(include_super);
+ if (!inc_super) {
+ lookup_mod = RCLASS_ORIGIN(mod);
+ }
+ }
+
+ me = rb_method_entry_without_refinements(lookup_mod, id, NULL);
+ if (me) {
+ if (me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) return METHOD_VISI_UNDEF;
+ if (!inc_super && me->owner != mod) return METHOD_VISI_UNDEF;
+ return METHOD_ENTRY_VISI(me);
+ }
+ return METHOD_VISI_UNDEF;
+}
+
/*
* call-seq:
- * mod.method_defined?(symbol) -> true or false
- * mod.method_defined?(string) -> true or false
+ * mod.method_defined?(symbol, inherit=true) -> true or false
+ * mod.method_defined?(string, inherit=true) -> true or false
*
* Returns +true+ if the named method is defined by
- * _mod_ (or its included modules and, if _mod_ is a class,
- * its ancestors). Public and protected methods are matched.
+ * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
+ * ancestors. Public and protected methods are matched.
* String arguments are converted to symbols.
*
* module A
@@ -1306,6 +1336,8 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
* A.method_defined? :method1 #=> true
* C.method_defined? "method1" #=> true
* C.method_defined? "method2" #=> true
+ * C.method_defined? "method2", true #=> true
+ * C.method_defined? "method2", false #=> false
* C.method_defined? "method3" #=> true
* C.method_defined? "protected_method1" #=> true
* C.method_defined? "method4" #=> false
@@ -1313,37 +1345,26 @@ rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
*/
static VALUE
-rb_mod_method_defined(VALUE mod, VALUE mid)
+rb_mod_method_defined(int argc, VALUE *argv, VALUE mod)
{
- ID id = rb_check_id(&mid);
- if (!id || !rb_method_boundp(mod, id, 1)) {
- return Qfalse;
- }
- return Qtrue;
-
+ rb_method_visibility_t visi = check_definition_visibility(mod, argc, argv);
+ return (visi == METHOD_VISI_PUBLIC || visi == METHOD_VISI_PROTECTED) ? Qtrue : Qfalse;
}
static VALUE
-check_definition(VALUE mod, VALUE mid, rb_method_visibility_t visi)
+check_definition(VALUE mod, int argc, VALUE *argv, rb_method_visibility_t visi)
{
- const rb_method_entry_t *me;
- ID id = rb_check_id(&mid);
- if (!id) return Qfalse;
- me = rb_method_entry_without_refinements(mod, id, NULL);
- if (me) {
- if (METHOD_ENTRY_VISI(me) == visi) return Qtrue;
- }
- return Qfalse;
+ return (check_definition_visibility(mod, argc, argv) == visi) ? Qtrue : Qfalse;
}
/*
* call-seq:
- * mod.public_method_defined?(symbol) -> true or false
- * mod.public_method_defined?(string) -> true or false
+ * mod.public_method_defined?(symbol, inherit=true) -> true or false
+ * mod.public_method_defined?(string, inherit=true) -> true or false
*
* Returns +true+ if the named public method is defined by
- * _mod_ (or its included modules and, if _mod_ is a class,
- * its ancestors).
+ * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
+ * ancestors.
* String arguments are converted to symbols.
*
* module A
@@ -1358,26 +1379,28 @@ check_definition(VALUE mod, VALUE mid, rb_method_visibility_t visi)
* def method3() end
* end
*
- * A.method_defined? :method1 #=> true
- * C.public_method_defined? "method1" #=> true
- * C.public_method_defined? "method2" #=> false
- * C.method_defined? "method2" #=> true
+ * A.method_defined? :method1 #=> true
+ * C.public_method_defined? "method1" #=> true
+ * C.public_method_defined? "method1", true #=> true
+ * C.public_method_defined? "method1", false #=> true
+ * C.public_method_defined? "method2" #=> false
+ * C.method_defined? "method2" #=> true
*/
static VALUE
-rb_mod_public_method_defined(VALUE mod, VALUE mid)
+rb_mod_public_method_defined(int argc, VALUE *argv, VALUE mod)
{
- return check_definition(mod, mid, METHOD_VISI_PUBLIC);
+ return check_definition(mod, argc, argv, METHOD_VISI_PUBLIC);
}
/*
* call-seq:
- * mod.private_method_defined?(symbol) -> true or false
- * mod.private_method_defined?(string) -> true or false
+ * mod.private_method_defined?(symbol, inherit=true) -> true or false
+ * mod.private_method_defined?(string, inherit=true) -> true or false
*
* Returns +true+ if the named private method is defined by
- * _ mod_ (or its included modules and, if _mod_ is a class,
- * its ancestors).
+ * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
+ * ancestors.
* String arguments are converted to symbols.
*
* module A
@@ -1392,26 +1415,28 @@ rb_mod_public_method_defined(VALUE mod, VALUE mid)
* def method3() end
* end
*
- * A.method_defined? :method1 #=> true
- * C.private_method_defined? "method1" #=> false
- * C.private_method_defined? "method2" #=> true
- * C.method_defined? "method2" #=> false
+ * A.method_defined? :method1 #=> true
+ * C.private_method_defined? "method1" #=> false
+ * C.private_method_defined? "method2" #=> true
+ * C.private_method_defined? "method2", true #=> true
+ * C.private_method_defined? "method2", false #=> false
+ * C.method_defined? "method2" #=> false
*/
static VALUE
-rb_mod_private_method_defined(VALUE mod, VALUE mid)
+rb_mod_private_method_defined(int argc, VALUE *argv, VALUE mod)
{
- return check_definition(mod, mid, METHOD_VISI_PRIVATE);
+ return check_definition(mod, argc, argv, METHOD_VISI_PRIVATE);
}
/*
* call-seq:
- * mod.protected_method_defined?(symbol) -> true or false
- * mod.protected_method_defined?(string) -> true or false
+ * mod.protected_method_defined?(symbol, inherit=true) -> true or false
+ * mod.protected_method_defined?(string, inherit=true) -> true or false
*
* Returns +true+ if the named protected method is defined
- * by _mod_ (or its included modules and, if _mod_ is a
- * class, its ancestors).
+ * _mod_. If _inherit_ is set, the lookup will also search _mod_'s
+ * ancestors.
* String arguments are converted to symbols.
*
* module A
@@ -1426,16 +1451,18 @@ rb_mod_private_method_defined(VALUE mod, VALUE mid)
* def method3() end
* end
*
- * A.method_defined? :method1 #=> true
- * C.protected_method_defined? "method1" #=> false
- * C.protected_method_defined? "method2" #=> true
- * C.method_defined? "method2" #=> true
+ * A.method_defined? :method1 #=> true
+ * C.protected_method_defined? "method1" #=> false
+ * C.protected_method_defined? "method2" #=> true
+ * C.protected_method_defined? "method2", true #=> true
+ * C.protected_method_defined? "method2", false #=> false
+ * C.method_defined? "method2" #=> true
*/
static VALUE
-rb_mod_protected_method_defined(VALUE mod, VALUE mid)
+rb_mod_protected_method_defined(int argc, VALUE *argv, VALUE mod)
{
- return check_definition(mod, mid, METHOD_VISI_PROTECTED);
+ return check_definition(mod, argc, argv, METHOD_VISI_PROTECTED);
}
int
@@ -2121,10 +2148,10 @@ Init_eval_method(void)
rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
- rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
- rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
- rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
- rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
+ rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, -1);
+ rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, -1);
+ rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, -1);
+ rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, -1);
rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);