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

Michael Schwarze <[email protected]>
Newsgroups gmane.comp.lang.ruby.general
Message-ID <[email protected]>
Hi Austin,

Thanks; I’m from a different programming language background and curious whether there is kind of a 'pattern of implementation‘ for implementing the Template Method Pattern in Ruby. My 'research‘ so far brought contra-dictionary results: the book on design patterns in Ruby saying not to use 'abstract‘ methods, but showing them in the respective examples and the examples found on the web |1, 2, 3] showing these 'abstract‘ methods in Ruby, too.

Hence my first question, to understand which approach to implementing the Template Method Pattern Ruby developers have chosen. I think that’s one of the ideas of design patterns: to have and guide a discussion around common or recurring design challenges. How do you approach this in Ruby? Do you prefer to inherit from a simpler use case / class, an 'abstract‘ class with these made up 'abstract‘ methods (no content, just raising an error) or do you prefer mixin modules? Why so?

As I’ve got a real world problem in one of my Ruby projects to solve, which reminded me of the Template Method Pattern, I’ve made up three possible design examples [4, 5, 6] for solving this, which would all work. But which way is ’the Ruby way’ here? So it’s actually more about trying to better understand OO in Ruby than about pattern.

Does this make sense to anybody?

Many thanks!

Cheers,
Michael


> Am 10.01.2019 um 20:23 schrieb Austin Ziegler <[email protected]>:
> 
> 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>


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.