2012-04-04 59 views

Odpowiedz

24

Użyj introspekcji, Luke!

class A 
    attr_accessor :x, :y 

    def initialize(*args) 
    @x, @y = args 
    end 

    def attrs 
    instance_variables.map{|ivar| instance_variable_get ivar} 
    end 
end 

a = A.new(5,10) 
a.x # => 5 
a.y # => 10 
a.attrs # => [5, 10] 
+2

Uwaga: attrs powróci * wszystkie * zmienne instancji, a nie tylko te ujawnione przez 'attr_accessor' – Jonah

+0

@Jonah: tak, to było wtedy założenie. Bardziej precyzyjną metodę można odnieść do [tej odpowiedzi] (http://stackoverflow.com/a/34440466/125816). –

1

podczas korzystania attr_accessor zdefiniować atrybuty klasy, Ruby przy użyciu refexion zdefiniować kilka sposobów, na każdy atrybut oświadczył jeden uzyskać wartość i inne ustawienia, instancję zmiennej o tej samej nazwie atrybutu

widać to metody z użyciem

p A.instance_methods 

[:x, :x=, :y, :y=, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?,.. 

więc to atrybuty są dostepne, poza klasą, z

p "#{a.x},#{a.y}" 

lub wewnątrz klasy dzięki odpowiedniej instancji zmiennej

class A 
    ... 
    def attributes 
    [@x,@y] 
    end 
    ... 
end 
p a.attributes #=> [5,10] 
+3

Dziękuję za odpowiedź, ale zapytałem o przypadek, gdy nie znam nazw atrybutów, ponieważ w przeciwnym razie nie byłoby to podejście DRY.Na przykład, co jeśli zdecyduję się dodać dodatkowe atrybuty '@ d',' @ e', '@ f'. Wtedy będę musiał dodać je w metodzie 'attributes' manualy, jak również w' initialize', co prowadzi do powielenia kodu. – user1179942

+0

W tej sytuacji użyj rozwiązania Sergio – pgon

12

Chociaż odpowiedź Sergio pomaga, zwróci wszystkie zmienne instancji, który, jeśli dobrze rozumiem pytanie PO, a nie to, co jest proszony.

Jeśli chcesz zwrócić tylko "atrybuty", które mają np. mutator, trzeba zrobić coś nieco bardziej skomplikowane, takie jak:

attrs = Hash.new 
instance_variables.each do |var| 
    str = var.to_s.gsub /^@/, '' 
    if respond_to? "#{str}=" 
    attrs[str.to_sym] = instance_variable_get var 
    end 
end 
attrs 

ta zwraca tylko te atrybuty zadeklarowane z attr_accessor (lub z utworzonego ręcznie mutator) i zachować wewnętrzne zmienne instancji ukryte. Możesz zrobić coś podobnego, jeśli chcesz zadeklarować te z attr_reader.

+0

Myślę, że jest to lepsza odpowiedź, biorąc pod uwagę pytanie. Po prostu dodam do tego. Ruby tworzy {Variable} = metody, gdy symbol został dodany jako akcesor lub program piszący. odpowiedzi na? zapewnia, że ​​istnieje poprawna metoda istniejąca z nazwą {Variable} =. Pierwsza część to odgadnięcie pierwszego "@" zwróconej zmiennej. W przykładzie OP zostaną utworzone metody "x =" i "y =", których szukasz przez @x; x = i @y; y = –

+0

W niektórych przypadkach będzie to obejmować: attributes = '. : / – XtraSimplicity

3

Zobacz ten inny Stack Overflow Question. Zastępują attr_accessor.

def self.attr_accessor(*vars) 
    @attributes ||= [] 
    @attributes.concat vars 
    super(*vars) 
    end 

    def self.attributes 
    @attributes 
    end 

    def attributes 
    self.class.attributes 
    end 
1
class A 
    ATTRIBUTES = [:x, :y] 
    attr_accessor *ATTRIBUTES 

    def initialize(x,y) 
    @x, @y = x, y 
    end 

    def attributes 
    ATTRIBUTES.map{|attribute| self.send(attribute) } 
    end 
end 

To nie może być DRY-est, ale jeśli jesteś zainteresowany tylko w ten sposób do jednej klasy (w przeciwieństwie do klasy bazowej że wszystko dziedziczy), to powinno działać.

0

Jeśli masz attr_writer s/attr_accessor s zdefiniowane na swoich atrybutów, niż mogą być łatwo pobierane przez dopasowanie =$ regexp:

A.instance_methods.each_with_object([]) { |key, acc| acc << key.to_s.gsub(/=$/, '') if key.match(/\w=$/) } 

LUB

A.instance_methods.each_with_object([]) { |key, acc| acc << key if key = key.to_s.match(/^(.*\w)=$/)&.[](1) } 
Powiązane problemy