variable programacion privados polimorfismo objetos herencia con clases clase attr_reader attr_accessor atributos ruby instance-variables attr attr-accessor

ruby - programacion - ¿Cómo configuro un attr_accessor para una variable de instancia dinámica?



programacion con objetos ruby (7)

Creé dinámicamente una variable de instancia dentro de mi clase:

class Mine attr_accessor :some_var def intialize @some_var = true end def my_number num self.instance_variable_set "@my_#{num}", num end end

¿Cómo hago @my_#{num} ahora como un valor attr?

por ejemplo, quiero poder hacer esto:

dude = Mine.new dude.my_number 1 dude.my_1 => 1


Aquí hay un problema con los dos métodos ... si se establece una variable de instancia en una instancia, su acceso estará disponible para todas las instancias, porque está definiendo métodos en self.class lugar de en self.

dude = Mine.new dude.my_number 1 puts dude.my_1 dudette = Mine.new dudette.my_1 = 2 # works, but probably shouldn''t dudette.my_number 2 dude.my_2 = 3 # works, but probably shouldn''t

Lo que probablemente quiera hacer es modificar solo la instancia que tiene la variable de instancia:

class Mine # ... def my_number num class << self attr_accessor "my_#{num}" end self.send("my_#{num}=", num) end end

De esta forma, las variables de instancia solo obtienen accesos en los objetos para los que fueron creados. Tampoco me molesté con instance_variable_set, porque si está configurando un acceso, entonces creo que se lee mejor para reutilizarlo. Pero eso es una llamada de estilo. El gran problema aquí es llamar a la class << self lugar de self.class .


Es posible que desee utilizar OpenStruct:

require "ostruct" class Mine < OpenStruct end dude = Mine.new dude.my_number = 1 dude.my_number # => 1

No sé por qué querrías que dude.my_1 devolviera 1 - ¿no es eso devolverte lo que ya tienes?


Esto se puede lograr usando __send__ . Aquí:

class Mine attr_accessor :some_var def intialize @some_var = true end def my_number num self.class.__send__(:attr_accessor, "my_#{num}") self.__send__("my_#{num}=", num) end end dude = Mine.new dude.my_number 1 puts dude.my_1 => 1


Fácil. Puede definir dinámicamente el lector de atributos dentro del método my_number:

def my_number num self.instance_variable_set "@my_#{num}", num self.class.class_eval do define_method("my_#{num}") { num } end end

ver si eso funciona para ti


Otra solución más para agregar a la pila, define_singleton_method :

class Mine def my_number num define_singleton_method("num_#{num}") { num } end end

Un efecto secundario de todas estas soluciones es que si lo llamas varias veces con diferentes números, terminas con un montón de métodos en tu objeto:

dude = Mine.new dude.my_number 1 dude.my_number 5 dude.my_1 => 1 dude.my_5 => 5

Podemos solucionar esto eliminando el método anterior:

class Mine def my_number num old_num = @num if @num # need to use `old_num` local variable # instance var scope is different inside `class_eval` singleton_class.class_eval { remove_method("num_#{old_num}") } end @num = num define_singleton_method("num_#{num}") { @num } end end


esta respuesta no contamina el espacio de clases, por ejemplo ... si lo hago mine.my_number 4 , las otras instancias de Mine no obtendrán el método my_4 ... esto sucede porque utilizamos la clase singleton del objeto en lugar de la clase.

class Mine def my_number num singleton_class.class_eval { attr_accessor "my_#{num}" } send("my_#{num}=", num) end end a = Mine.new b = Mine.new a.my_number 10 #=> 10 a.my_10 #=> 10 b.my_10 #=> NoMethodError


hilo más viejo, pero me pareció útil gracias. Aquí está el código de la respuesta de Dorkus Prime, pero también tomando vars de instancia de nombre / valores en un hash

@cookies = browser.cookies.to_a @cookies.each do |cookie| self.class.__send__(:attr_accessor, "#{cookie[:name]}") self.__send__("#{cookie[:name]}=",cookie[:value]) end