Sandwhich principle (ruby koans)

hello, I’m working on ruby koans.
Now I have to do some sandwhich code. The exercise looks like this :
require File.expand_path(File.dirname(FILE) + ‘/edgecase’)class
AboutSandwichCode < EdgeCase::Koan def count_lines(file_name)
file = open(file_name)
count = 0
while line = file.gets
count += 1
end
count
ensure
file.close if file
end def test_counting_lines
assert_equal 4, count_lines(“example_file.txt”)
end #
------------------------------------------------------------------ def
find_line(file_name)
file = open(file_name)
while line = file.gets
return line if line.match(/e/)
end
ensure
file.close if file
end def test_finding_lines
assert_equal “test\n”, find_line(“example_file.txt”)
end #

THINK ABOUT IT:

The count_lines and find_line are similar, and yet different.

They both follow the pattern of “sandwich code”.

Sandwich code is code that comes in three parts: (1) the top slice

of bread, (2) the meat, and (3) the bottom slice of bread. The

bread part of the sandwich almost always goes together, but

the meat part changes all the time.

Because the changing part of the sandwich code is in the middle,

abstracting the top and bottom bread slices to a library can be

difficult in many languages.

(Aside for C++ programmers: The idiom of capturing allocated

pointers in a smart pointer constructor is an attempt to deal with

the problem of sandwich code for resource allocation.)

Consider the following code:

def file_sandwich(file_name)

file = open(file_name)
yield(file)

ensure
file.close if file
end # Now we write: def count_lines2(file_name)
file_sandwich(file_name) do |file|
count = 0
while line = file.gets
count += 1
end
count
end
end def test_counting_lines2
assert_equal 4, count_lines2(“example_file.txt”)
end #
------------------------------------------------------------------ def
find_line2(file_name)
# Rewrite find_line using the file_sandwich library function.
end def test_finding_lines2
assert_equal __, find_line2(“example_file.txt”)
end #
------------------------------------------------------------------ def
count_lines3(file_name)
open(file_name) do |file|
count = 0
while line = file.gets
count += 1
end
count
end
end def test_open_handles_the_file_sandwich_when_given_a_block
assert_equal __, count_lines3(“example_file.txt”)
endend
But I don’t get the principle.Can anyone explain this to me ? Roelof

Roelof,

This principle says that when you have two pieces of code that are
almost
identical, except for the “middle” part, you can create a method that
takes
a block to fill the “middle” part.

For example, suppose you have two methods, and both need to save
information to a log file before and after execution:

def hello
save_in_logfile “Starting to execute method ‘hello’”
puts “first method”
save_in_logfile “Finishing execution of method ‘hello’”
end

def world
save_in_logfile “Starting to execute method ‘world’”
puts “second method”
save_in_logfile “Finishing execution of method ‘world’”
end

The “sandwich” the koan talks about could be interpreted as the
save_in_logfile methods being the slices of bread and the puts calls the
meat. So we could use blocks to create this:

def sandwich(string)
save_in_logfile “Starting to execute method ‘#{string}’”
yield
save_in_logfile “Finishing to execute method ‘#{string}’”
end

And the two methods would become:

def hello
sandwich(“hello”) do
puts “first method”
end
end

def world
sandwich(“world”) do
puts “second method”
end
end

This way, the repetitive part (save_in_logfile stuff) is called in only
one
place. This technique is used in the File::open method - when you call
it
with a block, the opened file is automatically closed after the block is
executed.

Hope that helps!

2012/9/24 Roelof W. [email protected]

On Mon, Sep 24, 2012 at 9:38 AM, Carlos A. [email protected]
wrote:

Roelof,

This principle says that when you have two pieces of code that are almost
identical, except for the “middle” part, you can create a method that takes
a block to fill the “middle” part.

Another pattern which has a similar structure and uses abstract
methods and inheritance is “template method”:

Although with template method the stress is more on having different
classes filling in portions of an algorithm with different
functionality. On a higher level of abstraction both patterns share
the property that part (or parts) of an algorithm are delegated to
another method / function which is called from the basic algorithm
implementation.

Kind regards

robert

Oke, If I understand it right the principle is the same as the DRY
method Roelof

Date: Mon, 24 Sep 2012 17:29:34 +0900

Everybody thanks for the explanation. Roelof

Date: Mon, 24 Sep 2012 21:00:05 +0900

On Mon, Sep 24, 2012 at 1:13 PM, Roelof W. [email protected]
wrote:

If I understand it right the principle is the same as the DRY method

DRY is a meta principle: the reduction of redundancy (or: repetition)
is the driving force behind many patterns and refactoring approaches.
Identifying common behavior and finding proper abstractions for it is
one of the core tasks in software engineering - if not the single most
important task we do. It gives you

  • reduced code size
  • less errors during maintenance (if the same code appears n times,
    you will have to fix a bug or implement an extension of the
    functionality in n locations and can easily forget one).
  • sometimes increased complexity

Kind regards

robert