2010-07-08 25 views
35

Tengo un objeto creado, y quiero, basado en alguna comprobación condicional, agregar algunos atributos a este objeto. ¿Cómo puedo hacer esto? Para explicar lo que quiero:agregando atributos a un objeto Ruby dinámicamente

A=Object.new 
if(something happens) 
{ 
    #make A have another attibute say age 
    #& store something in A.age 

} 

Respuesta

6

Puede utilizar instance_variable_set para establecer una variable en una instancia de la clase Object La clase Object no tiene ningún atributos que se pueden establecer directamente (y instance_variable_get conseguirlo.) .

Sin embargo, sospecho que esta no es la mejor solución para lo que está tratando de lograr; no es la norma trabajar directamente con la clase Object, sino definir o usar clases que hereden de ella, que tienen los atributos con los que desea trabajar.

44

En primer lugar, lo que pasa con ruby ​​es que permite una sintaxis diferente que es ampliamente utilizada por los codificadores ruby. Los identificadores en mayúscula son Clases o Constantes (gracias a sepp2k por su comentario), pero intenta convertirlo en un objeto. Y casi nadie usa {} marca un bloque multilínea.

a = Object.new 
if (something happens) 
    # do something 
end 

no estoy seguro de cuál es tu pregunta, pero tengo una idea, y esto sería la solución:

Si sabe qué atributos que clase puede tener, y está limitado se debe utilizar

class YourClass 
    attr_accessor :age 
end 

attr_accessor :age es la abreviatura de:

def age 
    @age 
end 
def age=(new_age) 
    @age = new_age 
end 

Ahora se puede hacer algo lik e esto:

a = YourClass.new 
if (some condition) 
    a.age = new_value 
end 

Si desea hacerlo completamente dinámico que puede hacer algo como esto:

a = Object.new 
if (some condition) 
    a.class.module_eval { attr_accessor :age} 
    a.age = new_age_value 
end 
+1

usando capitales para la clase no está rubí "sintaxis", pero convención común. Ya te dije que aún no soy un tipo rubio. Por cierto, tu solución funciona lo suficientemente bien para mí. Gracias. –

+0

Sé que esta es una convención común, es por eso que escribí "Identificadores en mayúscula ** deben ** ser Clases" y vi que eres nuevo en rubí, así que pensé, te muestro cómo la mayoría de los codificadores de rubí lo harían. Y la sintaxis fue sobre la parátesis del bloque if – jigfox

+8

@Nikhil: en realidad es * sintaxis, no una cuestión de convención.Cualquier identificador que comience con una letra mayúscula es una constante en ruby. Entonces 'a = Object.new' y' A = Object.new' también hacen cosas muy diferentes (la primera define una variable local, la otra una constante global). – sepp2k

20

Esto agrega el atributo de sólo el objeto:

a = Object.new 
if (something happens) 
    class << a 
    attr_accessor :age 
    end 
    a.age = new_age_value 
end 
16

Usted podría utilice un OpenStruct:

a = OpenStruct.new 
if condition 
    a.age = 4 
end 

O simplemente usa un hash antiguo simple.

+0

¡genial! ¡Muchas gracias! – pahnin

9

Si el nombre del atributo se conoce en tiempo de código de escritura entonces usted puede hacer lo que ya se sugirió:

class A 
end 

a = A.new 
a.age = 20 # Raises undefined method `age=' 

# Inject attribute accessors into instance of A 
class << a 
    attr_accessor :age 
end 

a.age = 20 # Succeeds 
a.age # Returns 20 

b = A.new 
b.age # Raises undefined method, as expected, since we only modified one instance of A 

Sin embargo, si el nombre del atributo es dinámica y sólo se conoce en tiempo de ejecución a continuación, te tener que llamar attr_accessor un poco diferente:

attr_name = 'foo' 

class A 
end 

a = A.new 
a.foo = 20 # Raises undefined method `foo=' 

# Inject attribute accessors into instance of A 
a.instance_eval { class << self; self end }.send(:attr_accessor, attr_name) 

a.foo = 20 # Succeeds 
a.foo # Returns 20 
+4

También puede hacer 'a.singleton_class.send (: attr_accessor, attr_name)'. ¡Gracias! –

Cuestiones relacionadas