ruby-changes:52135
From: usa <ko1@a...>
Date: Mon, 13 Aug 2018 22:48:33 +0900 (JST)
Subject: [ruby-changes:52135] usa:r64343 (trunk): Fix problem about notimplemented case
usa 2018-08-13 22:48:27 +0900 (Mon, 13 Aug 2018) New Revision: 64343 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64343 Log: Fix problem about notimplemented case Re-revert r64340, and take care about notimplemented case. Modified files: trunk/test/ruby/test_module.rb trunk/vm_method.c Index: vm_method.c =================================================================== --- vm_method.c (revision 64342) +++ vm_method.c (revision 64343) @@ -1278,14 +1278,44 @@ rb_mod_undef_method(int argc, VALUE *arg https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1278 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 *arg https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1336 * 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 *arg https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1345 */ 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, r https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1379 * 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, https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1415 * 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, https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1451 * 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) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L2148 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); Index: test/ruby/test_module.rb =================================================================== --- test/ruby/test_module.rb (revision 64342) +++ test/ruby/test_module.rb (revision 64343) @@ -468,17 +468,42 @@ class TestModule < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L468 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) - - 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 !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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L999 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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L1008 protected :bar private :baz end - - assert_equal(true, c.public_method_defined?(:foo)) - assert_equal(false, c.public_method_defined?(:bar)) - assert_equal(false, c.public_method_defined?(:baz)) - - # 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(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(false, c.protected_method_defined?("foo")) - assert_equal(true, c.protected_method_defined?("bar")) - assert_equal(false, c.protected_method_defined?("baz")) - - 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(false, c.private_method_defined?("foo")) - assert_equal(false, c.private_method_defined?("bar")) - assert_equal(true, c.private_method_defined?("baz")) + 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) + + [[], [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] + + 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(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(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(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(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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/