80 votes

Trouver les classes disponibles dans un module

J'ai un module MyModule . Je charge dynamiquement des classes dans cet espace. Comment puis-je obtenir la liste des classes définies dans son espace de noms ?

Exemple :

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

Je dois dire que chaque f contient quelque chose comme "class Foo ; end".

Vous pouvez également penser à ceci : dans Rails, comment pourrais-je trouver de manière programmatique toutes les classes définies dans le module ActiveRecord ?

139voto

Chuck Points 138930

Les classes sont accessibles par le biais de constantes. Les classes définies dans un module sont listées comme des constantes dans ce module. Il suffit donc de choisir les constantes qui font référence aux classes.

MyModule.constants.select {|c| MyModule.const_get(c).is_a? Class}

7 votes

Une chose : pourquoi utilisez-vous ce test au lieu de "MyModule.const_get(c).is_a ? Classe" ? Je ne suis pas familier avec l'utilisation de "===" comme ça.

3 votes

Aucune raison impérieuse. La version === était simplement plus lisible pour moi. L'utilisation de is_a ? fonctionnerait tout aussi bien.

6 votes

Évitez l'utilisation explicite de l'opérateur d'égalité des cas === . Comme son nom l'indique, il est destiné à être utilisé de manière implicite par case et en dehors d'elles, cela donne un code assez confus. [[Guide de style](https://github.com/bbatsov/ruby-style-guide#no-case-equality) ]

4voto

cesartalves Points 112

Si vous êtes sur rails, vous devez d'abord accéder aux constantes pour qu'elles s'affichent, car elles sont chargées paresseusement.

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]**

1voto

blaedj Points 162

Si vous souhaitez obtenir toutes les classes d'un module de manière récursive, vous pouvez faire quelque chose comme

def get_classes(mod)
  mod.constants.map do |c|
    const = mod.const_get(c)
    if const.is_a? Class
      const
    elsif const.is_a? Module
      get_classes(const)
    else
      next
    end
  end.flatten
end

Ensuite, étant donné une structure de module comme :

module MyModule
  module Submodule1
    class Class1
    end
  end

  module Submodule2
    class Class2
    end
  end
end

la sortie ressemble à :

puts get_classes(MyModule)

# => MyModule::Submodule1::Class1
# => MyModule::Submodule2::Class2

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X