web-dev-qa-db-fra.com

Étant donné une classe, voir si instance a method (Ruby)

Je sais en Ruby que je peux utiliser respond_to? pour vérifier si un objet a une certaine méthode.

Mais, étant donné la classe, comment puis-je vérifier si l'instance a une certaine méthode?

c'est-à-dire quelque chose comme

Foo.new.respond_to?(:bar)

Mais j'estime qu'il doit y avoir un meilleur moyen que d'instancier une nouvelle instance.

201
user94154

Je ne sais pas pourquoi tout le monde suggère que vous devriez utiliser instance_methods et include? lorsque method_defined? fait le travail.

class Test
  def hello; end
end

Test.method_defined? :hello #=> true
336
horseyguy

Vous pouvez utiliser method_defined? comme suit:

String.method_defined? :upcase # => true

Beaucoup plus facile, portable et efficace que le instance_methods.include? que tout le monde semble suggérer.

N'oubliez pas 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

En réalité, cela ne fonctionne pas pour les objets et les classes.

Cela fait:

class TestClass
  def methodName
  end
end

Donc, avec la réponse donnée, cela fonctionne:

TestClass.method_defined? :methodName # => TRUE

Mais cela ne marche PAS:

t = TestClass.new
t.method_defined? : methodName  # => ERROR!

Donc, je l'utilise pour les classes et les objets:

Des classes:

TestClass.methods.include? 'methodName'  # => TRUE

Objets:

t = TestClass.new
t.methods.include? 'methodName'  # => TRUE
22
Alex V

La réponse à " Étant donné une classe, voir si instance a method (Ruby) " est préférable. Apparemment, Ruby a cette fonction intégrée et je l’ai ratée. 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 . En Ruby 1.8, le premier répertorie tous les noms de méthodes d'instance dans un tableau de chaînes et le second le limite aux méthodes publiques. Le second comportement correspond à ce que vous voudriez probablement, puisque respond_to? se limite également aux méthodes publiques par défaut.

Foo.public_instance_methods.include?('bar')

En Ruby 1.9, cependant, ces méthodes renvoient des tableaux de symboles.

Foo.public_instance_methods.include?(:bar)

Si vous envisagez de le faire souvent, vous voudrez peut-être étendre Module pour inclure une méthode de raccourci. (Cela peut sembler étrange d’attribuer ceci à Module au lieu de Class, mais puisque c’est là que vivent les méthodes instance_methods, il est préférable de rester en ligne avec ce modèle.)

class Module
  def instance_respond_to?(method_name)
    public_instance_methods.include?(method_name)
  end
end

Si vous souhaitez prendre en charge à la fois Ruby 1.8 et Ruby 1.9, vous pouvez également ajouter la logique permettant de rechercher des chaînes et des symboles.

8
Matchu

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

Foo.instance_methods.include? 'bar'
3
dbyrne

Essayez Foo.instance_methods.include? :bar

Si vous vérifiez si un objet peut répondre à une série de méthodes, vous pouvez procéder comme suit:

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 chose.les méthodes incluent toutes les méthodes que vous recherchez, ça va être des méthodes égales. Par exemple:

[1,2] & [1,2,3,4,5]
==> [1,2]

alors 

[1,2] & [1,2,3,4,5] == [1,2]
==> true

Dans cette situation, vous voudriez utiliser des symboles, car lorsque vous appelez. Méthodes, il retourne un tableau de symboles et si vous utilisez ["my", "methods"], il retourne false. 

2
TalkativeTree

Je pense qu'il y a quelque chose qui ne va pas avec method_defined? dans Rails. Cela peut être incohérent ou quelque chose comme ça, donc si vous utilisez Rails, il est préférable d’utiliser quelque chose de attribute_method?(attribute) .

" le test de method_defined? sur les classes ActiveRecord ne fonctionne pas avant une instanciation " est une question sur l'incohérence.

2
NoDisplayName
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 aide!

1

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

1
yxhuvud

Dans mon cas de travail avec Ruby 2.5.3, les phrases suivantes ont parfaitement fonctionné:

value = "hello world"

value.methods.include? :upcase

Il retournera une valeur booléenne true ou false.

0
Manuel Lazo