no need

no need

Ruby’s modules give us opportunities to eliminate unnecessary classes from our designs.

In this example we have a citation, something that could be found in any academic paper, and 2 different ways of formatting it

  1. MLA (Modern Language Association)
  2. CMS (Chicago Manual of Style)

The obvious implementation ported from say Java to Ruby would look like:


class Citation

class << self

def mla
  new MLAFormat.new
end

def cms
  new CMSFormat.new
end

end

attr_reader :format

def initialize(format) @format = format end

def to_s format.format self end

end

class Format

def format(citation) raise ‘must be implemented with specific citation formatting’ end

end

class MLAFormat

def format(citation) ‘MLA format’ end

end

class CMSFormat

def format(citation) ‘CMS format’ end

end

citation = Citation.new MLAFormat.new puts citation => ‘MLA format’

citation = Citation.new CMSFormat.new puts citation => ‘CMS format’

citation = Citation.mla puts citation => ‘MLA format’

citation = Citation.cms puts citation => ‘CMS format’

Here our Citation class delegates the formatting specifics to a Format object. And I also created some class methods on Citation to make creating a Citation with a specific format cleaner and simpler.

Now do the various Format classes need to be classes? I’d say no, they don’t require initialization and they have no state; they’re just behavior.

In Ruby we can use modules instead.


class Citation

  class << self

    def mla
      citation = new
      class << citation
        include MLAFormat
      end
      citation
    end

    def cms
      citation = new
      class << citation
        include CMSFormat
      end
      citation
    end

  end

  def to_s
    format
  end

end

module MLAFormat

  def format
    'MLA format'
  end

end

module CMSFormat

  def format
    'CMS format'
  end

end

citation = Citation.new 
class << citation
  include MLAFormat
end
puts citation => 'MLA format'

citation = Citation.new 
class << citation
  include CMSFormat
end
puts citation => 'CMS format'

citation = Citation.mla
puts citation => 'MLA format'

citation = Citation.cms
puts citation => 'CMS format'

Here we mixin to a Citation object at runtime a specific format module. The Citation#to_s method is implemented in terms of #format, who’s implementation must be mixed in via a format module. So we’ve eliminated the abstract superclass, Format, changed 2 keywords from class to module and also eliminated the single citation argument from each Format module’s #format method.

Even though there’s not much difference between the 2 methods, I think using modules is more accurate because the classes just aren’t necessary.

Jared Carroll Developer

Sharpen your programming skills by completing coding exercises that are reviewed by other developers at Upcase today.