2009-11-14 10 views
12

Estoy tratando de hacer un instance_eval seguido de un attr_accessor dentro de initialize, y sigo obteniendo esto: `` initialize ': método indefinido' attr_accessor'`. ¿Por qué no está funcionando?¿Por qué no puedo usar attr_accessor dentro de initialize?

El código es algo así como esto:

class MyClass 
    def initialize(*args) 
     instance_eval "attr_accessor :#{sym}" 
    end 
end 

Respuesta

20

No se puede llamar attr_accessor en la instancia, porque attr_accessor no se define como un método de instancia de MyClass. Solo está disponible en módulos y clases. Sospecho que desea llamar attr_accessor en metaclase de la instancia, así:

class MyClass 
    def initialize(varname) 
    class <<self 
     self 
    end.class_eval do 
     attr_accessor varname 
    end 
    end 
end 

o1 = MyClass.new(:foo) 
o2 = MyClass.new(:bar) 
o1.foo = "foo" # works 
o2.bar = "bar" # works 
o2.foo = "baz" # does not work 
+0

class_eval es lo mismo que ponerlo donde escribió usted mismo – johannes

+4

No, no lo es. 'clase << uno mismo; ...; end' no es un cierre. No podrá acceder a 'varname' dentro de él, pero puede acceder a él en el bloque' class_eval'. – sepp2k

+0

[respuesta de semiomant] (http://stackoverflow.com/a/14978624/403664) es bueno. Echale un vistazo. –

4

una implementación más limpia (NB: Esto añadirá el descriptor de acceso a todas las instancias de la clase, no sólo la única instancia, ver comentarios abajo):

class MyClass 
    def initialize(varname) 
    self.class.send(:attr_accessor, varname) 
    end 
end 
+6

Esto define el descriptor de acceso como un método de instancia de 'MyClass'. Entonces, si tienes 'o1 = MyClass.new (: foo)' y 'o2 = MyClass.new (: bar)' tanto 'o1' como' o2' tienen accesadores para 'foo' y' bar', que no es el comportamiento previsto. – sepp2k

+0

¡Muy bien! Aquí tengo mis botes. Dejaré esta respuesta aquí (con su comentario) para cualquier persona que pueda encontrarla. –

+0

La solución de Rob parece mucho más limpia. Pero me atendré a la solución de sepp2k, teniendo los accesadores solo para una instancia. – JAkk

4

Rob d'Apice lo tiene casi derecha. Sólo tiene que escribir:

self.singleton_class.send(:attr_accessor, varname) 

o

self.singleton_class.class_eval "attr_accessor :#{varname}" 

o mi variante preferida

self.singleton_class.class_exec do attr_accessor varname end 

asumiendo el valor de varname es un símbolo

Cuestiones relacionadas