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
Так, как судить, определил ли метод или нет?
Опубликованный вами код отлично подходит для проверки того, определен ли метод или нет. 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
У класса 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
Посмотрите на класс объекта 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