web-dev-qa-db-ja.com

attr_readerまたはattr_accessorによって定義された属性を取得する方法

クラスAがあるとします

class A
  attr_accessor :x, :y

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

xおよびy属性を取得するには、それらの名前が正確にわからない場合があります。

例えば。

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

内省を使って、ルーク!

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]
31

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を使用して宣言したい場合は、同様のことができます。

14
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ではないかもしれませんが、(すべてが継承する基本クラスとは対照的に)1つのクラスに対してのみこれを行うことに関心がある場合、これは機能するはずです。

8
marksiemers

この他の 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
3
reto

属性にattr_writers/attr_accessorsが定義されている場合は、=$正規表現に一致させることで簡単に取得できます。

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) }
1
zinovyev

attr_accessorを使用してクラスの属性を定義する場合、Ruby refexionを使用して、宣言された属性ごとにいくつかのメソッドを定義します。1つは値を取得し、もう1つは設定します。属性の同じ名前

あなたはこのメソッドを使用して見ることができます

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

したがって、この属性はクラスの外でアクセス可能です。

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

または対応するインスタンス変数を介してクラス内

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