When defining accessories in Ruby, there can be tension between the multiplicity (which we all love) and best practice.
For example, if I want to set a value in an instance, but prevent 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 all of a sudden, I use a raw instance variable that makes me twitch. I mean, if I needed to process has_sauce before setting it for a future date, I would need to do a lot more refactoring than just redefining the accessory. And come on, raw instance variables? Blech.
I could just ignore the problem and use attr_accessor. I mean, anyone can set an attribute if they really want to; it is, after all, ruby. But then I lose the idea of encapsulating data, the interface of the object is less defined, and the system is potentially much more chaotic.
Another solution would be to define a pair of accessories 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 does its job, but it's a piece of the template for easy access and frankly: ew.
So, is there a better Ruby way?