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 descendantsmé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_classen lugar deClasshacerlo mucho más rápido (ver fuente en apidock.com/rails/Class/descendants )ObjectSpaceno la tendrá.ObjectyBasicObject?, 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 nombreselfen la línea de código del método.Si usa Rails> = 3, tiene dos opciones en su lugar. Úselo
.descendantssi desea más de un nivel de profundidad de clases para niños, o úselo.subclassespara 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;enddevuelve el singleton_class de un objeto. En 1.9+ puedes usarsome_obj.singleton_classen 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 (
ClassoModule)De esta manera, es mucho más rápido que compararlo con cada clase
ObjectSpacecomo 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
#subclasseses de Rails ActiveSupport.Puedes
require 'active_support/core_ext'y usar eldescendantsmétodo. Mira el documento y pruébalo en IRB o en palanca. Se puede usar sin rieles.fuente
using Railsun 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