2009-08-25 7 views
32

Tengo una clase que tiene varios módulos que se mezclan con ella en función de algunos criterios de tiempo de ejecución.¿Cómo puedo saber qué módulos se han mezclado en una clase?

Quiero ser capaz de obtener una lista de los módulos que se han mezclado en esta clase. Como puedes hacer eso?

ACTUALIZACIÓN

Así que cuando dije clase I significaba objeto tal como es el objeto que se está extendiendo en tiempo de ejecución usando:

obj.extend(MyModule) 

obj.included_modules y obj.ancestors no existen por lo que no puede obtener los módulos que se han mezclado desde allí.

Respuesta

38

Probar:

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

por ejemplo:

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

ACTUALIZACIÓN

Para obtener los módulos mezclados en una instancia de objeto en tiempo de ejecución que necesita para recuperar los eigenclass de la instancia . No hay manera limpia de hacer esto en Ruby, pero un lenguaje bastante común es la siguiente:

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

Si usted se encuentra usando mucho esto, puede darle difusión:

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

y la solución es entonces:

obj.eigenclass.included_modules 
+10

hay un método ya preparado para eso, llamados 'included_modules '. – Swanand

+0

Así que hay. Gracias por el consejo. –

+0

Resulta que salté el arma. He descargado la pregunta con más detalles. –

39

Esta podría ser una mejor idea:

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

Si está buscando la lista completa, Swanand's answer es su mejor opción.

Si, por el contrario, desea comprobar si una clase incluye un módulo en particular, el operador < es su amigo:

module Foo 
end 

class Bar 
    include Foo 
end 

Bar < Foo 
# => true 
3

Sólo las clases pueden métodos de la historia y cuando se agrega un método a una instancia que realmente está agregando a la metaclass de objetos. El módulo que está buscando estará en esta lista de antepasados ​​de metaclase.

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

Aquí es otra manera eficaz de saber si un módulo ha sido incluido o extendieron por una clase.

Como han mencionado otros, puede determinar si un módulo está incluido en una clase al marcar el método de clase included_modules que existe en todas las clases en ruby.

Así que si había una clase llamada MyClass y que quería ver si incluido el módulo Comparable se podría hacer algo como esto:

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

Si desea determinar si su clase tiene extendieron el módulo ActiveRecord::Querying, como todas las clases de rieles modelo hacen, en realidad se puede utilizar esto:

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

¿Por qué funciona esto? Para citar el libro Eloquent Ruby, by Russ Olsen:

Cuando se mezcla un módulo en una clase, Ruby rewires la jerarquía de clases un poco, insertando el módulo como una especie de seudo superclase de la clase.

Esto significa también que otra manera de determinar si un módulo ha sido incluido en su clase es hacer algo como esto (aunque yo prefiero el método included_modules):

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

Y si desea verificar si el módulo está incluido:

obj.singleton_class.include? MyModule 
+0

AFAIK, esta es definitivamente la forma preferida de probar esto. – xiy

2

I como solución de @ AlexParamonov, pero jugado un poco y descubrí que esto funciona igual de bien:

obj.class.include? MyModule

MyClass.include? MyModule

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

+0

A menos que haya modificado el objeto singleton. Por ejemplo: 'a = []; a.extend (MyAwesomeModule) '. En este caso 'a.class.included_modules' no incluirá' MyAwesomeModule', pero 'a.singleton_class.included_modules' se – AlexParamonov

Cuestiones relacionadas