2012-04-04 49 views
18

假設中定義的屬性我有一個類A如何打通attr_reader或attr_accessor

class A 
    attr_accessor :x, :y 

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

我怎樣才能得到xy屬性,不知道他們究竟是如何命名的。

E.g.

a = A.new(5,10) 
a.attributes # => [5, 10] 

回答

24

使用自省,盧克!

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

注:ATTRS將返回*所有*實例變量,而不僅僅是由'attr_accessor'公開的那些變量。 – Jonah 2015-12-30 17:26:36

+0

@Jonah:是的,那是當時的假設。對於更精確的方法,可以參考[此答案](http://stackoverflow.com/a/34440466/125816)。 – 2015-12-30 17:47:30

1

當您使用attr_accessor來定義,紅寶石使用refexion的類屬性,定義了幾個方法,每種屬性聲明,一個拿到價值以及其他設置,同名的實例變量該屬性的

您可以使用

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?,.. 

所以這個屬性是入店,類超出這個方法,用

看210

或班級通過相應的實例變量

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

感謝您的回覆,但我詢問了一個不知道屬性名稱的情況,因爲否則它不會是DRY方法。例如,如果我決定添加額外的屬性'@ d','@ e','@ f',該怎麼辦?然後,我必須將它們添加到'attributes'方法manualy以及'initialize'中,這會導致代碼重複。 – user1179942 2012-04-05 14:17:03

+0

在這種情況下,使用塞爾吉奧的解決方案 – pgon 2012-04-05 19:36:58

12

而Sergio的答案有助於裏面,它會返回所有的實例變量,而如果我理解正確的OP的問題,是不是什麼問。

如果您只想返回具有例如賦值函數,你必須做的稍微複雜一些,如東西:

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 

這僅返回attr_accessor(或手動創建的突變)聲明的屬性,並保持隱藏在內部的實例變量。如果你想用attr_reader聲明的話,你可以做類似的事情。

+0

我認爲這是一個更好的回答給出的問題。我只會追加到它。 無論何時添加符號作爲訪問者或寫入者,Ruby都會創建{Variable} =方法。迴應?只是確保{Variable} = name存在有效的方法。第一部分是關閉返回變量中的第一個「@」。 在OP示例中,將創建方法「x =」和「y =」,並且您使用@x; x =和@y; y = – 2014-08-14 22:39:10

+0

來查找它們。在某些情況下,這將包括':屬性='。 :/ – XtraSimplicity 2017-11-02 08:17:49

3

看到這個其他Stack Overflow Question。它們覆蓋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 

這可能不是DRY-EST,但如果你只關注這樣一類(而不是一個基類,一切從繼承),那麼這應該工作。

0

如果你有attr_writer S/attr_accessor,在你的屬性定義,超過他們可以通過匹配=$正則表達式可以很容易地檢索:

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

OR

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