Ich kann die Klassenhierarchie in Ruby leicht aufsteigen lassen:
String.ancestors # [String, Enumerable, Comparable, Object, Kernel]
Enumerable.ancestors # [Enumerable]
Comparable.ancestors # [Comparable]
Object.ancestors # [Object, Kernel]
Kernel.ancestors # [Kernel]
Gibt es eine Möglichkeit, die Hierarchie ebenfalls abzusteigen? Ich würde das gerne machen
Animal.descendants # [Dog, Cat, Human, ...]
Dog.descendants # [Labrador, GreatDane, Airedale, ...]
Enumerable.descendants # [String, Array, ...]
aber es scheint keine descendants
Methode zu geben.
(Diese Frage wird gestellt, weil ich alle Modelle in einer Rails-Anwendung finden möchte, die von einer Basisklasse abstammen, und sie auflisten möchte. Ich habe einen Controller, der mit jedem solchen Modell arbeiten kann, und ich möchte neue Modelle hinzufügen können ohne den Controller ändern zu müssen.)
singleton_class
anstattClass
es viel schneller zu machen (siehe Quelle unter apidock.com/rails/Class/descendants )ObjectSpace
diese nicht hat.Object
und machenBasicObject
?, Neugierig zu wissen, was sie zeigenp ObjectSpace.each_object(Class)
druckt alle Klassen aus. Sie können die Nachkommen jeder gewünschten Klasse auch abrufen, indem Sie ihren Namenself
in der Codezeile der Methode ersetzen .Wenn Sie Rails> = 3 verwenden, haben Sie zwei Möglichkeiten. Verwenden
.descendants
Sie diese Option, wenn Sie mehr als eine Ebenentiefe für untergeordnete Klassen oder.subclasses
für die erste Ebene von untergeordneten Klassen verwenden möchten .Beispiel:
quelle
Ruby 1.9 (oder 1.8.7) mit raffinierten verketteten Iteratoren:
Ruby vor 1.8.7:
Verwenden Sie es so:
quelle
ObjectSpace.each_object(::Class)
- dies sorgt dafür, dass der Code funktioniert, wenn zufällig eine YourModule :: -Klasse definiert ist.Überschreiben Sie die Klassenmethode mit dem Namen geerbt . Diese Methode wird beim Erstellen der Unterklasse übergeben, die Sie verfolgen können.
quelle
Alternativ (aktualisiert für Ruby 1.9+):
Ruby 1.8 kompatibler Weg:
Beachten Sie, dass dies für Module nicht funktioniert. Außerdem wird YourRootClass in die Antwort aufgenommen. Sie können Array # - oder eine andere Methode zum Entfernen verwenden.
quelle
ObjectSpace.each_object(class<<MyClass;self;end) {|it| puts it}
class<<some_obj;self;end
die singleton_class eines Objekts zurück. In 1.9+ können Siesome_obj.singleton_class
stattdessen verwenden (meine Antwort wurde aktualisiert, um dies widerzuspiegeln). Jedes Objekt ist eine Instanz seiner singleton_class, die auch für Klassen gilt. Da jedes Objekt (SomeClass) alle Instanzen von SomeClass zurückgibt und SomeClass eine Instanz von SomeClass.singleton_class ist, gibt jedes Objekt (SomeClass.singleton_class) SomeClass und alle Unterklassen zurück.Obwohl die Verwendung von ObjectSpace funktioniert, scheint die geerbte Klassenmethode hier besser für die geerbte Ruby-Dokumentation (Unterklasse) geeignet zu sein
Objectspace ist im Wesentlichen eine Möglichkeit, auf alles zuzugreifen, was derzeit den zugewiesenen Speicher verwendet. Daher ist es nicht ideal, jedes einzelne seiner Elemente zu durchlaufen, um zu überprüfen, ob es sich um eine Unterklasse der Animal-Klasse handelt.
Im folgenden Code implementiert die geerbte Animal-Klassenmethode einen Rückruf, der alle neu erstellten Unterklassen zu ihrem Nachkommen-Array hinzufügt.
quelle
Ich weiß, dass Sie fragen, wie dies bei der Vererbung zu tun ist, aber Sie können dies direkt in Ruby erreichen, indem Sie die Klasse (
Class
oderModule
) mit einem Namensabstand versehen.Auf diese Weise ist es viel schneller als im Vergleich zu jeder Klasse in
ObjectSpace
wie es andere Lösungen vorschlagen.Wenn Sie dies in einer Erbschaft ernsthaft benötigen, können Sie Folgendes tun:
Benchmarks hier: http://www.eq8.eu/blogs/13-ruby-ancestors-descendants-and-other-annoying-relatives
aktualisieren
Am Ende müssen Sie nur noch Folgendes tun
danke @saturnflyer für den vorschlag
quelle
(Rails <= 3.0) Alternativ können Sie ActiveSupport :: DescendantsTracker verwenden, um die Tat auszuführen. Aus der Quelle:
Da es gut modularisiert ist, können Sie einfach das jeweilige Modul für Ihre Ruby-App auswählen.
quelle
Ruby Facets hat Nachkommen der Klasse #,
Es unterstützt auch einen Generationsabstandsparameter.
quelle
Eine einfache Version, die ein Array aller Nachkommen einer Klasse enthält:
quelle
#subclasses
von Rails ActiveSupport stammt.Sie können
require 'active_support/core_ext'
und verwenden diedescendants
Methode. Schauen Sie sich das Dokument an und probieren Sie es in IRB oder Pry aus. Kann ohne Schienen verwendet werden.quelle
using Rails
in einem ganzheitlichen Sinne ist.Rails bietet für jedes Objekt eine Unterklassenmethode, die jedoch nicht gut dokumentiert ist, und ich weiß nicht, wo sie definiert ist. Es gibt ein Array von Klassennamen als Zeichenfolgen zurück.
quelle
Die Verwendung von descants_tracker gem kann helfen. Das folgende Beispiel wurde aus dem Dokument des Edelsteins kopiert:
Dieser Edelstein wird von dem beliebten Virtus-Edelstein verwendet , daher finde ich ihn ziemlich solide.
quelle
Diese Methode gibt einen mehrdimensionalen Hash aller Nachkommen eines Objekts zurück.
quelle
Wenn Sie Zugriff auf Code haben, bevor eine Unterklasse geladen wird, können Sie geerbt verwenden Methode verwenden.
Wenn Sie dies nicht tun (was kein Fall ist, aber für jeden, der diesen Beitrag gefunden hat, nützlich sein könnte), können Sie einfach schreiben:
Es tut mir leid, wenn ich die Syntax verpasst habe, aber die Idee sollte klar sein (ich habe momentan keinen Zugriff auf Ruby).
quelle