2009-08-25 10 views
32

J'ai une classe qui a un certain nombre de modules qui sont mélangés avec elle en fonction de certains critères d'exécution.Comment savoir quels modules ont été mélangés dans une classe?

Je veux être capable d'obtenir une liste des modules qui ont été mélangés dans cette classe. Comment peux-tu faire ça?

MISE À JOUR

Alors, quand je dis classe je voulais dire objet tel qu'il est l'objet qui est en cours d'extension à l'exécution en utilisant:

obj.extend(MyModule) 

obj.included_modules et obj.ancestors n'existent pas vous ne peut pas obtenir les modules qui ont été mélangés à partir de là.

Répondre

38

Essayez:

MyClass.ancestors.select {|o| o.class == Module } 

par exemple:

>> Array.ancestors.select {|o| o.class == Module} 
=> [Enumerable, Kernel] 

MISE À JOUR

Pour obtenir les modules mixtes dans une instance d'objet lors de l'exécution dont vous aurez besoin pour récupérer les eigenclass de l'instance . Il n'y a aucun moyen propre à faire en Ruby, mais un langage assez commun est le suivant:

(class << obj; self; end).included_modules 

Si vous vous trouvez en utilisant ce lot, vous pouvez le faire généralement disponibles:

module Kernel 
    def eigenclass 
    class << self 
     self 
    end 
    end 
end 

et la solution est alors:

obj.eigenclass.included_modules 
+10

Il existe une méthode prête pour cela, appelé 'included_modules '. – Swanand

+0

Donc il y a. Merci pour le conseil. –

+0

Il s'avère que j'ai sauté le pistolet. J'ai soulevé la question avec plus de détails. –

39

Cela pourrait être une meilleure idée:

MyClass.included_modules 
irb(main):001:0> Array.included_modules 
=> [Enumerable, Kernel] 
21

Si vous cherchez la liste complète, Swanand's answer est votre meilleur pari.

Si, d'autre part, vous voulez vérifier si une classe comprend un module particulier , l'opérateur < est votre ami:

module Foo 
end 

class Bar 
    include Foo 
end 

Bar < Foo 
# => true 
3

Seules les classes peuvent méthodes de l'histoire et quand vous ajoutez une méthode à une instance que vous êtes en train de l'ajouter à la métaclasse des objets. Le module que vous recherchez sera dans cette liste d'ancêtres de métaclasses.

module TestModule; end 

obj = "test" 
obj.extend(TestModule) 

class Object 
    def metaclass 
    class << self; self; end 
    end 
end 

obj.metaclass.ancestors 
# => [TestModule, String, Comparable, Object, Kernel, BasicObject] 
6

Voici un autre moyen efficace pour voir si un module a été inclus ou prolongée par une classe.

Comme d'autres l'ont mentionné, vous pouvez déterminer si un module est inclus dans une classe en vérifiant la méthode de classe included_modules qui existe sur toutes les classes de ruby.

Donc, si vous aviez une classe nommée MyClass et que vous vouliez voir si elle inclus le module Comparable que vous pourriez faire quelque chose comme ceci:

# will return true if MyClass.include(Comparable) 
MyClass.included_modules.include?(Comparable) 

Si vous voulez savoir si votre classe a étendu le module ActiveRecord::Querying, comme toutes les classes de modèles de rails font, vous pouvez réellement utiliser:

# will return true if MyClass.extend(ActiveRecord::Querying) 
MyClass.kind_of?(ActiveRecord::Querying) 

Pourquoi cela fonctionne-t-il? Pour citer le livre Eloquent Ruby, by Russ Olsen:

Lorsque vous mélangez un module dans une classe, Ruby rebranche la hiérarchie des classes un peu, l'insertion du module comme une sorte de pseudo superclasse de la classe.

Cela signifie aussi qu'une autre façon de déterminer si un module a été inclus dans votre classe est de faire quelque chose comme ça (même si je préfère encore la méthode included_modules):

# will also return true if MyClass.include(Comparable) 
MyClass.new.kind_of?(Comparable) 
17
obj.singleton_class.included_modules 

Et si vous voulez vérifier si le module inclus:

obj.singleton_class.include? MyModule 
+0

AFAIK, c'est certainement maintenant le moyen préféré de tester cela. – xiy

2

I comme @ solution de AlexParamonov, mais j'ai joué et a trouvé que cela fonctionne tout aussi bien:

obj.class.include? MyModule

MyClass.include? MyModule

http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-include-3F

+0

Sauf si vous avez modifié l'objet singleton. Par exemple: 'a = []; a.extend (MyAwesomeModule) '. Dans ce cas, 'a.class.included_modules' n'inclura pas' MyAwesomeModule', mais 'a.singleton_class.included_modules' – AlexParamonov

Questions connexes