When defining accessors in Ruby, there can be a tension between brevity (which we all love) and best practice.
For example, if I wanted to expose a value on an instance but prohibit any external objects from updating it, I could do the following:
class Pancake
attr_reader :has_sauce
def initialize(toppings)
sauces = [:maple, :butterscotch]
@has_sauce = toppings.size != (toppings - sauces).size
...
But suddenly I'm using a raw instance variable, which makes me twitch. I mean, if I needed to process has_sauce before setting at a future date, I'd potentially need to do a lot more refactoring than just overriding the accessor. And come on, raw instance variables? Blech.
I could just ignore the issue and use attr_accessor
. I mean, anyone can set the attribute if they really want to; this is, after all, Ruby. But then I lose the idea of data encapsulation, the object's interface is less well defined and the system is potentially that much more chaotic.
Another solution would be to define a pair of accessors under different access modifiers:
class Pancake
attr_reader :has_sauce
private
attr_writer :has_sauce
public
def initialize(toppings)
sauces = [:maple, :butterscotch]
self.has_sauce = toppings.size != (toppings - sauces).size
end
end
Which gets the job done, but that's a chunk of boilerplate for a simple accessor and quite frankly: ew.
So is there a better, more Ruby way?