如何判断类中是否定义了某个方法?

发布于 2024-09-13 03:25:51 字数 240 浏览 6 评论 0原文

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜雨飘雪 2024-09-20 03:25:51

您发布的代码可以很好地检查该方法是否已定义。 Module#method_define? 正是正确的选择。 (还有变体 Module#public_method_define?< /a>, Module#protected_method_define?Module#private_method_define?.) 问题在于您对 def_method 的调用,该调用不存在。 (它被称为 Module#define_method )。

这就像一个魅力:

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

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

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

或者我误解了你的问题并且你担心继承?在这种情况下,Module#method_define? 不是正确的选择,因为它遍历整个继承链。在这种情况下,您必须使用 Module#instance_methods或其同类 Module#public_instance_methods 之一Module#protected_instance_methodsModule#private_instance_methods ,它接受一个可选参数,告诉他们是否包含超类/混合中的方法。 (请注意,文档是错误的:如果您不传递任何参数,它包含所有继承的方法。)

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

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

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 [email protected]_defined?(:hello)
    assert [email protected]_methods.include?(:hello)
    assert [email protected]?(:hello)
    assert [email protected]_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

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).

This works like a charm:

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

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

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 [email protected]_defined?(:hello)
    assert [email protected]_methods.include?(:hello)
    assert [email protected]?(:hello)
    assert [email protected]_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
痴情换悲伤 2024-09-20 03:25:51

查看 Ruby 对象类。它有一个 methods 函数来获取方法列表,并有一个 respond_to? 来检查特定方法。所以你想要这样的代码:

class C1
  def add_hello
    unless self.respond_to? "hello"
      def hello
        puts 'Hi Everyone'
      end
    end  
  end
end

cone.hello      #This would fail
cone.add_hello  
cone.hello      #This would work

Look at the Ruby Object class. It has a methods function to get an list of methods and a respond_to? to check for a specific method. So you want code like this:

class C1
  def add_hello
    unless self.respond_to? "hello"
      def hello
        puts 'Hi Everyone'
      end
    end  
  end
end

cone.hello      #This would fail
cone.add_hello  
cone.hello      #This would work
独闯女儿国 2024-09-20 03:25:51

Object 类具有方法“methods”: docs

 class Klass
   def kMethod()
   end
 end
 k = Klass.new
 k.methods[0..9]    #=> ["kMethod", "freeze", "nil?", "is_a?",
                    #    "class", "instance_variable_set",
                    #    "methods", "extend", "__send__", "instance_eval"]
 k.methods.length   #=> 42

The Object class has the method "methods": docs

 class Klass
   def kMethod()
   end
 end
 k = Klass.new
 k.methods[0..9]    #=> ["kMethod", "freeze", "nil?", "is_a?",
                    #    "class", "instance_variable_set",
                    #    "methods", "extend", "__send__", "instance_eval"]
 k.methods.length   #=> 42
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文