Today we’ll talk about attributes in Ruby.
Let’s start with the following rule from the Ruby Style Guide:
attrfamily of functions to define trivial accessors or mutators.
Everyone who’s coded a bit of Ruby knows it’s preferable to generate
trivial reader and writer methods via some metaprogramming magic
instead of writing them by hand. The methods from
attr_accessor do exactly that kind
of magic. Here’s an example using
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
attr_writer in action:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
attr_accessor combines the two:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Pretty sure none of you has learned anything new at this point. Now we start with the fun part…
How many of you know how
attr behaves? Are you totally sure? Let’s
see what the style guide says about it:
Avoid the use of
attr’s behavior changed between Ruby 1.8 and 1.9. In Ruby 1.8
created a single reader method. With an optional second boolean argument it
created both a reader and a writer method (a la
1 2 3 4 5 6 7 8 9
Note that you cannot pass multiple attribute names to
attr in Ruby 1.8.
In Ruby 1.9 calling
attr with an attribute name and a boolean is
deprecated and it now behaves a lot more like
Given all this facts it’s not a surprise that so many people think
it’s a bad idea to use
attr. I guess if the design of that portion
of the API were up to me I’d have made
attr behave like
attr_accessor from day 1. The name of
attr_accessor is a bit of a
accessor is hardly a synonym for reader and
writer. Anyways, this is not of particular importance. Off to the
next item on our agenda for today.
Is this something that should have been defined with
1 2 3
Basically it call comes down to whether this is a trivial reader method or not. Some people would argue that because the name of the instance variable and the name of the method are not the same – it’s not. I’d argue the opposite case – it is! The name of the method does not change the semantics. In essence you’re simply in need of an alias for the default attribute reader method:
Boolean attributes are a bit special, since generally we’d like to
? at the end of predicate method names, but this cannot be done with
attr_reader/attr_accessor. Some people would simple hand-code such
1 2 3
I wouldn’t call one style necessary good or bad – it’s more of a personal preference.
One final note – you should use
attr_ only for trivial reader and writer methods (trivial means that
they do not need any defensive copying or pre-update checks).
1 2 3 4
This would expose
@something to external modifications if it’s a
mutable object. To shield yourself from this you can use defensive
copying (or freezing when applicable):
1 2 3 4
Same goes for attributes writers. If you have an
age attribute and you
want to enforce that it should be a positive number you’d generally roll your
1 2 3 4 5
This post has become way too long, so I’ll be wrapping it up. I hope you’ve found my musing on the subject of attributes useful.
As usual I’m looking forward to hearing your thoughts here and on Twitter!
P.S. Happy 4th of July to all my American readers! :–)