-
Notifications
You must be signed in to change notification settings - Fork 0
/
about_sandwich_code.rb
111 lines (93 loc) · 2.61 KB
/
about_sandwich_code.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
require File.expand_path(File.dirname(__FILE__) + '/neo')
class AboutSandwichCode < Neo::Koan
def count_lines(file_name)
file = open(file_name)
count = 0
while 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 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.
file_sandwich(file_name) do |file|
while line = file.gets
return line if line.match(/e/)
end
end
end
def test_finding_lines2
assert_equal "test\n", find_line2("example_file.txt")
end
# ------------------------------------------------------------------
def count_lines3(file_name)
open(file_name) do |file|
count = 0
while file.gets
count += 1
end
count
end
end
def test_open_handles_the_file_sandwich_when_given_a_block
assert_equal 4, count_lines3("example_file.txt")
end
end