Puedo ascender fácilmente la jerarquía de clases en Ruby:
String.ancestors # [String, Enumerable, Comparable, Object, Kernel]
Enumerable.ancestors # [Enumerable]
Comparable.ancestors # [Comparable]
Object.ancestors # [Object, Kernel]
Kernel.ancestors # [Kernel]
¿Hay alguna manera de descender la jerarquía también? Me gustaria hacer esto
Animal.descendants # [Dog, Cat, Human, ...]
Dog.descendants # [Labrador, GreatDane, Airedale, ...]
Enumerable.descendants # [String, Array, ...]
Pero no parece haber un descendants
método.
(Esta pregunta surge porque quiero encontrar todos los modelos en una aplicación Rails que descienden de una clase base y enumerarlos; tengo un controlador que puede funcionar con cualquier modelo y me gustaría poder agregar nuevos modelos sin tener que modificar el controlador.)
singleton_class
en lugar deClass
hacerlo mucho más rápido (ver fuente en apidock.com/rails/Class/descendants )ObjectSpace
no la tendrá.Object
yBasicObject
?, curiosidad por saber lo que muestranp ObjectSpace.each_object(Class)
imprimirá todas las clases. También puede obtener los descendientes de cualquier clase que desee sustituyendo su nombreself
en la línea de código del método.Si usa Rails> = 3, tiene dos opciones en su lugar. Úselo
.descendants
si desea más de un nivel de profundidad de clases para niños, o úselo.subclasses
para el primer nivel de clases para niños.Ejemplo:
fuente
Ruby 1.9 (o 1.8.7) con ingeniosos iteradores encadenados:
Ruby pre-1.8.7:
Úselo así:
fuente
ObjectSpace.each_object(::Class)
: esto mantendrá el código funcionando cuando tenga un YourModule :: Class definido.Reemplazar el método de clase denominado heredado . Este método pasaría a la subclase cuando se crea, lo que puede rastrear.
fuente
Alternativamente (actualizado para ruby 1.9+):
Forma compatible con Ruby 1.8:
Tenga en cuenta que esto no funcionará para los módulos. Además, YourRootClass se incluirá en la respuesta. Puede usar Array # u otra forma de eliminarlo.
fuente
ObjectSpace.each_object(class<<MyClass;self;end) {|it| puts it}
class<<some_obj;self;end
devuelve el singleton_class de un objeto. En 1.9+ puedes usarsome_obj.singleton_class
en su lugar (actualicé mi respuesta para reflejar eso). Cada objeto es una instancia de su singleton_class, que también se aplica a las clases. Dado que each_object (SomeClass) devuelve todas las instancias de SomeClass, y SomeClass es una instancia de SomeClass.singleton_class, each_object (SomeClass.singleton_class) devolverá SomeClass y todas las subclases.Aunque el uso de ObjectSpace funciona, el método de clase heredado parece ser más adecuado aquí heredado (subclase) documentación de Ruby
El espacio de objetos es esencialmente una forma de acceder a cualquier cosa y a todo lo que actualmente usa memoria asignada, por lo que iterar sobre cada uno de sus elementos para verificar si es una subclase de la clase Animal no es ideal.
En el siguiente código, el método de clase Animal heredado implementa una devolución de llamada que agregará cualquier subclase recién creada a su matriz de descendientes.
fuente
Sé que está preguntando cómo hacer esto en herencia, pero puede lograr esto directamente en Ruby espaciando el nombre de la clase (
Class
oModule
)De esta manera, es mucho más rápido que compararlo con cada clase
ObjectSpace
como lo proponen otras soluciones.Si realmente necesita esto en una herencia, puede hacer algo como esto:
puntos de referencia aquí: http://www.eq8.eu/blogs/13-ruby-ancestors-descendants-and-other-annoying-relatives
actualizar
al final todo lo que tienes que hacer es esto
gracias @saturnflyer por su sugerencia
fuente
(Rails <= 3.0) Alternativamente, podría usar ActiveSupport :: DescendantsTracker para hacer la escritura. De la fuente:
Dado que está bien modularizado, puede simplemente 'seleccionar' ese módulo en particular para su aplicación Ruby.
fuente
Ruby Facets tiene descendientes de clase #,
También es compatible con un parámetro de distancia generacional.
fuente
Una versión simple que proporciona una matriz de todos los descendientes de una clase:
fuente
#subclasses
es de Rails ActiveSupport.Puedes
require 'active_support/core_ext'
y usar eldescendants
método. Mira el documento y pruébalo en IRB o en palanca. Se puede usar sin rieles.fuente
using Rails
un sentido holístico.Rails proporciona un método de subclases para cada objeto, pero no está bien documentado y no sé dónde está definido. Devuelve una matriz de nombres de clase como cadenas.
fuente
Usar descendants_tracker gem puede ayudar. El siguiente ejemplo se copia del documento de la gema:
Esta gema es utilizada por la popular joya virtus , así que creo que es bastante sólida.
fuente
Este método devolverá un hash multidimensional de todos los descendientes de un Objeto.
fuente
Si tiene acceso al código antes de cargar cualquier subclase, puede usar el método heredado .
Si no lo hace (lo cual no es un caso, pero podría ser útil para cualquiera que haya encontrado esta publicación), simplemente puede escribir:
Lo siento si me perdí la sintaxis, pero la idea debería ser clara (no tengo acceso a Ruby en este momento).
fuente