tags:

views:

62

answers:

2

I'm learning Ruby and working on my first real project. The program will receive a data structure and needs to reproduce the information contained that structure in various text formats. All of the different output types rely on the same set underlying attributes (about 40 of them) and the same set of common functions (about 10 of them); but they differ in how they render the information as text.

My initial inclination was to design this using inheritance, as illustrated in the example below. However:

  1. I'm not certain how to do this (see code comments in Foo.produce_output).
  2. I'm wondering whether I'm on the wrong track altogether by using inheritance rather than something else -- a mixin?

Ideally, users of the project would not have to concern themselves with all of the format-specific classes (FooFormatA, FooFormatB, etc.). Instead, they would deal only with Foo.

Any advice would be appreciated.

class Foo
    attr_accessor :output_types  # Many other common attributes.
    def produce_output
        # Take a Foo object and invoke the
        # appropriate produce_output method for
        # each of the output types.
    end

    # Various other common methods. 
end

class FooFormatA < Foo
    def produce_output
        puts "FooA"
    end
end

class FooFormatB < Foo
    def produce_output
        puts "FooB"
    end
end

class FooFormatC < Foo
    def produce_output
        puts "FooC"
    end
end

# Example use case.
f = Foo.new
f.output_types = ['A', 'C']
f.produce_output
+3  A: 

inheritance does indeed seem to be the wrong thing here. what i'd do is have a set of methods, format_output_a, format_output_b, ..., then say

['a', 'c'].each {|i| puts self.send('format_output_#{i}')}

if you don't want to tie the method names to the output type, you can maintain a lookup table

FORMATTERS = {'A' => :format_a, 'B' => :format_b, ...}

['A', 'C'].each {|i| puts self.send(FORMATTERS[i])}
Martin DeMello
+1  A: 

If I understand your goal correctly, you want each object of type Foo to be able to implement different output formats? If so, I'd use a mixin like this:

module FooFormats
  attr_accessor :output_types

  def produce_output_a
    puts "FooA"
  end

  def produce_output_b
    puts "FooB"
  end

  def produce_output_c
    puts "FooC"
  end

  def produce_output
    @output_types.each do |output_type|
      begin
        send "produce_output_#{output_type.to_s.downcase}"
      rescue
        #An undefined output format
      end
    end
  end

end

class Foo
  include FooFormats

  def initialize(output_types = [])
    self.output_types = output_types
  end
  # Various other common methods. 
end

# Example use case.
f = Foo.new ['A', 'C']
f.produce_output
Pesto