Suchen Sie nach verfügbaren Klassen in einem Modul

75

Ich habe ein Modul MyModule. Ich lade dynamisch Klassen hinein. Wie kann ich eine Liste der Klassen erhalten, die in ihrem Namespace definiert sind?

Beispiel:

def load_plugins
  Dir.glob(File.dirname(__FILE__) + '/plugins/*.rb') do |f|
    MyModule.class_eval File.read(f)
  end

  # now how can I find the new classes I've loaded into MyModule?
end

Ich sollte sagen, dass jedes so fetwas wie "Klasse Foo; Ende" enthält.

Sie können sich das auch so vorstellen: Wie kann ich in Rails programmgesteuert alle im ActiveRecord-Modul definierten Klassen finden?

Joshuaxls
quelle

Antworten:

128

Auf Klassen wird über Konstanten zugegriffen. Innerhalb eines Moduls definierte Klassen werden in diesem Modul als Konstanten aufgeführt. Sie müssen also nur die Konstanten auswählen, die sich auf Klassen beziehen.

MyModule.constants.select {|c| MyModule.const_get(c).is_a? Class}
Futter
quelle
7
Eine Sache: Warum verwenden Sie diesen Test anstelle von "MyModule.const_get (c) .is_a? Class"? Ich bin nicht mit der Verwendung von "===" so vertraut.
Joshuaxls
3
Kein zwingender Grund. Die === Version war für mich nur besser lesbar. Is_a verwenden? würde genauso gut funktionieren.
Chuck
6
Vermeiden Sie die explizite Verwendung des Fallgleichheitsoperators ===. Wie der Name schon sagt, soll es implizit von caseAusdrücken verwendet werden, und außerhalb davon liefert es ziemlich verwirrenden Code. [Style Guide ]
James Fernandes
Ich weiß nicht warum, aber dies funktioniert nicht bei in Ruby integrierten Modulen wie Kernel, Comparable und Enumerable.
Vishnuprasanth
1
@Vizkrig: AFAIK Diese Module sollten keine Klassen enthalten. Wenn Sie nach Klassen suchen, die ein Modul enthalten, anstatt nach Klassen, die sich in einem Modul befinden, ist dies eine andere Frage .
Chuck
1

Wenn Sie sich auf Schienen befinden, müssen Sie zuerst auf die Konstanten zugreifen, damit sie angezeigt werden, da sie träge geladen sind.

MyModule::NotAClass = "not a class"

MyModule.constants => [:NotAClass]

MyModule::AClass => :AClass # Access class for it to be autoloaded

MyModule.constants => [:AClass, :NotAClass]

# Now, select the constants which are class instances

MyModule.constants
        .map(&MyModule.method(:const_get))
        .select { |constant| constant.is_a? Class} 

 => [MyModule::AClass]**
cesartalves
quelle