2010-07-02 12 views
46

Tener una cadena con el módulo y el nombre de una clase, como:¿Obtener una clase por nombre en Ruby?

"Admin::MetaDatasController" 

cómo consigo la clase real?

El siguiente código funciona si no hay módulo:

Kernel.const_get("MetaDatasController") 

pero rompe con el módulo:

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 > 
+0

duplicados de http://stackoverflow.com/ preguntas/1448670/ruby-stringto-class –

Respuesta

88

Si quieres algo simple que maneja sólo su caso especial se puede escribir

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

Pero si quieres algo más general, divide la cuerda en :: y resolver los nombres uno tras otro:

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") 

En la primera iteración Object pregunta se hace por la constante Admin y devuelve el módulo o clase Admin, a continuación, en la segunda iteración se pide que el módulo o clase por la constante MetaDatasController, y devuelve esa clase. Como no hay más componentes, la clase se devuelve del método (si hubiera habido más componentes, se habría iterado hasta encontrar el último).

+1

Fuera de interés, ¿por qué está usando 'Kernel' como receptor? una constante de nivel superior se define en 'Object' y no en' Kernel'. – horseyguy

+0

El OP lo usó, y no me detuve para buscar cuál podría ser el módulo real que definió las constantes de nivel superior. Lo he cambiado – Theo

1

podría estar fuera de la base, pero no evaluaría la clase?

eval("Admin::MetaDatasController") 

por lo eval("Admin::MetaDatasController").new sería el mismo que Admin::MetaDatasController.new

+8

Sí, pero viene con un montón de equipaje. A saber, seguridad y velocidad. Una buena regla general es evitar el uso descuidado de eval. Además, tenga cuidado de a quién sugiere esto, o podría encontrarse siendo incendiado en la hoguera por confraternizar con el mal (tiende a ser un tema delicado). –

+20

:-) lo tengo. eval = mal con un error de ortografía. – potatopeelings

42

ActiveSupport proporciona un método llamado constantize, que va a hacer esto. Si está en Rails, que supongo que está basado en el nombre de su constante, entonces ya tiene cargado ActiveSupport.

require 'active_support/core_ext/string' 

class Admin 
    class MetaDatasController 
    end 
end 

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

Para ver cómo se implementa el método, echa un vistazo a https://github.com/rails/rails/blob/85c2141fe3d7edb636a0b5e1d203f05c70db39dc/activesupport/lib/active_support/inflector/methods.rb#L230-L253

+2

Al agregar un enlace a un archivo github, presione y para obtener un enlace directo a esa confirmación específica. – Ashitaka

+1

También puede usar 'ActiveSupport :: Inflector # constantize' que no requiere que requiera toda la extensión del núcleo String. – hololeap

18

En Rubí 2.x, sólo puede hacer esto:

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

Tenga en cuenta que si no sabe si la constante existe, puede 'Object.const_get (str) rescue nil' o' Object.const_defined? (Str) && Object.const_get (str) ' – Phrogz

Cuestiones relacionadas