2011-09-23 20 views
18

Estoy intentando generar attr_reader a partir de un hash (con hash anidado) para que refleje la creación de la variable de instancia automáticamente.Ruby: generar dinámicamente attribute_accessor

aquí es lo que tengo hasta ahora:

data = {:@datetime => '2011-11-23', :@duration => '90', :@class => {:@price => '£7', :@level => 'all'}} 


class Event 
#attr_reader :datetime, :duration, :class, :price, :level 
    def init(data, recursion) 
    data.each do |name, value| 
    if value.is_a? Hash 
     init(value, recursion+1) 
    else 
     instance_variable_set(name, value) 
     #bit missing: attr_accessor name.to_sym 
    end 
    end 
end 

Pero no puedo encontrar una manera de hacer eso :(

Respuesta

33

es necesario llamar al método de clase (privada) en el attr_accessorEvent clase:

self.class.send(:attr_accessor, name) 

recomiendo agrega el @ en esta línea:

instance_variable_set("@#{name}", value) 

Y no los use en el hash.

data = {:datetime => '2011-11-23', :duration => '90', :class => {:price => '£7', :level => 'all'}} 
+0

¡¡ERES mi nuevo mejor amigo !! eso solo funciona y es tan simple ... Ruby es mágico :) y TÚ eres una estrella :) (Estoy feliz porque lo busqué por un tiempo) –

+0

Solo una pregunta rápida más, ¿hay alguna manera de anteponer el nombre de el hash que contiene el nombre del descriptor, para poder llamar a my_class.class.price, o algo así? –

+0

Antes que nada, 'clase' es una palabra clave reservada, no la use. Su segunda pregunta en su comentario aquí va más allá del alcance de esta pregunta en particular. Es posible que desee comenzar una nueva pregunta, ya que se trata de la recursión y tal, no con acceso de atributos. (PD, no olvides aceptar la mejor respuesta) – rdvdijk

1

attr_accessor es un método de clase, y como tal debe ser invocado en la clase. También es un método privado, por lo que debe invocarlo en un contexto en el que el objeto de clase sea self.

Como un ejemplo:

class C 
    def foo 
    self.class.instance_eval do 
     attr_accessor :baz 
    end 
    end 
end 

Después de crear una instancia de C y llamando foo en ese caso, esa instancia - y todas las instancias futuras - contendrá métodos baz y baz=.

3

Se podría hacer un poco de meta-mágica para resolver esto, utilizando method_missing:

class Event 
    def method_missing(method_name, *args, &block) 
    if instance_variable_names.include? "@#{method_name}" 
     instance_variable_get "@#{method_name}" 
    else 
     super 
    end 
    end 
end 

Lo que esto va a hacer es permitir el acceso a las variables de objeto ejemplo a través de la sintaxis object.variable, si el objeto tiene esas variables definido, sin recurrir a la modificación de toda la clase a través de attr_accessor.

Cuestiones relacionadas