Как судить, определил ли метод в классе?

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

Так, как судить, определил ли метод или нет?

8
задан Benjamin 3 November 2013 в 12:58
поделиться

3 ответа

Опубликованный вами код отлично подходит для проверки того, определен ли метод или нет. Module # method_defined? - это правильный выбор. (Также есть варианты Module # public_method_defined? , Module # protected_method_defined? и Module # private_method_defined? .) Проблема связана с вашим вызовом 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_defined? не является правильным выбором, потому что он проходит всю цепочку наследования. В этом случае вам нужно будет использовать Module # instance_methods или один из его кузенов Module # public_instance_methods , Module # protected_instance_methods или Module # 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 !@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
17
ответ дан 5 December 2019 в 08:22
поделиться

У класса 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
1
ответ дан 5 December 2019 в 08:22
поделиться

Посмотрите на класс объекта Ruby . В нем есть функция methods для получения списка методов и response_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
2
ответ дан 5 December 2019 в 08:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: