rspec 0.5.11 → 0.5.12
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +12 -0
- data/README +4 -2
- data/Rakefile +14 -4
- data/bin/spec +7 -7
- data/bin/test2spec +13 -8
- data/lib/spec/api/helper/diff.rb +53 -0
- data/lib/spec/api/helper/instance_helper.rb +11 -11
- data/lib/spec/api/helper/instance_negator.rb +11 -11
- data/lib/spec/api/helper/kind_helper.rb +11 -11
- data/lib/spec/api/helper/kind_negator.rb +11 -11
- data/lib/spec/api/helper/respond_helper.rb +11 -11
- data/lib/spec/api/helper/respond_negator.rb +11 -11
- data/lib/spec/api/helper/should_base.rb +6 -6
- data/lib/spec/api/helper/should_helper.rb +35 -35
- data/lib/spec/api/helper/should_negator.rb +20 -20
- data/lib/spec/rake/spectask.rb +15 -6
- data/lib/spec/runner.rb +1 -0
- data/lib/spec/runner/backtrace_tweaker.rb +2 -0
- data/lib/spec/runner/base_text_formatter.rb +3 -1
- data/lib/spec/runner/html_formatter.rb +153 -0
- data/lib/spec/runner/option_parser.rb +9 -2
- data/lib/spec/runner/progress_bar_formatter.rb +4 -0
- data/lib/spec/runner/rdoc_formatter.rb +3 -0
- data/lib/spec/runner/reporter.rb +5 -5
- data/lib/spec/runner/specdoc_formatter.rb +3 -0
- data/lib/spec/test_to_spec/sexp_transformer.rb +1 -0
- data/lib/spec/test_to_spec/translation_test_runner.rb +10 -2
- data/lib/spec/version.rb +1 -1
- data/test/spec/api/helper/arbitrary_predicate_test.rb +49 -73
- data/test/spec/api/helper/diff_test.rb +60 -0
- data/test/spec/api/helper/equality_test.rb +14 -0
- data/test/spec/api/helper/should_have_test.rb +0 -29
- data/test/spec/api/helper/typing_test.rb +87 -87
- data/test/spec/api/sugar_test.rb +0 -6
- data/test/spec/runner/backtrace_tweaker_test.rb +8 -2
- data/test/spec/runner/html_formatter_test.rb +47 -0
- data/test/spec/runner/option_parser_test.rb +0 -5
- data/test/test_classes.rb +73 -0
- data/test/test_helper.rb +3 -0
- metadata +8 -49
- data/doc/README +0 -3
- data/doc/config.yaml +0 -2
- data/doc/plugin/syntax.rb +0 -60
- data/doc/plugin/version.rb +0 -19
- data/doc/src/core_team.page +0 -31
- data/doc/src/default.css +0 -199
- data/doc/src/default.template +0 -31
- data/doc/src/documentation/index.page +0 -188
- data/doc/src/documentation/meta.info +0 -22
- data/doc/src/documentation/mocks.page +0 -287
- data/doc/src/documentation/underscores.page +0 -21
- data/doc/src/examples.page +0 -9
- data/doc/src/images/David_and_Aslak.jpg +0 -0
- data/doc/src/images/Whats_That_Dude.jpg +0 -0
- data/doc/src/images/ducks1.png +0 -0
- data/doc/src/images/ul.gif +0 -0
- data/doc/src/index.page +0 -74
- data/doc/src/meta.info +0 -33
- data/doc/src/tools/index.page +0 -49
- data/doc/src/tools/meta.info +0 -18
- data/doc/src/tools/rails.page +0 -132
- data/doc/src/tools/rake.page +0 -21
- data/doc/src/tools/rcov.page +0 -28
- data/doc/src/tools/spec.page +0 -129
- data/doc/src/tools/test2spec.page +0 -103
- data/doc/src/tutorials/index.page +0 -52
- data/doc/src/tutorials/meta.info +0 -36
- data/doc/src/tutorials/notes.txt +0 -263
- data/doc/src/tutorials/stack.rb +0 -11
- data/doc/src/tutorials/stack_01.page +0 -226
- data/doc/src/tutorials/stack_02.page +0 -182
- data/doc/src/tutorials/stack_03.page +0 -283
- data/doc/src/tutorials/stack_04.page +0 -164
- data/doc/src/tutorials/stack_04.page.orig +0 -123
- data/doc/src/tutorials/stack_05.page +0 -90
- data/doc/src/tutorials/stack_05.page.orig +0 -124
- data/doc/src/tutorials/stack_06.page +0 -359
- data/doc/src/tutorials/stack_06.page.orig +0 -359
- data/doc/src/tutorials/stack_spec.rb +0 -25
- data/doc/src/ul.gif +0 -0
data/doc/src/tutorials/stack.rb
DELETED
@@ -1,226 +0,0 @@
|
|
1
|
-
h2. A Simple Stack - The First Specification
|
2
|
-
|
3
|
-
h3. Where do we start?
|
4
|
-
|
5
|
-
We want to start off with the simplest thing that we can specify, just as we would in TDD. Remember that in spite of some important (if subtle) distinctions, BDD <em>is</em> TDD at its core.
|
6
|
-
|
7
|
-
As discussed in the <a href="index.html">Overview</a>, a common first specification is that a new stack should be empty, and we typically verify this by checking that its size is 0. This simplicity is what we're looking for, but we want to avoid the "size" question. Well, let's think about how a client might use a stack:
|
8
|
-
|
9
|
-
<ruby>
|
10
|
-
#example usage
|
11
|
-
stack.pop unless stack.empty?
|
12
|
-
</ruby>
|
13
|
-
|
14
|
-
So let's start with "A new stack should be empty".
|
15
|
-
|
16
|
-
h3. Create a spec file
|
17
|
-
|
18
|
-
Start by creating a file called stack_spec.rb in /projects/ruby/stack/. You can use any filename and directory you wish, but the following will assume these names and locations.
|
19
|
-
|
20
|
-
h3. Add a context
|
21
|
-
|
22
|
-
Add the following to stack_spec.rb
|
23
|
-
|
24
|
-
<ruby>
|
25
|
-
context "A new stack" do
|
26
|
-
end
|
27
|
-
</ruby>
|
28
|
-
|
29
|
-
A context represents an object (or set of objects) in a known state. This is the same concept as a fixture in xUnit. For each known state from which we wish to specify behaviour, we'll add a new context.
|
30
|
-
|
31
|
-
To see what damage we've done so far, open a command shell, cd to /projects/ruby/stack/, and enter the following:
|
32
|
-
|
33
|
-
<pre>
|
34
|
-
$ spec stack_spec.rb
|
35
|
-
</pre>
|
36
|
-
|
37
|
-
You should see output similar to this
|
38
|
-
|
39
|
-
<pre>
|
40
|
-
Finished in 6.9e-05 seconds
|
41
|
-
|
42
|
-
1 context, 0 specifications, 0 failures
|
43
|
-
</pre>
|
44
|
-
|
45
|
-
The <code>spec</code> command is installed when you install rSpec. It requires (using the ruby <code>require</code> method) any file(s) (or all of the files in a directory) that you specify on the command line. The <code>context</code> method accepts a name ("An empty stack") and a block (do ... end) and processes everything inside the block. Since there's nothing in this block to process, we discover that rSpec processed 1 context, but 0 specifications.
|
46
|
-
|
47
|
-
You may wonder why bother with the name? Try adding the <code>-f s</code> option to the command
|
48
|
-
|
49
|
-
<pre>
|
50
|
-
$ spec stack_spec.rb -f s
|
51
|
-
|
52
|
-
A new stack
|
53
|
-
|
54
|
-
Finished in 6.9e-05 seconds
|
55
|
-
|
56
|
-
1 context, 0 specifications, 0 failures
|
57
|
-
</pre>
|
58
|
-
|
59
|
-
The option <code>-f s</code> is a shortcut for <code>--format specdoc</code>, which tells rSpec to print out the names of all the contexts and specifications as they are run. As we progress, you'll see how choosing these names carefully not only documents things well inside the spec files, but also in generated output.
|
60
|
-
|
61
|
-
h3. Add a specification
|
62
|
-
|
63
|
-
The spec that we are starting with is "A new stack should be empty". So far we have the context, "A new stack", but we need the specification, "should be empty" :
|
64
|
-
|
65
|
-
<ruby>
|
66
|
-
context "A new stack" do
|
67
|
-
specify "should be empty" do
|
68
|
-
end
|
69
|
-
end
|
70
|
-
</ruby>
|
71
|
-
|
72
|
-
<pre>
|
73
|
-
$ spec stack_spec.rb -f s
|
74
|
-
|
75
|
-
A new stack
|
76
|
-
- should be empty
|
77
|
-
|
78
|
-
Finished in 0.000188 seconds
|
79
|
-
|
80
|
-
1 context, 1 specification, 0 failures
|
81
|
-
</pre>
|
82
|
-
|
83
|
-
As you can see, this reads like a specification. This is just like the output you get from running jUnit tests through agiledox. Agiledox was an important part of the inception of BDD, so we built it right into rspec. Of course, we haven't actually written any code in the specification, so we need to add some. Just as we do in TDD, we're going to add one little bit at a time - just enough to produce a failed expectation - followed by just enough code to meet the expectation.
|
84
|
-
|
85
|
-
Let's start by creating the new stack.
|
86
|
-
|
87
|
-
<ruby>
|
88
|
-
context "A new stack" do
|
89
|
-
setup do
|
90
|
-
@stack = Stack.new
|
91
|
-
end
|
92
|
-
specify "should be empty" do
|
93
|
-
end
|
94
|
-
end
|
95
|
-
</ruby>
|
96
|
-
|
97
|
-
Introducing a setup here may seem a bit premature to some, but we know what the context is here: it's a new stack. We want to express that context in the setup method to clearly define it as the starting state for each of the specifications within this context.
|
98
|
-
|
99
|
-
<pre>
|
100
|
-
$ spec stack_spec.rb -f s
|
101
|
-
|
102
|
-
A new stack
|
103
|
-
- should be empty (FAILED - 1)
|
104
|
-
|
105
|
-
1)
|
106
|
-
NameError in 'A new stack should be empty'
|
107
|
-
uninitialized constant Stack
|
108
|
-
./stack_spec.rb:3:in `setup'
|
109
|
-
|
110
|
-
Finished in 0.00031 seconds
|
111
|
-
|
112
|
-
1 context, 1 specification, 1 failure
|
113
|
-
</pre>
|
114
|
-
|
115
|
-
This tells us that there is a NameError, that it can't find the name Stack, and that the problem is in the setup block of this context. To resolve this, create a new file named stack.rb and add the following:
|
116
|
-
|
117
|
-
<ruby>
|
118
|
-
class Stack
|
119
|
-
end
|
120
|
-
</ruby>
|
121
|
-
|
122
|
-
Then require that file in stack_spec.rb:
|
123
|
-
|
124
|
-
<ruby>
|
125
|
-
require 'stack'
|
126
|
-
|
127
|
-
context "A new stack" do
|
128
|
-
...
|
129
|
-
</ruby>
|
130
|
-
|
131
|
-
and run the specs.
|
132
|
-
|
133
|
-
<pre>
|
134
|
-
$ spec stack_spec.rb -f s
|
135
|
-
|
136
|
-
A new stack
|
137
|
-
- should be empty
|
138
|
-
|
139
|
-
Finished in 0.000229 seconds
|
140
|
-
|
141
|
-
1 context, 1 specification, 0 failures
|
142
|
-
</pre>
|
143
|
-
|
144
|
-
We're getting closer, but we still need more to exercise this specification.
|
145
|
-
|
146
|
-
<ruby>
|
147
|
-
context "A new stack" do
|
148
|
-
setup do
|
149
|
-
@stack = Stack.new
|
150
|
-
end
|
151
|
-
specify "should be empty" do
|
152
|
-
@stack.should_be_empty
|
153
|
-
end
|
154
|
-
end
|
155
|
-
</ruby>
|
156
|
-
|
157
|
-
<pre>
|
158
|
-
$ spec stack_spec.rb -f s
|
159
|
-
|
160
|
-
A new stack
|
161
|
-
- should be empty (FAILED - 1)
|
162
|
-
|
163
|
-
1)
|
164
|
-
NoMethodError in 'A new stack should be empty'
|
165
|
-
undefined method `empty?' for #<Stack:0x36e6fc>
|
166
|
-
./stack_spec.rb:8:in `should be empty'
|
167
|
-
|
168
|
-
Finished in 0.000361 seconds
|
169
|
-
|
170
|
-
1 context, 1 specification, 1 failure
|
171
|
-
</pre>
|
172
|
-
|
173
|
-
In this case, rspec interprets the message <code>should_be_empty</code>, and sends <code>empty?</code> to <code>stack</code>. This will work for any predicate (ruby methods that end with a "?" and return boolean).
|
174
|
-
|
175
|
-
You can think of <code>NameError</code> as the equivalent of a compilation failure in java or C#. <code>Stack</code> doesn't respond to the <code>empty?</code> message ... yet.
|
176
|
-
|
177
|
-
<ruby>
|
178
|
-
class Stack
|
179
|
-
def empty?
|
180
|
-
end
|
181
|
-
end
|
182
|
-
</ruby>
|
183
|
-
|
184
|
-
<pre>
|
185
|
-
$ spec stack_spec.rb -f s
|
186
|
-
|
187
|
-
A new stack
|
188
|
-
- should be empty (FAILED - 1)
|
189
|
-
|
190
|
-
1)
|
191
|
-
ExpectationNotMetError in 'A new stack should be empty'
|
192
|
-
Stack #<Stack:0x36e60c> should be empty
|
193
|
-
./stack_spec.rb:8:in `should be empty'
|
194
|
-
|
195
|
-
Finished in 0.000389 seconds
|
196
|
-
|
197
|
-
1 context, 1 specification, 1 failure
|
198
|
-
</pre>
|
199
|
-
|
200
|
-
... and NOW we get a failing expectation. "Stack #<Stack:0x36e60c> should be empty" is the detail of this <code>ExpectationNotMetError</code>. The expectation is that <code>empty?</code> should return <code>true</code>, but it does not. Let's make it so ...
|
201
|
-
|
202
|
-
<ruby>
|
203
|
-
class Stack
|
204
|
-
def empty?
|
205
|
-
true
|
206
|
-
end
|
207
|
-
end
|
208
|
-
</ruby>
|
209
|
-
|
210
|
-
<pre>
|
211
|
-
spec stack_spec.rb -f s
|
212
|
-
|
213
|
-
A new stack
|
214
|
-
- should be empty
|
215
|
-
|
216
|
-
Finished in 0.000256 seconds
|
217
|
-
|
218
|
-
1 context, 1 specification, 0 failures
|
219
|
-
</pre>
|
220
|
-
|
221
|
-
And thus we have completed our first specification: "A new stack should be empty"
|
222
|
-
|
223
|
-
If you've never had any experience, returning <code>true</code> from <code>empty?</code> may seem a bit strange. Even if you have, you may not feel that the cycle is complete yet. "Test-Code-Refactor", right? Or rather "Spec-Code-Refactor". At this point, we should refactor to eliminate duplication, and you might argue that there is duplication between the spec expecting true and the method returning true. The problem right now is that we have no specs with expectations of the stack being anything other than empty. Any conditional logic we might implement here would be adding new behaviour. Refactoring is defined as changing structure without changing behaviour. And so, as much as we'd like to change <code>true</code> to something more useful, we need to take that urge and recognize that, in this case, we have a deficiency in our specifications - not in the code.
|
224
|
-
|
225
|
-
<a href="stack_02.html">Next</a>
|
226
|
-
|
@@ -1,182 +0,0 @@
|
|
1
|
-
h2. A Simple Stack
|
2
|
-
|
3
|
-
h3. Choosing the next Specification
|
4
|
-
|
5
|
-
We left our code in a state in which it could not be refactored because adding conditional logic would be adding new behaviour at this point (which is not refactoring). We wanted to refactor because we had a hard-coded return value from a method that is begging for some conditional logic. So let's choose a specification to focus on next that will help us to address that. We want a specification that will result in a non-empty stack.
|
6
|
-
|
7
|
-
Since an "empty stack" seems more interesting from a behavioural perspective than a "new stack", let's start talking about the behaviour of an <em>empty</em> stack.
|
8
|
-
|
9
|
-
<ruby>
|
10
|
-
context "An empty stack" do
|
11
|
-
specify "should not be empty after 'push'" do
|
12
|
-
end
|
13
|
-
end
|
14
|
-
</ruby>
|
15
|
-
|
16
|
-
<pre>
|
17
|
-
$ spec stack_spec.rb -f s
|
18
|
-
|
19
|
-
A new stack
|
20
|
-
- should be empty
|
21
|
-
|
22
|
-
An empty stack
|
23
|
-
- should not be empty after 'push'
|
24
|
-
|
25
|
-
Finished in 0.000391 seconds
|
26
|
-
|
27
|
-
2 contexts, 2 specifications, 0 failures
|
28
|
-
</pre>
|
29
|
-
|
30
|
-
See how that's reading like a specification document? OK, now let's fill in the specification. First we add the setup for our context.
|
31
|
-
|
32
|
-
<ruby>
|
33
|
-
context "An empty stack" do
|
34
|
-
setup do
|
35
|
-
@stack = Stack.new
|
36
|
-
end
|
37
|
-
specify "should not be empty after 'push'" do
|
38
|
-
end
|
39
|
-
end
|
40
|
-
</ruby>
|
41
|
-
|
42
|
-
<pre>
|
43
|
-
$ spec stack_spec.rb -f s
|
44
|
-
|
45
|
-
A new stack
|
46
|
-
- should be empty
|
47
|
-
|
48
|
-
An empty stack
|
49
|
-
- should not be empty after 'push'
|
50
|
-
|
51
|
-
Finished in 0.000444 seconds
|
52
|
-
|
53
|
-
2 contexts, 2 specifications, 0 failures
|
54
|
-
</pre>
|
55
|
-
|
56
|
-
No change in the result. Now we'll push something on to the stack.
|
57
|
-
|
58
|
-
<ruby>
|
59
|
-
context "An empty stack" do
|
60
|
-
setup do
|
61
|
-
@stack = Stack.new
|
62
|
-
end
|
63
|
-
specify "should not be empty after 'push'" do
|
64
|
-
@stack.push 37
|
65
|
-
end
|
66
|
-
end
|
67
|
-
</ruby>
|
68
|
-
|
69
|
-
<pre>
|
70
|
-
$ spec stack_spec.rb -f s
|
71
|
-
|
72
|
-
A new stack
|
73
|
-
- should be empty
|
74
|
-
|
75
|
-
An empty stack
|
76
|
-
- should not be empty after 'push' (FAILED - 1)
|
77
|
-
|
78
|
-
1)
|
79
|
-
NoMethodError in 'An empty stack should not be empty after 'push''
|
80
|
-
undefined method `push' for #<Stack:0x36d0e0>
|
81
|
-
./stack_spec.rb:17:in `should not be empty after 'push''
|
82
|
-
|
83
|
-
Finished in 0.000548 seconds
|
84
|
-
|
85
|
-
2 contexts, 2 specifications, 1 failure
|
86
|
-
</pre>
|
87
|
-
|
88
|
-
The <code>NoMethodError</code> tells us we need to add a push method to the stack.
|
89
|
-
|
90
|
-
<ruby>
|
91
|
-
class Stack
|
92
|
-
def empty?
|
93
|
-
true
|
94
|
-
end
|
95
|
-
def push item
|
96
|
-
end
|
97
|
-
end
|
98
|
-
</ruby>
|
99
|
-
|
100
|
-
<pre>
|
101
|
-
$ spec stack_spec.rb -f s
|
102
|
-
|
103
|
-
A new stack
|
104
|
-
- should be empty
|
105
|
-
|
106
|
-
An empty stack
|
107
|
-
- should not be empty after 'push'
|
108
|
-
|
109
|
-
Finished in 0.000427 seconds
|
110
|
-
|
111
|
-
2 contexts, 2 specifications, 0 failures
|
112
|
-
</pre>
|
113
|
-
|
114
|
-
The idea is to add a little bit of spec, just enough to get some kind of failure, then just enough code to get the code to meet the expectations expressed in the spec. In this case, the NameError was like a compilation failure in java or C#.
|
115
|
-
|
116
|
-
Next we set our expectation:
|
117
|
-
|
118
|
-
<ruby>
|
119
|
-
context "An empty stack" do
|
120
|
-
setup do
|
121
|
-
@stack = Stack.new
|
122
|
-
end
|
123
|
-
specify "should not be empty after 'push'" do
|
124
|
-
@stack.push 37
|
125
|
-
@stack.should_not_be_empty
|
126
|
-
end
|
127
|
-
end
|
128
|
-
</ruby>
|
129
|
-
|
130
|
-
<pre>
|
131
|
-
$ spec stack_spec.rb -f s
|
132
|
-
|
133
|
-
A new stack
|
134
|
-
- should be empty
|
135
|
-
|
136
|
-
An empty stack
|
137
|
-
- should not be empty after 'push' (FAILED - 1)
|
138
|
-
|
139
|
-
1)
|
140
|
-
ExpectationNotMetError in 'An empty stack should not be empty after 'push''
|
141
|
-
Stack #<Stack:0x36cf50> should not be empty
|
142
|
-
./stack_spec.rb:18:in `should not be empty after 'push''
|
143
|
-
|
144
|
-
Finished in 0.000604 seconds
|
145
|
-
|
146
|
-
2 contexts, 2 specifications, 1 failure
|
147
|
-
</pre>
|
148
|
-
|
149
|
-
The <code>ExpectationNotMetError</code> tells us we have something to implement. We want to do the simplest thing that we can do to meet our existing expectations. At this point we don't know anything about collections or even specific values, so we can just manage whether or not it is empty.
|
150
|
-
|
151
|
-
<ruby>
|
152
|
-
class Stack
|
153
|
-
def initialize
|
154
|
-
@empty = true
|
155
|
-
end
|
156
|
-
def empty?
|
157
|
-
@empty
|
158
|
-
end
|
159
|
-
def push item
|
160
|
-
@empty = false
|
161
|
-
end
|
162
|
-
end
|
163
|
-
</ruby>
|
164
|
-
|
165
|
-
<pre>
|
166
|
-
$ spec stack_spec.rb -f s
|
167
|
-
|
168
|
-
A new stack
|
169
|
-
- should be empty
|
170
|
-
|
171
|
-
An empty stack
|
172
|
-
- should not be empty after 'push'
|
173
|
-
|
174
|
-
Finished in 0.000443 seconds
|
175
|
-
|
176
|
-
2 contexts, 2 specifications, 0 failures
|
177
|
-
</pre>
|
178
|
-
|
179
|
-
Again, this may seem a little odd, but we haven't specified anything yet about what happens to things that get pushed on to the stack. That's right around the corner though...
|
180
|
-
|
181
|
-
<a href="stack_01.html">Previous</a> |
|
182
|
-
<a href="stack_03.html">Next</a>
|
@@ -1,283 +0,0 @@
|
|
1
|
-
h2. A Simple Stack - eliminating duplication
|
2
|
-
|
3
|
-
h3. What to specify next?
|
4
|
-
|
5
|
-
Picking the next thing to specify is always a challenge (just as picking the next thing to test is in TDD). Ideally, you want to specify the simplest thing that you can imagine implementing. Of course, thinking about implementation seems to fly in the face of a core tenet of TDD and BDD: focus on interface - focus on behaviour. So you have a couple of opposing forces and notions guiding this decision. The bottom line is that it's not that important which one you pick next. The important thing is that as soon as you recognize that you've headed down the wrong path (one which requires a lot of implementation to meet the newest specification), roll back immediately and pick a different "next step".
|
6
|
-
|
7
|
-
For our problem, there seem to be (at least) two logical potential next steps. We know that pushing on to an empty stack results in the stack no longer being empty. So one logical next step might be to specify how an empty stack behaves when sending it a different message. Another might be to send push to a non-empty stack. But what I'd really like to know is what happened to the item we just pushed onto the stack!
|
8
|
-
|
9
|
-
To specify that, we have to move diagonally a bit. We need to specify the stack's response to a new message starting in a new state - a new context. We're going to start with a stack with one item already pushed onto it and specify what happens when you send it 'top'. Why top and not pop? In this case, top is simpler than pop - top just returns the top item, while pop also removes it from the stack.
|
10
|
-
|
11
|
-
h3. Send top to a stack with one item
|
12
|
-
|
13
|
-
Start by adding a new context and spec in stack_spec.rb.
|
14
|
-
|
15
|
-
<ruby>
|
16
|
-
context "A stack with one item" do
|
17
|
-
specify "should return top when you send it 'top'" do
|
18
|
-
end
|
19
|
-
end
|
20
|
-
</ruby>
|
21
|
-
|
22
|
-
<pre>
|
23
|
-
$ spec stack_spec.rb -f s
|
24
|
-
|
25
|
-
A new stack
|
26
|
-
- should be empty
|
27
|
-
|
28
|
-
An empty stack
|
29
|
-
- should not be empty after 'push'
|
30
|
-
|
31
|
-
A stack with one item
|
32
|
-
- should return top when you send it 'top'
|
33
|
-
|
34
|
-
Finished in 0.000693 seconds
|
35
|
-
|
36
|
-
3 contexts, 4 specifications, 0 failures
|
37
|
-
</pre>
|
38
|
-
|
39
|
-
Add the setup...
|
40
|
-
|
41
|
-
<ruby>
|
42
|
-
context "A stack with one item" do
|
43
|
-
setup do
|
44
|
-
@stack = Stack.new
|
45
|
-
@stack.push "one item"
|
46
|
-
end
|
47
|
-
|
48
|
-
specify "should return top when you send it 'top'" do
|
49
|
-
end
|
50
|
-
end
|
51
|
-
</ruby>
|
52
|
-
|
53
|
-
<pre>
|
54
|
-
$ spec stack_spec.rb -f s
|
55
|
-
|
56
|
-
A new stack
|
57
|
-
- should be empty
|
58
|
-
|
59
|
-
An empty stack
|
60
|
-
- should not be empty after 'push'
|
61
|
-
|
62
|
-
A stack with one item
|
63
|
-
- should return top when you send it 'top'
|
64
|
-
|
65
|
-
Finished in 0.000733 seconds
|
66
|
-
|
67
|
-
3 contexts, 4 specifications, 0 failures
|
68
|
-
</pre>
|
69
|
-
|
70
|
-
No change in the output. Add the expectation...
|
71
|
-
|
72
|
-
<ruby>
|
73
|
-
context "A stack with one item" do
|
74
|
-
setup do
|
75
|
-
@stack = Stack.new
|
76
|
-
@stack.push "one item"
|
77
|
-
end
|
78
|
-
|
79
|
-
specify "should return top when you send it 'top'" do
|
80
|
-
@stack.top.should_equal "one item"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
</ruby>
|
84
|
-
|
85
|
-
<pre>
|
86
|
-
$ spec stack_spec.rb -f s
|
87
|
-
|
88
|
-
A new stack
|
89
|
-
- should be empty
|
90
|
-
|
91
|
-
An empty stack
|
92
|
-
- should not be empty after 'push'
|
93
|
-
|
94
|
-
A stack with one item
|
95
|
-
- should return top when you send it 'top' (FAILED - 1)
|
96
|
-
|
97
|
-
1)
|
98
|
-
NoMethodError in 'A stack with one item should return top when you send it 'top''
|
99
|
-
undefined method `top' for #<Stack:0x36bd44 @empty=false>
|
100
|
-
./stack_spec.rb:35:in `should return top when you send it 'top''
|
101
|
-
|
102
|
-
Finished in 0.000863 seconds
|
103
|
-
|
104
|
-
3 contexts, 4 specifications, 1 failure
|
105
|
-
</pre>
|
106
|
-
|
107
|
-
The <code>NoMethodError</code> tells us to add the 'top' method.
|
108
|
-
|
109
|
-
<ruby>
|
110
|
-
class Stack
|
111
|
-
...
|
112
|
-
def top
|
113
|
-
end
|
114
|
-
end
|
115
|
-
</ruby>
|
116
|
-
|
117
|
-
<pre>
|
118
|
-
$ spec stack_spec.rb -f s
|
119
|
-
|
120
|
-
A new stack
|
121
|
-
- should be empty
|
122
|
-
|
123
|
-
An empty stack
|
124
|
-
- should not be empty after 'push'
|
125
|
-
|
126
|
-
A stack with one item
|
127
|
-
- should return top when you send it 'top' (FAILED - 1)
|
128
|
-
|
129
|
-
1)
|
130
|
-
ExpectationNotMetError in 'A stack with one item should return top when you send it 'top''
|
131
|
-
nil should equal "one item"
|
132
|
-
./stack_spec.rb:35:in `should return top when you send it 'top''
|
133
|
-
|
134
|
-
Finished in 0.000867 seconds
|
135
|
-
|
136
|
-
3 contexts, 4 specifications, 1 failure
|
137
|
-
</pre>
|
138
|
-
|
139
|
-
The <code>ExpectationNotMetError</code> tells us to implement something. What's the simplest thing we can add to meet all of the current expectations?
|
140
|
-
|
141
|
-
<ruby>
|
142
|
-
class Stack
|
143
|
-
...
|
144
|
-
def top
|
145
|
-
"one item"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
</ruby>
|
149
|
-
|
150
|
-
<pre>
|
151
|
-
$ spec stack_spec.rb -f s
|
152
|
-
|
153
|
-
A new stack
|
154
|
-
- should be empty
|
155
|
-
|
156
|
-
An empty stack
|
157
|
-
- should not be empty after 'push'
|
158
|
-
|
159
|
-
A stack with one item
|
160
|
-
- should return top when you send it 'top'
|
161
|
-
|
162
|
-
Finished in 0.000744 seconds
|
163
|
-
|
164
|
-
3 contexts, 4 specifications, 0 failures
|
165
|
-
</pre>
|
166
|
-
|
167
|
-
Again we have duplication between the specs and the code ("one item") and we want to get rid of it. This time, however, we have enough specs and entry points that there is actually something to refactor to.
|
168
|
-
|
169
|
-
If you're not familiar with refactoring, check out <a href="http://www.refactoring.com/">http://www.refactoring.com/</a>. We'll do some now, but we won't be examining the steps too deeply. The basic idea is that we want to change structure/implementation without affecting behaviour. Running the specs and watching them pass between each step proves that the behaviour is in tact.
|
170
|
-
|
171
|
-
First, we save the item we add and return that from <code>top</code> ...
|
172
|
-
|
173
|
-
<ruby>
|
174
|
-
class Stack
|
175
|
-
def initialize
|
176
|
-
@empty = true
|
177
|
-
end
|
178
|
-
def empty?
|
179
|
-
@empty
|
180
|
-
end
|
181
|
-
def push item
|
182
|
-
@empty = false
|
183
|
-
@item = item
|
184
|
-
end
|
185
|
-
def top
|
186
|
-
@item
|
187
|
-
end
|
188
|
-
end
|
189
|
-
</ruby>
|
190
|
-
|
191
|
-
<pre>
|
192
|
-
$ spec stack_spec.rb -f s
|
193
|
-
|
194
|
-
A new stack
|
195
|
-
- should be empty
|
196
|
-
|
197
|
-
An empty stack
|
198
|
-
- should not be empty after 'push'
|
199
|
-
|
200
|
-
A stack with one item
|
201
|
-
- should return top when you send it 'top'
|
202
|
-
|
203
|
-
Finished in 0.000846 seconds
|
204
|
-
|
205
|
-
3 contexts, 4 specifications, 0 failures
|
206
|
-
</pre>
|
207
|
-
|
208
|
-
Now let's use the item to determine "emptiness"...
|
209
|
-
|
210
|
-
<ruby>
|
211
|
-
class Stack
|
212
|
-
def initialize
|
213
|
-
@empty = true
|
214
|
-
end
|
215
|
-
def empty?
|
216
|
-
@item.nil?
|
217
|
-
end
|
218
|
-
def push item
|
219
|
-
@empty = false
|
220
|
-
@item = item
|
221
|
-
end
|
222
|
-
def top
|
223
|
-
@item
|
224
|
-
end
|
225
|
-
end
|
226
|
-
</ruby>
|
227
|
-
|
228
|
-
<pre>
|
229
|
-
$ spec stack_spec.rb -f s
|
230
|
-
|
231
|
-
A new stack
|
232
|
-
- should be empty
|
233
|
-
|
234
|
-
An empty stack
|
235
|
-
- should not be empty after 'push'
|
236
|
-
|
237
|
-
A stack with one item
|
238
|
-
- should return top when you send it 'top'
|
239
|
-
|
240
|
-
Finished in 0.000764 seconds
|
241
|
-
|
242
|
-
3 contexts, 4 specifications, 0 failures
|
243
|
-
</pre>
|
244
|
-
|
245
|
-
Now we can eliminate <code>@empty</code> (which means we can eliminate <code>initialize</code> as well).
|
246
|
-
|
247
|
-
<ruby>
|
248
|
-
class Stack
|
249
|
-
def empty?
|
250
|
-
@item.nil?
|
251
|
-
end
|
252
|
-
def push item
|
253
|
-
@item = item
|
254
|
-
end
|
255
|
-
def top
|
256
|
-
@item
|
257
|
-
end
|
258
|
-
end
|
259
|
-
</ruby>
|
260
|
-
|
261
|
-
<pre>
|
262
|
-
$ spec stack_spec.rb -f s
|
263
|
-
|
264
|
-
A new stack
|
265
|
-
- should be empty
|
266
|
-
|
267
|
-
An empty stack
|
268
|
-
- should not be empty after 'push'
|
269
|
-
|
270
|
-
A stack with one item
|
271
|
-
- should return top when you send it 'top'
|
272
|
-
|
273
|
-
Finished in 0.000737 seconds
|
274
|
-
|
275
|
-
3 contexts, 4 specifications, 0 failures
|
276
|
-
</pre>
|
277
|
-
|
278
|
-
So this time we were able to refactor, and in doing so not only reduce the duplication but also reduce the size of the stack class. Sweet.
|
279
|
-
|
280
|
-
To be continued...
|
281
|
-
|
282
|
-
<a href="stack_02.html">Previous</a> |
|
283
|
-
<a href="stack_04.html">Next</a>
|