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.

195
demandé sur Arslan Ali 2010-07-22 00:04:46

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
319
répondu horseyguy 2013-11-09 14:56:46

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? .

43
répondu Marc-André Lafortune 2010-07-21 23:27:22

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
21
répondu Alex V 2013-10-10 20:34:38

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.

7
répondu Matchu 2017-05-23 12:34:50

pas sûr que ce soit la meilleure façon, mais vous pouvez toujours faire ceci:

Foo.instance_methods.include? 'bar'
2
répondu dbyrne 2010-07-21 20:10:23

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.

2
répondu NoDisplayName 2017-05-23 12:10:41

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.

2
répondu TalkativeTree 2015-08-06 21:41:28

Essayer Foo.instance_methods.include? :bar

2
répondu imightbeinatree at Cloudspace 2015-08-06 21:50:40

klass.instance_methods.include :method_name ou "method_name" , selon la version de Ruby, je pense.

1
répondu yxhuvud 2015-08-09 00:49:37
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!

1
répondu Rajeev Kannav Sharma 2015-08-09 00:50:40