Je peux facilement monter dans la hiérarchie des classes dans Ruby:
String.ancestors # [String, Enumerable, Comparable, Object, Kernel]
Enumerable.ancestors # [Enumerable]
Comparable.ancestors # [Comparable]
Object.ancestors # [Object, Kernel]
Kernel.ancestors # [Kernel]
Existe-t-il également un moyen de descendre la hiérarchie? J'aimerais faire ça
Animal.descendants # [Dog, Cat, Human, ...]
Dog.descendants # [Labrador, GreatDane, Airedale, ...]
Enumerable.descendants # [String, Array, ...]
mais il ne semble pas y avoir de descendants
méthode.
(Cette question se pose parce que je veux trouver tous les modèles dans une application Rails qui descendent d'une classe de base et les lister; j'ai un contrôleur qui peut fonctionner avec n'importe quel modèle de ce type et j'aimerais pouvoir ajouter de nouveaux modèles sans avoir à modifier le contrôleur.)
singleton_class
au lieu de leClass
rendre beaucoup plus rapide (voir la source sur apidock.com/rails/Class/descendants )ObjectSpace
ne l'aura pas.Object
etBasicObject
?, Curieux de savoir ce qu'ils montrentp ObjectSpace.each_object(Class)
affichera toutes les classes. Vous pouvez également obtenir les descendants de toute classe souhaitée en remplaçant son nomself
dans la ligne de code de la méthode.Si vous utilisez Rails> = 3, vous avez deux options en place. À utiliser
.descendants
si vous voulez plus d'un niveau de profondeur des classes enfants, ou à utiliser.subclasses
pour le premier niveau des classes enfants.Exemple:
la source
Ruby 1.9 (ou 1.8.7) avec des itérateurs chaînés astucieux:
Ruby pré-1.8.7:
Utilisez-le comme ceci:
la source
ObjectSpace.each_object(::Class)
- cela permettra au code de fonctionner lorsque vous aurez défini un YourModule :: Class.Remplacez la méthode de classe nommée inherited . Cette méthode serait transmise à la sous-classe lors de sa création que vous pouvez suivre.
la source
Alternativement (mis à jour pour ruby 1.9+):
Méthode compatible avec Ruby 1.8:
Notez que cela ne fonctionnera pas pour les modules. En outre, YourRootClass sera inclus dans la réponse. Vous pouvez utiliser Array # - ou un autre moyen de le supprimer.
la source
ObjectSpace.each_object(class<<MyClass;self;end) {|it| puts it}
class<<some_obj;self;end
renvoie le singleton_class d'un objet. Dans la version 1.9+, vous pouvez utiliser à lasome_obj.singleton_class
place (mis à jour ma réponse pour refléter cela). Chaque objet est une instance de sa singleton_class, qui s'applique également aux classes. Puisque each_object (SomeClass) renvoie toutes les instances de SomeClass, et SomeClass est une instance de SomeClass.singleton_class, each_object (SomeClass.singleton_class) renverra SomeClass et toutes les sous-classes.Bien que l'utilisation d'ObjectSpace fonctionne, la méthode de classe héritée semble mieux convenir ici documentation Ruby héritée (sous-classe)
Objectspace est essentiellement un moyen d'accéder à tout et à tout ce qui utilise actuellement la mémoire allouée, donc itérer sur chacun de ses éléments pour vérifier s'il s'agit d'une sous-classe de la classe Animal n'est pas idéal.
Dans le code ci-dessous, la méthode héritée de la classe Animal implémente un rappel qui ajoutera toute sous-classe nouvellement créée à son tableau de descendants.
la source
Je sais que vous demandez comment faire cela en héritage mais vous pouvez y parvenir directement dans Ruby en espaçant les noms de la classe (
Class
ouModule
)C'est beaucoup plus rapide de cette façon que de comparer à toutes les classes
ObjectSpace
comme le proposent d'autres solutions.Si vous en avez vraiment besoin dans un héritage, vous pouvez faire quelque chose comme ceci:
benchmarks ici: http://www.eq8.eu/blogs/13-ruby-ancestors-descendants-and-other-annoying-relatives
mettre à jour
à la fin, tout ce que tu as à faire est ceci
merci @saturnflyer pour la suggestion
la source
(Rails <= 3.0) Vous pouvez également utiliser ActiveSupport :: DescendantsTracker pour faire l'acte. De la source:
Comme il est bien modulaire, vous pouvez simplement choisir ce module particulier pour votre application Ruby.
la source
Ruby Facets a des descendants de classe #,
Il prend également en charge un paramètre de distance générationnel.
la source
Une version simple qui donne un tableau de tous les descendants d'une classe:
la source
#subclasses
provient de Rails ActiveSupport.Vous pouvez
require 'active_support/core_ext'
et utilisez ladescendants
méthode. Consultez le document et essayez-le en IRB ou en faisant levier. Peut être utilisé sans rails.la source
using Rails
dans un sens holistique.Rails fournit une méthode de sous-classes pour chaque objet, mais elle n'est pas bien documentée et je ne sais pas où elle est définie. Il renvoie un tableau de noms de classe sous forme de chaînes.
la source
L'utilisation du gem descendants_tracker peut aider. L'exemple suivant est copié à partir de la documentation du gem:
Cette gemme est utilisée par la gemme virtus populaire , donc je pense qu'elle est assez solide.
la source
Cette méthode retournera un hachage multidimensionnel de tous les descendants d'un Object.
la source
Si vous avez accès au code avant le chargement d'une sous-classe, vous pouvez utiliser la méthode héritée .
Si vous ne le faites pas (ce qui n'est pas un cas mais cela pourrait être utile pour quiconque a trouvé ce message), vous pouvez simplement écrire:
Désolé si j'ai manqué la syntaxe mais l'idée doit être claire (je n'ai pas accès à ruby pour le moment).
la source