2011-02-11 6 views
29

Me creados dinámicamente una variable de instancia dentro de mi clase:¿Cómo configuro un attr_accessor para una variable de instancia dinámica?

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 atr?

p. Ej. Quiero ser capaz de hacer esto:

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

Respuesta

25

esta respuesta no contamina el espacio de la clase, ejemplo .. si lo hago mine.my_number 4 entonces las otras instancias de Mine no conseguirán el método my_4 .. esto sucede porque usamos 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 
+0

¿Hay alguna razón para usar 'singleton_class'? También siendo una línea, la sintaxis 'class_eval {attr_accessor:" my _ # {num} "}' sería más limpia :) –

+1

@ HalilÖzgür quiere definir ese método solo para esa instancia, entonces es por eso que usa 'singleton_class', si usa 'self.class', entonces todas las instancias obtienen el método y usted no quiere eso. tiene razón con la sintaxis, haré el cambio – Orlando

+0

btw singleton_class es lo mismo que hacer 'clase << self' – Orlando

23

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

Esto va a definir descriptores de acceso en todos los casos, no sólo el que usted llama 'my_number' sucesivamente. Agregué una respuesta adicional que solo agrega métodos para las instancias en las que ha agregado una variable de instancia. – carpeliam

10

Fácil. Se puede definir dinámicamente el lector atributo 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 funciona para usted

5

Hay un problema con los dos métodos aquí ... Si una variable de instancia se establece en un caso, su acceso estará disponible para todas las instancias, porque está definiendo métodos en self.class en lugar de uno mismo.

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 es probable que desee hacer es modificar sólo 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 manera, las variables de instancia única obtener descriptores de acceso de los objetos 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 al class << self en lugar de self.class.

+0

Cuando probé esto, recibí el error "variable local indefinida o método' num 'para # ". Parece que la variable num cae fuera del alcance aquí. – kinofrost

+0

¡Ah, tienes razón! Tendré que pensar en esto un poco más. Mientras tanto, esta no es la solución correcta. :/ – carpeliam

+0

tampoco funcionó para mí. Borre su respuesta si no funciona. – davidmontoyago

3

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é te gustaría volver dude.my_1 1 - no se que devolver lo que ya tiene?

+0

Tengo curiosidad por saber cómo puede heredar OpenStruct * y * ActiveRecord :: Base – Trip

+1

@Trip no puede heredar de varias clases. –

+0

Mis pensamientos ->; _; – Trip

0

hilo antiguo, pero me pareció útil gracias. Aquí está el código de respuesta de Dorkus Prime, pero también teniendo vars ejemplo de nombre \ valores de 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 
Cuestiones relacionadas