Der Code, den Sie gebucht haben, funktioniert gut für die Überprüfung, ob die Methode definiert ist oder nicht. Module#method_defined?
ist genau die richtige Wahl. (Es gibt auch die Varianten Module#public_method_defined?
, Module#protected_method_defined?
und Module#private_method_defined?
.) Das Problem ist mit Ihrem Anruf zu def_method
, die nicht existiert. (Es heißt Module#define_method
).
Dies wirkt wie ein Zauber:
class C1
define_method(:hello) do
puts 'Hi Everyone'
end unless method_defined? :hello
end
Da Sie bereits den Namen im Voraus wissen, und verwenden Sie keine Schließung, gibt es keine Notwendigkeit Module#define_method
zu verwenden, können Sie nur verwenden, um das def
Schlüsselwort stattdessen:
class C1
def hello
puts 'Hi Everyone'
end unless method_defined? :hello
end
Oder habe ich Ihre Frage missverstanden und Sie sind besorgt über Vererbung? In diesem Fall ist Module#method_defined?
nicht die richtige Wahl, da es die gesamte Vererbungskette durchläuft. In diesem Fall müssen Sie Module#instance_methods
oder einen seiner Cousins Module#public_instance_methods
, Module#protected_instance_methods
oder Module#private_instance_methods
verwenden, die ein optionales Argument verwenden, das ihnen sagt, ob Methoden aus Superklassen/Mixins eingeschlossen werden sollen oder nicht. (Beachten Sie, dass die Dokumentation falsch ist: Wenn Sie keine Argumente übergeben, es wird umfassen alle geerbten Methoden.)
class C1
unless instance_methods(false).include? :hello
def hello
puts 'Hi Everyone'
end
end
end
Hier ist eine kleine Test-Suite, die zeigt, dass mein Vorschlag funktioniert:
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
Der Test besteht in 1.9.2, aber "test_that_the_method_cannot_be_redefined" und "test_that_the_method_does_exist_after_it_has_been_defined" schlägt unter Ruby 1.8.7 fehl. – mrm