2010-07-08 12 views
35

Mam obiekt utworzony i chcę, na podstawie warunkowego sprawdzenia, dodać pewne atrybuty do tego obiektu. Jak mogę to zrobić? Aby wyjaśnić, co chcę:dynamicznie dodawanie atrybutów obiektu Ruby

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

} 

Odpowiedz

6

Można użyć instance_variable_set ustawić zmienną na instancji klasy Object Klasa obiektu nie ma żadnych atrybutów, które można ustawić bezpośrednio (i instance_variable_get je zdobyć). .

Podejrzewam jednak, że nie jest to najlepsze rozwiązanie dla tego, co próbujesz osiągnąć; nie jest normą bezpośrednia praca z klasą Object, ale raczej definiowanie lub używanie klas, które dziedziczą po niej, które mają atrybuty, z którymi chcesz pracować.

44

Przede wszystkim chodzi o to, że pozwala na inną składnię, która jest szeroko stosowana przez programistów ruby. Wielkimi literami są Klasy lub Stałe (dzięki sepp2k), ale próbujesz uczynić z tego obiekt. I prawie nikt nie używa {} do zaznaczania bloku wielowierszowego.

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

Nie jestem pewien, co jest Twoje pytanie, ale mam pomysł, a to byłoby rozwiązanie:

Jeśli wiesz, co przypisuje że klasa może mieć, i to między innymi należy użyć

class YourClass 
    attr_accessor :age 
end 

attr_accessor :age jest skrótem od:

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

teraz można zrobić coś LIK e to:

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

Jeśli chcesz zrobić to całkowicie dynamiczny można zrobić coś takiego:

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

używanie stolic do klasy nie jest "składnią" ruby, ale powszechną konwencją. Już ci mówiłem - nie jestem jeszcze zbytnim rubinem. Przy okazji Twoje rozwiązanie działa wystarczająco dobrze dla mnie. Dzięki. –

+0

Wiem, że to powszechna konwencja, dlatego napisałem: "Wielkimi literami powinny być ** Klasy" i zobaczyłem, że jesteś nowy w Ruby, więc pomyślałem, że pokażę ci, jak zrobi to większość programistów ruby. A składnia dotyczyła paranteza bloku jeśli: – jigfox

+8

@Nikhil: Właściwie to * jest *, a nie kwestią konwencji.Każdy identyfikator zaczynający się od dużej litery jest stałą w rubinie. Zatem 'a = Object.new' i' A = Object.new' robią zbyt różne rzeczy (pierwsza definiuje zmienną lokalną, a druga stałą globalną). – sepp2k

20

to dodaje atrybut tylko do obiektu:

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

Mogłabyś używaj OpenStruct:

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

Lub po prostu użyj zwykłego starego hasha.

+0

genialny! Wielkie dzięki! – pahnin

9

Jeśli nazwa atrybutu jest znany w momencie kod pisanie to można zrobić to, co było już sugerowane:

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 

Jednak jeśli nazwa atrybutu jest dynamiczna i znana tylko w czasie wykonywania Pokochasz więc trzeba zadzwonić pod numer attr_accessor nieco inaczej:

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

Możesz także wykonać 'a.singleton_class.send (: attr_accessor, attr_name)'. Dzięki! –

Powiązane problemy