50 votes

Obtenir une classe par son nom en Ruby ?

Avoir une chaîne avec le module et le nom d'une classe, comme :

"Admin::MetaDatasController"

comment puis-je obtenir le cours actuel ?

Le code suivant fonctionne s'il n'y a pas de module :

Kernel.const_get("MetaDatasController")

mais ça casse avec le module :

ruby-1.8.7-p174 > Kernel.const_get("Admin::MetaDatasController")
NameError: wrong constant name Admin::MetaDatasController
        from (irb):34:in `const_get'
        from (irb):34
ruby-1.8.7-p174 >

92voto

Theo Points 60103

Si vous voulez quelque chose de simple qui ne gère que votre cas particulier, vous pouvez écrire

Object.const_get("Admin").const_get("MetaDatasController")

Mais si vous voulez quelque chose de plus général, divisez la chaîne sur :: et résoudre les noms l'un après l'autre :

def class_from_string(str)
  str.split('::').inject(Object) do |mod, class_name|
    mod.const_get(class_name)
  end
end

the_class = class_from_string("Admin::MetaDatasController")

Lors de la première itération Object est demandé pour la constante Admin et renvoie le Admin puis, à la deuxième itération, on demande à ce module ou à cette classe la constante MetaDatasController et renvoie cette classe. Puisqu'il n'y a plus de composants, la méthode renvoie cette classe (s'il y avait eu plus de composants, elle aurait itéré jusqu'à trouver le dernier).

45voto

Joshua Cheek Points 9450

ActiveSupport fournit une méthode appelée constantize, qui permet de le faire. Si vous êtes sur Rails, ce que je suppose d'après le nom de votre constante, alors vous avez déjà chargé ActiveSupport.

require 'active_support/core_ext/string'

class Admin
  class MetaDatasController
  end
end

"Admin::MetaDatasController".constantize # => Admin::MetaDatasController

Pour voir comment la méthode est mise en œuvre, consultez le document suivant https://github.com/rails/rails/blob/85c2141fe3d7edb636a0b5e1d203f05c70db39dc/activesupport/lib/active_support/inflector/methods.rb#L230-L253

22voto

hololeap Points 169

En Ruby 2.x, vous pouvez simplement faire cela :

Object.const_get('Admin::MetaDatasController')
=> Admin::MetaDatasController

1voto

potatopeelings Points 864

Je suis peut-être à côté de la plaque, mais l'évaluation ne renverrait-elle pas la classe ?

eval("Admin::MetaDatasController")

donc eval("Admin::MetaDatasController").new serait la même chose que Admin::MetaDatasController.new

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