Re: Template Method Pattern (GoF) without abstract methods in Ruby

Austin Ziegler <[email protected]>
Newsgroups gmane.comp.lang.ruby.general
Message-ID <CAJ4ekQt1Ts+VkvpVXm2YbGEh09FwVjvPp_v+hYFj6-prvWwD2Q@mail.gmail.com>
GoF is not a recipe book.

-a

On Thu, Jan 10, 2019 at 11:59 AM Michael Schwarze <[email protected]>
wrote:

> Hi!
>
> I have some questions re. the Template Method Pattern (GoF) in Ruby.
>
> I need to update a simple management reporting system and have to add HTML
> to the so far text-based reports. Looks to me like the classical use case
> for the Template Method Pattern. I learned from Russ Olsen’s book »Design
> Patterns in Ruby« that we do not have / use / „make up“ abstract methods in
> Ruby. But a lot of infos concerning this topic on the web use these
> 'abstract‘ methods by raising some kind of error upon calling the methods
> (see [1, 2, 3]).
>
> Does anybody out there in real ruby code bases actually use this approach
> with made up 'abstract‘ methods?
>
> I’ve come up with three simple and obviously contrived example
> implementations without using abstract methods (and without meta
> programming):
> a) Inheritance from a simple(r) use case [4]
> b) Inheritance from an 'abstract‘ class [5]
> c) Composition by mixin of an 'abstract' module with the concerning
> template method(s) [6]
>
> Anything I might have missed here? And which way is most idiomatic Ruby
> (if at all;-)
>
> Many thanks!
>
> Cheers,
> Michael
>
>
> ~~~
> [1]:
> https://medium.com/@dljerome/design-patterns-in-ruby-template-method-753443f5a1c8
> [2]:
> https://github.com/pruett/ruby-patterns/blob/master/patterns/template_method.md
> [3]:
> https://stackoverflow.com/questions/12873873/ruby-base-class-call-child-class-like-in-abstract-classes/12873925#12873925
>
> [4]: Example 1 - Inheritance from a simple(r) use case:
> # Represents a simple (text) report
> class Report
>   def initialize
>     @title = 'My Report'
>     @text = ['Line 1', 'Line 2.']
>   end
>
>   def output_report
>     output =  head
>     output << body
>     output << footer
>
>     output
>   end
>
>   def head
>     "#{@title}\n"
>   end
>
>   def body
>     output = ''
>     @text.each do |line|
>       output << "#{line}\n"
>     end
>
>     output
>   end
>
>   def footer
>     ''
>   end
> end
>
> # Represents an HTML report, inherits from the simple text report
> class HTMLReport < Report
>   def head
>     <<~HTML
>       <html>
>       <head>
>       <title>#{@title}</title>
>       </head>
>     HTML
>   end
>
>   def body
>     output = "<body>\n"
>     @text.each do |line|
>       output << "<p>#{line}</p>\n"
>     end
>     output << "</body>\n"
>
>     output
>   end
>
>   def footer
>     "</html>\n"
>   end
> end
>
> [5]: Example 2 - Inheritance from an 'abstract‘ class:
> # Represents an abstract report / template method(s)
> class Report
>   def initialize
>     @title = 'My Report'
>     @text = ['Line 1', 'Line 2.']
>   end
>
>   def output_report
>     output =  head
>     output << body
>     output << footer
>
>     output
>   end
> end
>
> # Represents a text report
> class TextReport < Report
>   def head
>     "#{@title}\n"
>   end
>
>   def body
>     output = ''
>     @text.each do |line|
>       output << "#{line}\n"
>     end
>
>     output
>   end
>
>   def footer
>     ''
>   end
> end
>
> # Represents an HTML report
> class HTMLReport < Report
>   def head
>     <<~HTML
>       <html>
>       <head>
>       <title>#{@title}</title>
>       </head>
>     HTML
>   end
>
>   def body
>     output = "<body>\n"
>     @text.each do |line|
>       output << "<p>#{line}</p>\n"
>     end
>     output << "</body>\n"
>
>     output
>   end
>
>   def footer
>     "</html>\n"
>   end
> end
>
> [6]: Example 3 - Mixin of an 'abstract' module with the template method(s):
> # Template method(s) for a report
> module Report
>   def initialize
>     @title = 'My Report'
>     @text = ['Line 1', 'Line 2.']
>   end
>
>   def output_report
>     output =  head
>     output << body
>     output << footer
>
>     output
>   end
> end
>
> # Represents a text report
> class TextReport
>   include Report
>
>   def head
>     "#{@title}\n"
>   end
>
>   def body
>     output = ''
>     @text.each do |line|
>       output << "#{line}\n"
>     end
>
>     output
>   end
>
>   def footer
>     ''
>   end
> end
>
> # Represents an HTML report
> class HTMLReport
>   include Report
>
>   def head
>     <<~HTML
>       <html>
>       <head>
>       <title>#{@title}</title>
>       </head>
>     HTML
>   end
>
>   def body
>     output = "<body>\n"
>     @text.each do |line|
>       output << "<p>#{line}</p>\n"
>     end
>     output << "</body>\n"
>
>     output
>   end
>
>   def footer
>     "</html>\n"
>   end
> end
>
>
> Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
> <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
>


-- 
Austin Ziegler • [email protected][email protected]
http://www.halostatue.ca/ • http://twitter.com/halostatue


Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.