Open-Closed Principle

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.