Comment créer une instance de classe à partir d'un nom de chaîne dans ruby?

121

J'ai le nom d'une classe et je souhaite créer une instance de cette classe afin de pouvoir parcourir chaque attribut de rails présent dans le schéma de cette classe.

Comment pourrais-je faire ça?

  1. J'ai le nom sous forme de chaîne de la classe que je veux vérifier
  2. Je suppose que j'ai besoin d'instancier une instance de classe pour pouvoir
  3. Parcourez ses attributs et imprimez-les.
mhenrixon
la source
1
c'est une excellente question. Merci de l'avoir demandé et de m'avoir évité d'utilisereval
David West

Réponses:

219

Dans les rails, vous pouvez simplement faire:

clazz = 'ExampleClass'.constantize

En rubis pur:

clazz = Object.const_get('ExampleClass')

avec modules:

module Foo
  class Bar
  end
end

vous utiliseriez

> clazz = 'Foo::Bar'.split('::').inject(Object) {|o,c| o.const_get c}
  => Foo::Bar 
> clazz.new
  => #<Foo::Bar:0x0000010110a4f8> 
Nous s
la source
4
Notez que Object.const_get('Foo::Bar')cela ne fonctionnera pas, alors que constantizecela fonctionnera.
Marc-André Lafortune
Merci, je me suis réveillé pour poser des questions à ce sujet à cause d'un problème Admin :: User :) Battez-moi.
mhenrixon
Hé @Wes, cela a été utile, merci! Question rapide - cela fonctionnerait-il également pour les modules imbriqués? Par exemple,clazz = 'Foo::Bar::Uber'
iaacp
@iaacp Oui, cela fonctionnera pour autant de niveaux imbriqués que vous.
Wes
6

Essaye ça:

Kernel.const_get("MyClass").new

Ensuite, pour parcourir les variables d'instance d'un objet:

obj.instance_variables.each do |v|
  # do something
end
métissage
la source
Merci, puisque je dois vraiment parcourir les colonnes du modèle d'enregistrement actif, cela ne fonctionnera pas pour moi mais cela sera utile dans mes applications ruby ​​"pures" :)
mhenrixon
1
Découvrez ActiveRecord # attributes () et / ou ActiveRecord # attribute_names ().
mbreining
5
module One
  module Two
    class Three
      def say_hi
        puts "say hi"
      end
    end
  end
end

one = Object.const_get "One"

puts one.class # => Module

three = One::Two.const_get "Three"

puts three.class # => Class

three.new.say_hi # => "say hi"

Ruby 2.0 et, peut - être les versions antérieures, Object.const_getva effectuer une recherche récursive sur un namespaces comme Foo::Bar. L'exemple ci-dessus est lorsque l'espace de noms est connu à l'avance et met en évidence le fait qu'il const_getpeut être appelé directement sur les modules plutôt que exclusivement sur Object.

A-Dubb
la source
Vous devriez ajouter une explication à cela. Pour l'instant, ce n'est qu'un bloc de code.
Josh Crozier