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