¿Cómo creo una instancia de clase a partir de un nombre de cadena en ruby?

121

Tengo el nombre de una clase y quiero crear una instancia de esa clase para poder recorrer cada atributo de rieles que está presente en el esquema de esa clase.

¿Cómo haría yo para hacer eso?

  1. Tengo el nombre como una cadena de la clase que quiero verificar.
  2. Supongo que necesito crear una instancia de clase para poder
  3. Recorra sus atributos e imprímalos.
mhenrixon
fuente
1
Esta es una gran pregunta. Gracias por preguntarme y evitar que lo useeval
David West

Respuestas:

219

En rieles puedes simplemente hacer:

clazz = 'ExampleClass'.constantize

En rubí puro:

clazz = Object.const_get('ExampleClass')

con módulos:

module Foo
  class Bar
  end
end

usarías

> clazz = 'Foo::Bar'.split('::').inject(Object) {|o,c| o.const_get c}
  => Foo::Bar 
> clazz.new
  => #<Foo::Bar:0x0000010110a4f8> 
Wes
fuente
4
Tenga en cuenta que Object.const_get('Foo::Bar')no funcionará, mientras que constantizesí.
Marc-André Lafortune
Gracias, me desperté para preguntar sobre eso debido a un problema de Admin :: Usuario :) Adelante.
mhenrixon
Hola @ Wes, esto fue útil, ¡gracias! Pregunta rápida: ¿funcionaría esto también para módulos anidados? Por ejemplo,clazz = 'Foo::Bar::Uber'
iaacp
@iaacp Sí, funcionará para tantos niveles anidados como tenga.
Wes
6

Prueba esto:

Kernel.const_get("MyClass").new

Luego, para recorrer las variables de instancia de un objeto:

obj.instance_variables.each do |v|
  # do something
end
mbreining
fuente
Gracias, ya que realmente tengo que recorrer las columnas del modelo de registro activo, esto no funcionará para mí, pero será útil en mis aplicaciones ruby ​​"puras" :)
mhenrixon
1
Consulte ActiveRecord # atributos () y / o ActiveRecord # atributos_nombres ().
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"

En Ruby 2.0 y anteriores, comunicados, posiblemente, Object.const_getserá de forma recursiva realizar una búsqueda en un espacio de nombres como Foo::Bar. El ejemplo anterior es cuando el espacio de nombres se conoce de antemano y destaca el hecho de que const_getse puede llamar directamente a los módulos en lugar de hacerlo exclusivamente Object.

A-Dubb
fuente
Debería agregar una explicación a esto. A partir de ahora, es solo un bloque de código.
Josh Crozier