How to get attributes that were defined through attr_reader or attr_accessor

Go To


Suppose I have a class A

class A
  attr_accessor :x, :y

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

How can I get x and y attributes without knowing how exactly they were named.


a =,10)
a.attributes # => [5, 10]
2012-04-04 07:43
by user1179942


Use introspection, Luke!

class A
  attr_accessor :x, :y

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

  def attrs{|ivar| instance_variable_get ivar}

a =,10)
a.x # => 5
a.y # => 10
a.attrs # => [5, 10]
2012-04-04 07:46
by Sergio Tulentsev
Note: attrs will return all instance variables, rather than just those exposed by attr_accessorJonah 2015-12-30 17:26
@Jonah: yes, that was the assumption back then. For a more precise method, one can refer to this answer - Sergio Tulentsev 2015-12-30 17:47


While Sergio's answer helps, it will return all the instance variables, which if I understand correctly the OP's question, is not what is asked.

If you want to return only the 'attributes' that have e.g. a mutator, you have to do something slightly more complicated such as:

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

This returns only the attributes declared with attr_accessor (or with a manually created mutator), and keep the internal instance variables hidden. You can do something similar if you want the ones declared with attr_reader.

2014-03-02 18:38
by Nicolas Bonnefon
I think this is a better answer given the question. I'll just append on to it.

Ruby creates {Variable}= methods whenever a symbol has been added as an accessor or writer. respond_to? just ensures that there is a valid method that exist with the {Variable}= name. The first part is to chomp off the first "@" on the returned variable.

In the OP example, methods "x=" and "y=" will get created, and you're looking for them with @x;x= and @y;y - Keith D Ball 2014-08-14 22:39

In some instances, this will include :attributes=. : - XtraSimplicity 2017-11-02 08:17


class A
  ATTRIBUTES = [:x, :y]
  attr_accessor *ATTRIBUTES

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

  def attributes{|attribute| self.send(attribute) }

This may not be the DRY-est, but if you are only concerned with doing this for one class (as opposed to a base class that everything inherits from), then this should work.

2016-08-11 07:12
by marksiemers


See this other Stack Overflow Question. They override attr_accessor.

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

  def self.attributes

  def attributes
2014-03-20 17:28
by reto


when you use attr_accessor to define attributes in a class, Ruby using refexion, define a couple of methods, for each attribute declared, one to get the value and other to set, an instance variable of the same name of the attribute

you can see this methods using

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

So this attributes are accesible, outside the class, with

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

or inside the class through the corresponding instance variable

class A
  def attributes
p a.attributes   #=> [5,10]
2012-04-04 15:15
by pgon
Thanks for your response, but I asked about a case when I don't know the names of the attributes, because otherwise it wouldn't be DRY approach. For example, what if I decide to add additional attributes @d, @e, @f. Then I'll have to add them in attributes method manualy as well as in initialize, which leads to the duplication of code - user1179942 2012-04-05 14:17
In this situation, use the Sergio's solutio - pgon 2012-04-05 19:36


If you have attr_writers/attr_accessors defined on your attributes, than they can be easily retrieved by matching the =$ regexp:

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


A.instance_methods.each_with_object([]) { |key, acc| acc << key if key = key.to_s.match(/^(.*\w)=$/)&.[](1) }
2017-12-29 15:11
by zinovyev