2010-07-08 27 views
35

Ho un oggetto creato, e voglio, sulla base di alcune controllo condizionale, per aggiungere alcuni attributi a questo oggetto. Come posso fare questo? Per spiegare quello che voglio:aggiunta di attributi a un oggetto di Ruby dinamicamente

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

} 

risposta

6

È possibile utilizzare instance_variable_set per impostare una variabile su un'istanza della classe Object La classe Object non ha gli attributi che è possibile impostare direttamente (e instance_variable_get per ottenerlo.) .

Tuttavia, ho il sospetto che questo non è la soluzione migliore per ciò che si sta cercando di ottenere; non è la norma di lavorare direttamente con la classe Object, ma piuttosto di definire o utilizzare le classi che ereditano da essa, che hanno gli attributi che si desidera lavorare.

44

Prima di tutto la cosa di rubino è che permette una sintassi diversa, che è ampiamente utilizzato dai programmatori rubino. identificatori capitalizzati sono classi o costanti (grazie a sepp2k per il suo commento), ma si tenta di renderlo un oggetto. E quasi nessuno usa {} fare segnare un blocco multilinea.

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

Io non sono sicuro di quello che la tua domanda è, ma io ho un'idea, e questo sarebbe la soluzione:

Se si sa che cosa gli attributi che classe può avere, ed è limitato si dovrebbe usare

class YourClass 
    attr_accessor :age 
end 

attr_accessor :age è l'abbreviazione di:

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

Ora si può fare qualcosa lik e questo:

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

Se si vuole fare completamente dinamico si può fare qualcosa di simile:

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

l'utilizzo di maiuscole per classe non è "sintassi" ruby ​​ma convenzione comune. Te l'ho già detto - non sono ancora un ragazzo rubino. A parte la tua soluzione funziona abbastanza bene per me. Grazie. –

+0

So che questa è una convenzione comune, ecco perché ho scritto "identificatori maiuscoli ** dovrebbero ** essere classi" e ho visto che sei nuovo nel rubino, così ho pensato, ti mostro come la maggior parte dei programmatori di rubini lo farebbero. E la sintassi era sulla parastesi per il blocco if – jigfox

+8

@Nikhil: In realtà è * la * sintassi, non una questione di convenzione.Qualsiasi identificatore che inizia con una lettera maiuscola è una costante in rubino. Quindi 'a = Object.new' e' A = Object.new' fanno cose troppo diverse (la prima definisce una variabile locale, l'altra una costante globale). – sepp2k

20

Questo aggiunge l'attributo solo l'oggetto:

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

Si potrebbe utilizzare un OpenStruct:

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

O semplicemente usa un semplice vecchio hash.

+0

geniale! Molte grazie! – pahnin

9

Se il nome dell'attributo è noto al momento il codice-scrittura, allora si può fare ciò che è stato suggerito già:

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 

Tuttavia, se il nome dell'attributo è dinamica e conosciuta solo in fase di esecuzione, allora ti chiamare attr_accessor un po 'diversamente:

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

Si può anche fare 'a.singleton_class.send (: attr_accessor, attr_name)'. Grazie! –

Problemi correlati