如何判断某个方法是否已在类中定义? [英] How to judge whether a method has defined in a class?

查看:224
本文介绍了如何判断某个方法是否已在类中定义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

class C1
  unless method_defined? :hello  # Certainly, it's not correct. I am asking to find something to do this work.
    def_method(:hello) do
      puts 'Hi Everyone'
    end
  end
end

那么,如何判断方法是否已定义?

So, how to judge whether a method has defined or not?

推荐答案

您发布的代码可以很好地检查方法是否已定义. Module#method_defined? 确实是正确的选择. (还有变体 Module#public_method_defined? Module#protected_method_defined? Module#define_method ).

The code you posted works just fine for checking whether the method is defined or not. Module#method_defined? is exactly the right choice. (There's also the variants Module#public_method_defined?, Module#protected_method_defined? and Module#private_method_defined?.) The problem is with your call to def_method, which doesn't exist. (It's called Module#define_method).

这就像一种魅力:

class C1      
  define_method(:hello) do
    puts 'Hi Everyone'
  end unless method_defined? :hello
end

但是,由于您已经预先知道名称并且不使用任何闭包,因此无需使用Module#define_method,您可以只使用def关键字:

However, since you already know the name in advance and don't use any closure, there is no need to use Module#define_method, you can just use the def keyword instead:

class C1
  def hello
    puts 'Hi Everyone'
  end unless method_defined? :hello
end

还是我误解了您的问题,而您担心继承?在这种情况下,Module#method_defined?不是正确的选择,因为它遍历了整个继承链.在这种情况下,您将必须使用 Module#instance_methods 或它的一个堂兄 Module#public_instance_methods

Or have I misunderstood your question and you are worried about inheritance? In that case, Module#method_defined? is not the right choice, because it walks the entire inheritance chain. In that case, you will have to use Module#instance_methods or one of its cousins Module#public_instance_methods, Module#protected_instance_methods or Module#private_instance_methods, which take an optional argument telling them whether to include methods from superclasses / mixins or not. (Note that the documentation is wrong: if you pass no arguments, it will include all the inherited methods.)

class C1
  unless instance_methods(false).include? :hello
    def hello
      puts 'Hi Everyone'
    end
  end
end

这里有一个小测试套件,表明我的建议有效:

Here's a little test suite that shows that my suggestion works:

require 'test/unit'
class TestDefineMethodConditionally < Test::Unit::TestCase
  def setup
    @c1 = Class.new do
      def self.add_hello(who)
        define_method(:hello) do
          who
        end unless method_defined? :hello
      end
    end

    @o = @c1.new
  end

  def test_that_the_method_doesnt_exist_when_it_hasnt_been_defined_yet
    assert !@c1.method_defined?(:hello)
    assert !@c1.instance_methods.include?(:hello)
    assert !@o.methods.include?(:hello)
    assert !@o.respond_to?(:hello)
    assert_raise(NoMethodError) { @o.hello }
  end

  def test_that_the_method_does_exist_after_it_has_been_defined
    @c1.add_hello 'one'

    assert @c1.method_defined?(:hello)
    assert @c1.instance_methods.include?(:hello)
    assert @o.methods.include?(:hello)
    assert_respond_to @o, :hello
    assert_nothing_raised { @o.hello }
    assert_equal 'one', @o.hello
  end

  def test_that_the_method_cannot_be_redefined
    @c1.add_hello 'one'

    assert @c1.method_defined?(:hello)
    assert @c1.instance_methods.include?(:hello)
    assert @o.methods.include?(:hello)
    assert_respond_to @o, :hello
    assert_nothing_raised { @o.hello }
    assert_equal 'one', @o.hello

    @c1.add_hello 'two'

    assert @c1.method_defined?(:hello)
    assert @c1.instance_methods.include?(:hello)
    assert @o.methods.include?(:hello)
    assert_respond_to @o, :hello
    assert_nothing_raised { @o.hello }
    assert_equal 'one', @o.hello, 'it should *still* respond with "one"!'
  end
end

这篇关于如何判断某个方法是否已在类中定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆