What is attr_accessor in Ruby?
Let's say you have a class Person
.
class Personendperson = Person.newperson.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 endendperson = Person.newperson.name # => nilperson.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 endendperson = Person.newperson.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 :nameend
Even this can get repetitive. When you want both reader and writer just use accessor!
class Person attr_accessor :nameendperson = Person.newperson.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}" endendperson = Person.newperson.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 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.
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 :barend
is equivalent to this code:
class Foo def bar @bar end def bar=( new_value ) @bar = new_value endend
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 endendclass Foo var :barendf = Foo.newp f.bar #=> nilf.bar = 42p f.bar #=> 42