Template Method Pattern (GoF) without abstract methods in Ruby
Michael Schwarze <[email protected]>
| Newsgroups | gmane.comp.lang.ruby.general |
|---|---|
| Message-ID | <[email protected]> |
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>
signature.asc
(application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEE78Xb8K/0Nf8MzAJdI9hGZAGIlMEFAlw3dvwACgkQI9hGZAGI lMH8lg/8DXtigvb/DiidNhcz0P56kfHqLXvjwpXq2QYsNsAFbiGr4Tq/W1BZ4nir kSjyl1G2J0O9W4sK4scUVcrl/ZgFelNzrxVcpxIdhpk70Sjd3bB4CD17pADlwB47 H87RW7LajAQB+GnZf6FWEZs7PlXTjdKm5SJ3oRExIN45JXdBICZ2mgYNEN7nOT0B 5HV4VzVFgUH/a9xSy2O7QqQVhLTbzydXddhUqrD/sBwkl1uggUrLRma7+5iV7R5N qa4hkeiDsBrgBi5DhrAza0gBG9ngsAloj0FXYx/jK8llSBIxA7Ri7bUyyo/nvWqa zkrkT4cYD+vHkt44ZElzKvHpNmzBFV1OEwoe6nDpBK5JSba9c9EUb8kRdq2gwQNl 5Z18rKgoccyFYOE+G8i8MrjRA64eWo0HRMYZ35dcIgsanJv9axUKNB2bFv9/uBML dsaGcLiqdCuairz3MuudGycpla1yqMjTQgBgahz+tCWBMEK6v8bvY8c2qSfLAzM3 BYnaYwYYtFJJerNnPa4ZdPX5lCxHWY0K0LEgsI7gemfhm+tmZw2oGhl3MQLTDUlL ViLHMPOjzKJMMRaq2JPS6/gMwE9x6pJkDlTB4oQl+DlBZv0ue5zOCEuEDmk6QC4G Glxi3KQPSxPq662HW1L5Xj+wu1JCSxKwoymlW7STHnOCwC2qyXw= =SsLa -----END PGP SIGNATURE-----