2011-05-23 8 views
7

Decir que tengo este código Ruby en test.rbCreación de instancia de la clase en el módulo a través de la cadena

module MyModule 
    class TestClassA 
    end 

    class TestClassB 
    def initialize 
     a = Object.const_get('MyModule::TestClassA').new 
    end 
    end 
end 

Aquí algunas pruebas en una cáscara de rubí comenzaron con IRB test.rb -r:

ruby-1.8.7-p302 > MyModule 
=> MyModule 
ruby-1.8.7-p302 > MyModule::TestClassA 
=> MyModule::TestClassA 
ruby-1.8.7-p302 > MyModule::TestClassA.new 
=> #<MyModule::TestClassA:0x10036bef0> 
ruby-1.8.7-p302 > MyModule::TestClassB 
=> MyModule::TestClassB 
ruby-1.8.7-p302 > MyModule::TestClassB.new 
NameError: wrong constant name MyModule::TestClassA 
    from ./test.rb:7:in `const_get' 
    from ./test.rb:7:in `initialize' 
    from (irb):1:in `new' 
    from (irb):1 

¿Por qué Object.const_get('MyModule::TestClassA').new en el constructor de TestClassB falla mientras MyModule::TestClassA.new funciona en la consola? También probé Object.const_get('TestClassA').new, pero eso tampoco funciona.

Respuesta

17

No hay una constante llamada "MyModule :: TestClassA", hay una constante llamada TestClassA dentro de una constante llamada MyModule.

Probar:

module MyModule 
    class TestClassA 
    end 

    class TestClassB 
    def initialize 
     a = Object.const_get("MyModule").const_get("TestClassA").new 
    end 
    end 
end 

cuanto a por qué no funciona, es porque :: es un operador y no una convención de nomenclatura.

ejemplos e información adicional está disponible en http://www.ruby-forum.com/topic/182803

+0

Gracias por esta explicación tan útil. Una pregunta: ¿Por qué cambiaste tu respuesta de usar un símbolo en const_get vs. ahora una cadena? ¿Eso hace alguna diferencia? ¡Gracias! – StefanS

+1

No, no, pero pensé que como su pregunta era "... a través de una cadena", sería mejor usar una cadena en lugar de un símbolo :-) –

+1

Para construcciones de clase/módulo anidadas arbitrariamente, este 1-liner funciona bien: class_name.split ('::'). inject (Kernel) {| scope, const_name | scope.const_get (const_name)} –

0

En Rubí 2.0+, esto funciona bien:

#! /usr/bin/env ruby 

module Foo 
    class Bar 
    def initialize(baz) 
     @baz = baz 
    end 

    def qux 
     puts "quux: #{@baz}" 
    end 
    end 
end 

Kernel.const_get("Foo::Bar").new('corge').qux 

Resultados:

bash-3.2$ ./test.rb 
quux: corge 
0

Creo que se puede utilizar Object.const_get:

klass = Object.const_get "ClassName" 
klass.new 
Cuestiones relacionadas