What is attr_accessor in Ruby?
attr_accessor
is very simple:
attr_accessor :foo
is a shortcut for:
def foo=(val)
@foo = val
end
def foo
@foo
end
it is nothing more than a getter/setter for an object
Let's say you have a class Person
.
class Person
end
person = Person.new
person.name # => no method error
Obviously we never defined method name
. Let's do that.
class Person
def name
@name # simply returning an instance variable @name
end
end
person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error
Aha, we can read the name, but that doesn't mean we can assign the name. Those are two different methods. The former is called reader and latter is called writer. We didn't create the writer yet so let's do that.
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"
Awesome. Now we can write and read instance variable @name
using reader and writer methods. Except, this is done so frequently, why waste time writing these methods every time? We can do it easier.
class Person
attr_reader :name
attr_writer :name
end
Even this can get repetitive. When you want both reader and writer just use accessor!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
Works the same way! And guess what: the instance variable @name
in our person object will be set just like when we did it manually, so you can use it in other methods.
class Person
attr_accessor :name
def greeting
"Hello #{@name}"
end
end
person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"
That's it. In order to understand how attr_reader
, attr_writer
, and attr_accessor
methods actually generate methods for you, read other answers, books, ruby docs.
attr_accessor
is (as @pst stated) just a method. What it does is create more methods for you.
So this code here:
class Foo
attr_accessor :bar
end
is equivalent to this code:
class Foo
def bar
@bar
end
def bar=( new_value )
@bar = new_value
end
end
You can write this sort of method yourself in Ruby:
class Module
def var( method_name )
inst_variable_name = "@#{method_name}".to_sym
define_method method_name do
instance_variable_get inst_variable_name
end
define_method "#{method_name}=" do |new_value|
instance_variable_set inst_variable_name, new_value
end
end
end
class Foo
var :bar
end
f = Foo.new
p f.bar #=> nil
f.bar = 42
p f.bar #=> 42
attr_accessor is just a method. (The link should provide more insight with how it works - look at the pairs of methods generated, and a tutorial should show you how to use it.)
The trick is that class
is not a definition in Ruby (it is "just a definition" in languages like C++ and Java), but it is an expression that evaluates. It is during this evaluation when the attr_accessor
method is invoked which in turn modifies the current class - remember the implicit receiver: self.attr_accessor
, where self
is the "open" class object at this point.
The need for attr_accessor
and friends, is, well:
Ruby, like Smalltalk, does not allow instance variables to be accessed outside of methods1 for that object. That is, instance variables cannot be accessed in the
x.y
form as is common in say, Java or even Python. In Rubyy
is always taken as a message to send (or "method to call"). Thus theattr_*
methods create wrappers which proxy the instance@variable
access through dynamically created methods.Boilerplate sucks
Hope this clarifies some of the little details. Happy coding.
1 This isn't strictly true and there are some "techniques" around this, but there is no syntax support for "public instance variable" access.