Suppose I have a class A
class A
attr_accessor :x, :y
def initialize(x,y)
@x, @y = x, y
end
end
How can I get x
and y
attributes without knowing how exactly they were named.
E.g.
a = A.new(5,10)
a.attributes # => [5, 10]
Summary. attr_reader and attr_writer in Ruby allow us to access and modify instance variables using the . notation by creating getter and setter methods automatically. These methods allow us to access instance variables from outside the scope of the class definition.
In Ruby, object methods are public by default, while data is private. To access and modify data, we use the attr_reader and attr_writer . attr_accessor is a shortcut method when you need both attr_reader and attr_writer .
attr_accessor is used to define an attribute for object of Model which is not mapped with any column in database.
An attribute reader returns the value of an instance variable. Another way of looking at this is that an attribute reader is a method that “exposes” an instance variable. It makes it accessible for others.
Use introspection, 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]
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 = 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
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With