Defensive Programming via Validating Decorators

Please read the original blog post by Yegor Bugayenko. He uses Java in the examples so I have tried to create possible Ruby version.

# bad version
class Report
  def export(filename)
    raise ArgumentError, 'No file name provided' unless filename
    raise ArgumentError, 'File already exists' if File.exist?(filename)

    # export a report to the file
  end
end

First we create a module to resemble Java interfaces more or less.

module Reportable
  def export(filename)
    raise NotImplementedError
  end
end

Than add class that actually generates a requested report.

class DefaultReport
  include Reportable

  def export(filename)
    # generate a report and save it in the filename
  end
end

Now let's implement couple decorators to validate filename presence and uniqueness.

class NoNullReport
  include Reportable

  def initialize(report)
    @origin = report
  end

  def export(filename)
    raise ArgumentError, 'No file name provided' unless filename
    origin.export(filename)
  end

  private

  attr_accessor origin
end

class NoOverwriteReport
  include Reportable

  def initialize(report)
    @origin = report
  end

  def export(filename)
    raise ArgumentError, 'File already exists' if File.exist?(filename)
    origin.export(filename)
  end

  private

  attr_accessor origin
end

Finally the usage.

report = NoNullReport.new NoOverwriteReport.new DefaultReport.new
report.export 'myfile.csv'
Alexander M About 5 years ago