Avec une classe, voir si l'instance a une méthode (Ruby)
Je sais dans Ruby que je peux utiliser respond_to?
pour vérifier si un objet a une certaine méthode.
Mais, compte tenu de la classe, comment puis-je vérifier si l'instance a une certaine méthode?
I. e, quelque chose comme
Foo.new.respond_to?(:bar)
mais je pense qu'il doit y avoir un meilleur moyen que d'instancier une nouvelle instance.
10 réponses
Je ne sais pas pourquoi tout le monde suggère que vous devriez utiliser instance_methods
et include?
quand method_defined?
fait le travail.
class Test
def hello; end
end
Test.method_defined? :hello #=> true
vous pouvez utiliser method_defined?
comme suit:
String.method_defined? :upcase # => true
beaucoup plus facile, portable et efficace que le instance_methods.include?
tout le monde semble suggérer.
gardez à l'esprit que vous ne saurez pas si une classe répond dynamiquement à certains appels avec method_missing
, par exemple en redéfinissant respond_to?
, ou depuis Ruby 1.9.2 en définissant respond_to_missing?
.
en fait, cela ne fonctionne pas à la fois pour les objets et les Classes.
Ce n':
class TestClass
def methodName
end
end
ainsi avec la réponse donnée, cela fonctionne:
TestClass.method_defined? :methodName # => TRUE
mais cela ne fonctionne pas:
t = TestClass.new
t.method_defined? : methodName # => ERROR!
donc je l'utilise pour les classes et les objets:
Classes:
TestClass.methods.include? 'methodName' # => TRUE
les Objets:
t = TestClass.new
t.methods.include? 'methodName' # => TRUE
la réponse à " étant donné une classe, voir si l'instance a la méthode (Ruby) " est mieux. Apparemment, Ruby a cette fonction, et j'ai un peu raté. Ma réponse est laissée pour référence, peu importe.
les classes Ruby répondent aux méthodes instance_methods
et public_instance_methods
. Dans Ruby 1.8, le premier liste tous les noms de méthode d'instance dans un tableau de chaînes, et le second le restreint au public méthode. Le second comportement est ce que vous souhaitez probablement, puisque respond_to?
se limite aux méthodes publiques par défaut, aussi bien.
Foo.public_instance_methods.include?('bar')
En Ruby 1.9, cependant, ces méthodes retournent des tableaux de symboles.
Foo.public_instance_methods.include?(:bar)
si vous prévoyez de faire cela souvent, vous pourriez vouloir étendre Module
pour inclure une méthode de raccourci. (Il peut sembler étrange d'attribuer cette Module
au lieu de Class
, mais puisque c'est là que l' instance_methods
méthodes live, il est préférable de garder en ligne avec ce modèle.)
class Module
def instance_respond_to?(method_name)
public_instance_methods.include?(method_name)
end
end
si vous voulez prendre en charge à la fois Ruby 1.8 et Ruby 1.9, ce serait un endroit pratique pour ajouter la logique pour rechercher à la fois des chaînes et des symboles, ainsi.
pas sûr que ce soit la meilleure façon, mais vous pouvez toujours faire ceci:
Foo.instance_methods.include? 'bar'
je pense qu'il y a quelque chose qui ne va pas avec method_defined?
dans les Rails. Il peut être incohérent ou quelque chose, donc si vous utilisez des Rails, il est préférable d'utiliser quelque chose de attribute_method?(attribute)
.
" dépistage method_defined? sur ActiveRecord, les classes ne fonctionnent pas jusqu'à ce qu'une instanciation " soit une question d'incohérence.
si vous vérifiez si un objet peut répondre à une série de méthodes, vous pouvez faire quelque chose comme:
methods = [:valid?, :chase, :test]
def has_methods?(something, methods)
methods & something.methods == methods
end
le methods & something.methods
joindra les deux tableaux sur leurs éléments communs/correspondants. quelque.méthodes comprend toutes les méthodes que vous vérifiez, il sera égal méthodes. Par exemple:
[1,2] & [1,2,3,4,5]
==> [1,2]
donc
[1,2] & [1,2,3,4,5] == [1,2]
==> true
dans cette situation, vous voulez utiliser des symboles, parce que quand vous appelez .méthodes, il retourne un tableau de symboles et si vous avez utilisé ["my", "methods"]
, il retournerait false.
Essayer Foo.instance_methods.include? :bar
klass.instance_methods.include :method_name
ou "method_name"
, selon la version de Ruby, je pense.
class Foo
def self.fclass_method
end
def finstance_method
end
end
foo_obj = Foo.new
foo_obj.class.methods(false)
=> [:fclass_method]
foo_obj.class.instance_methods(false)
=> [:fclass_method]
J'espère que cela vous aidera!