2011-02-11 11 views
29

I tworzone dynamicznie zmienną instancji w moim klasy:Jak ustawić attr_accessor dla zmiennej instancji dynamicznej?

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 

Jak zrobić @my_#{num} teraz jako wartość attr?

np. Chcę móc to zrobić:

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

Odpowiedz

25

ta odpowiedź nie zanieczyszcza przestrzeń klasa, przykład .. Jeśli zrobię mine.my_number 4 następnie pozostałe przypadki Mine nie dostanie metodę my_4 .. to się dzieje, ponieważ używamy klasę singleton obiektu zamiast klasy .

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

Czy jest jakiś powód używania 'singleton_class'? Również bycie jednym linkiem, 'class_eval {attr_accessor:" moja _ # {num} "}' składnia byłaby czystsza :) –

+1

@ HalilÖzgür chcesz zdefiniować tę metodę tylko dla tej instancji, dlatego właśnie używasz 'singleton_class', jeśli użyjesz 'self.class', wtedy wszystkie instancje uzyskają tę metodę, a ty tego nie chcesz. masz rację ze składnią, zrobię zmianę – Orlando

+0

btw singleton_class jest tym samym, co robienie 'class << self' – Orlando

23

Można to wykonać za pomocą __send__. Tutaj:

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

Pozwoli to określić akcesorów na wszystkich instancji, a nie tylko ten, który nazywa się 'my_number' dalej. Dodałem dodatkową odpowiedź, która dodaje tylko metody dla instancji, do których dodano zmienną instancji. – carpeliam

10

Łatwo. Można dynamicznie zdefiniować atrybut czytnika wewnątrz metody 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 

zobaczyć, czy działa Ci

5

Jest jeden problem z tymi dwoma metodami tutaj ... jeśli zmienna instancji jest ustawiona w jednej instancji, jego akcesor będzie dostępny dla wszystkich instancji, ponieważ definiujesz metody na self.class zamiast na sobie.

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 

Co prawdopodobnie chcesz zrobić, to zmodyfikować tylko instancję, która ma zmienną instancji:

class Mine 
    # ... 
    def my_number num 
    class << self 
     attr_accessor "my_#{num}" 
    end 
    self.send("my_#{num}=", num) 
    end 
end 

ten sposób zmienne instancji dostać tylko akcesorów na obiektach, które zostały utworzone za. Również nie zawracałem sobie głowy parametrem instance_variable_set, ponieważ jeśli ustawiasz accessor, myślę, że lepiej będzie go ponownie użyć. Ale to połączenie stylu. Wielką zaletą jest tutaj wywołanie class << self zamiast self.class.

+0

Po wypróbowaniu tego dostałem błąd "niezdefiniowana zmienna lokalna lub metoda" num "dla # ". Wydaje się, że zmienna num nie mieści się tutaj. – kinofrost

+0

Ach, masz rację! Będę musiał pomyśleć o tym trochę więcej. W międzyczasie nie jest to właściwe rozwiązanie. :/ – carpeliam

+0

Nie działa również dla mnie. Usuń swoją odpowiedź, jeśli nie działa. – davidmontoyago

3

Możesz użyć OpenStruct:

require "ostruct" 

class Mine < OpenStruct 
end 

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

nie wiem dlaczego chcesz chcą dude.my_1 powrót 1 - nie jest to, że daje ci to co już masz?

+0

Jestem ciekawa, jak możesz dziedziczyć OpenStruct * i * ActiveRecord :: Base – Trip

+1

@Trip, którego nie możesz odziedziczyć po wielu klasach. –

+0

Moje myśli ->; _; – Trip

0

starszy wątek, ale uznałem za użyteczne dziękuję. Oto kod odpowiedź Dorkus Prime, ale również biorąc wystąpienie z nazwą \ vars w wartości hash

@cookies = browser.cookies.to_a 

@cookies.each do |cookie| 
self.class.__send__(:attr_accessor, "#{cookie[:name]}") 
self.__send__("#{cookie[:name]}=",cookie[:value]) 
end 
Powiązane problemy