Le code affiché fonctionne très bien pour vérifier si la méthode est définie ou non. Module#method_defined?
est exactement le bon choix. (Il ya aussi les variantes Module#public_method_defined?
, Module#protected_method_defined?
et Module#private_method_defined?
.) Le problème est avec votre appel à def_method
, qui n'existe pas. (Il s'appelle Module#define_method
).
Cela fonctionne comme un charme:
class C1
define_method(:hello) do
puts 'Hi Everyone'
end unless method_defined? :hello
end
Cependant, puisque vous connaissez déjà le nom à l'avance et ne pas utiliser toute fermeture, il n'y a pas besoin d'utiliser Module#define_method
, vous pouvez simplement utiliser le mot-clé def
à la place:
class C1
def hello
puts 'Hi Everyone'
end unless method_defined? :hello
end
Ou ai-je mal compris votre question et vous êtes inquiet pour l'héritage? Dans ce cas, Module#method_defined?
n'est pas le bon choix, car il parcourt toute la chaîne d'héritage. Dans ce cas, vous devrez utiliser Module#instance_methods
ou l'un de ses cousins Module#public_instance_methods
, Module#protected_instance_methods
ou Module#private_instance_methods
, qui prennent un argument optionnel leur disant d'inclure ou non des méthodes de superclasses/mixins. (Notez que la documentation est erronée: si vous passez aucun argument, il sera inclure toutes les méthodes héritées.)
class C1
unless instance_methods(false).include? :hello
def hello
puts 'Hi Everyone'
end
end
end
Voici une petite suite de test qui montre que ma suggestion fonctionne:
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
Le test passe en 1.9.2 mais 'test_that_the_method_cannot_be_redefined' et' test_that_the_method_does_exist_after_it_has_been_defined' échouent sous ruby 1.8.7. – mrm