One thought I had on this episode is that the decorator mentioned in the Printer
example is particularly useful for changing the interface of an object from a library that we don’t control:
class Printer
def initialize(item)
@item = item
end
def print
puts @item
end
end
Ruby’s puts
method implicitly prints the return value of the #to_s
method on the object.
We previously needed to print these types:
Text.new.to_s
Image.new.filename
Document.new.formatted
One option would be to not care about modifying those classes. I would first grep
the project for instances of Image
and Document
and examine how they are being used. Assuming that search makes me feel like this change is possible, I would probably add an Image#to_s
and change Document#formatted
to Document#to_s
, then run all the specs and see if there are any failures.
What if Document
came from a library like Prawn or DocRaptor, though? I may not have control over modifying the class (beyond monkey patching, which I try to avoid). This is the case where a decorator would be great:
class PrintableDocument < SimpleDelegator
def initialize(*args)
super(Document.new(args))
end
def class
__getobj__.class
end
def to_s
__getobj__.formatted
end
end
There’s more detail on decorators in Ruby in Evaluating Alternative Decorator Implementations in Ruby, Tidy Views and Beyond with Decorators, and Decorators Compared to Strategies, Composites, and Presenters.