rspec 0.5.4 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/CHANGES +10 -2
  2. data/EXAMPLES.rd +34 -0
  3. data/README +1 -1
  4. data/Rakefile +23 -28
  5. data/bin/spec +0 -1
  6. data/doc/src/core_team.page +18 -9
  7. data/doc/src/tools/rails.page +71 -5
  8. data/doc/src/tools/rake.page +5 -8
  9. data/doc/src/tools/rcov.page +14 -5
  10. data/doc/src/tools/spec.page +33 -18
  11. data/doc/src/tutorials/meta.info +6 -1
  12. data/doc/src/tutorials/stack.rb +1 -1
  13. data/doc/src/tutorials/stack_01.page +2 -0
  14. data/doc/src/tutorials/stack_02.page +6 -4
  15. data/doc/src/tutorials/stack_03.page +7 -15
  16. data/doc/src/tutorials/stack_04.page +39 -78
  17. data/doc/src/tutorials/stack_05.page +1 -1
  18. data/doc/src/tutorials/stack_spec.rb +2 -18
  19. data/lib/spec/rake/rcov_verify.rb +2 -2
  20. data/lib/spec/rake/spectask.rb +4 -9
  21. data/lib/spec/runner.rb +1 -0
  22. data/lib/spec/runner/backtrace_tweaker.rb +2 -0
  23. data/lib/spec/runner/context.rb +7 -5
  24. data/lib/spec/runner/context_runner.rb +4 -4
  25. data/lib/spec/runner/kernel_ext.rb +1 -1
  26. data/lib/spec/runner/spec_matcher.rb +39 -0
  27. data/lib/spec/runner/specification.rb +3 -3
  28. data/lib/spec/version.rb +1 -1
  29. data/test/spec/api/helper/equality_test.rb +1 -1
  30. data/test/spec/runner/backtrace_tweaker_test.rb +15 -9
  31. data/test/spec/runner/context_matching_test.rb +35 -0
  32. data/test/spec/runner/context_runner_test.rb +16 -16
  33. data/test/spec/runner/context_test.rb +0 -21
  34. data/test/spec/runner/spec_matcher_test.rb +42 -0
  35. data/test/spec/runner/specification_test.rb +9 -4
  36. metadata +12 -10
  37. data/doc/reference/rspec reference.page +0 -0
  38. data/test/rcov/rcov_testtask.rb +0 -46
@@ -220,5 +220,7 @@ Finished in 0.000256 seconds
220
220
 
221
221
  And thus we have completed our first specification: "A new stack should be empty"
222
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
+
223
225
  <a href="stack_02.html">Next</a>
224
226
 
@@ -1,10 +1,10 @@
1
1
  h2. A Simple Stack
2
2
 
3
- h3. An Empty Stack
3
+ h3. Choosing the next Specification
4
4
 
5
- So now we know that when you first create a stack it is empty. What's next? We could make some more specifications about a new stack, but the fact that it is an empty stack is more interesting from a behavioural perspective than a new stack. So let's start talking about the behaviour of an <em>empty</em> stack.
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
6
 
7
- We all know the standard messages we want on a stack: some variation of push, pop and top. What should happen when we send 'push' to an empty stack? The usual first move is to specify that it has a size of 1, but we don't have a <code>size</code> method, nor do we want one if we can avoid it. We can, however, specify that it is no longer empty after a push.
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
8
 
9
9
  <ruby>
10
10
  context "An empty stack" do
@@ -111,7 +111,9 @@ Finished in 0.000427 seconds
111
111
  2 contexts, 2 specifications, 0 failures
112
112
  </pre>
113
113
 
114
- Remember, add a little bit at a time, run the specs and resolve name errors (these are like compilation failures in java and C#). Next we set our expectation:
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:
115
117
 
116
118
  <ruby>
117
119
  context "An empty stack" do
@@ -4,13 +4,13 @@ h3. What to specify next?
4
4
 
5
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
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 object we just pushed!
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
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 object, while pop also removes it from the stack.
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
10
 
11
11
  h3. Send top to a stack with one item
12
12
 
13
- Start by adding a new context in stack_spec.rb. Remember, the context is an object (or set of objects) in a known state, so we'll go ahead and add the setup right away
13
+ Start by adding a new context and spec in stack_spec.rb.
14
14
 
15
15
  <ruby>
16
16
  context "A stack with one item" do
@@ -26,7 +26,6 @@ A new stack
26
26
  - should be empty
27
27
 
28
28
  An empty stack
29
- - should keep its mouth shut when you send it 'push'
30
29
  - should not be empty after 'push'
31
30
 
32
31
  A stack with one item
@@ -58,7 +57,6 @@ A new stack
58
57
  - should be empty
59
58
 
60
59
  An empty stack
61
- - should keep its mouth shut when you send it 'push'
62
60
  - should not be empty after 'push'
63
61
 
64
62
  A stack with one item
@@ -91,7 +89,6 @@ A new stack
91
89
  - should be empty
92
90
 
93
91
  An empty stack
94
- - should keep its mouth shut when you send it 'push'
95
92
  - should not be empty after 'push'
96
93
 
97
94
  A stack with one item
@@ -124,7 +121,6 @@ A new stack
124
121
  - should be empty
125
122
 
126
123
  An empty stack
127
- - should keep its mouth shut when you send it 'push'
128
124
  - should not be empty after 'push'
129
125
 
130
126
  A stack with one item
@@ -158,7 +154,6 @@ A new stack
158
154
  - should be empty
159
155
 
160
156
  An empty stack
161
- - should keep its mouth shut when you send it 'push'
162
157
  - should not be empty after 'push'
163
158
 
164
159
  A stack with one item
@@ -169,11 +164,11 @@ Finished in 0.000744 seconds
169
164
  3 contexts, 4 specifications, 0 failures
170
165
  </pre>
171
166
 
172
- So now we've hard coded something even more obviously wrong than before. True/false/empty, etc - that was all a bit more subtle. This case is much more obvious. There are a couple of ways to view the problem. One is that we've got this hard coded value. The bigger problem is that we now have duplication between the specs and the code. We want to get rid of it. How do you eliminate duplication? Refactor! And since we have a suite (albeit small) of passing specifications, we can now refactor safely.
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.
173
168
 
174
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.
175
170
 
176
- First, we keep track of the item we add...
171
+ First, we save the item we add and return that from <code>top</code> ...
177
172
 
178
173
  <ruby>
179
174
  class Stack
@@ -200,7 +195,6 @@ A new stack
200
195
  - should be empty
201
196
 
202
197
  An empty stack
203
- - should keep its mouth shut when you send it 'push'
204
198
  - should not be empty after 'push'
205
199
 
206
200
  A stack with one item
@@ -211,7 +205,7 @@ Finished in 0.000846 seconds
211
205
  3 contexts, 4 specifications, 0 failures
212
206
  </pre>
213
207
 
214
- Now let's use that to determine "emptiness"...
208
+ Now let's use the item to determine "emptiness"...
215
209
 
216
210
  <ruby>
217
211
  class Stack
@@ -238,7 +232,6 @@ A new stack
238
232
  - should be empty
239
233
 
240
234
  An empty stack
241
- - should keep its mouth shut when you send it 'push'
242
235
  - should not be empty after 'push'
243
236
 
244
237
  A stack with one item
@@ -272,7 +265,6 @@ A new stack
272
265
  - should be empty
273
266
 
274
267
  An empty stack
275
- - should keep its mouth shut when you send it 'push'
276
268
  - should not be empty after 'push'
277
269
 
278
270
  A stack with one item
@@ -283,7 +275,7 @@ Finished in 0.000737 seconds
283
275
  3 contexts, 4 specifications, 0 failures
284
276
  </pre>
285
277
 
286
- You may wonder why we chose to refactor at this point, but we didn't the first time we had duplication between the tests and code. Remember the first step we took? It was to return <code>true</code> for <code>empty?</code>. Though more subtle than "one item", that was duplication between the specs and the code. The problem was that we didn't have any other methods on the stack that we could use. We would have had to contrive implementation that we had no specification for. At this point, however, we were able to make use of data we were passing into the the stack from the specification, so we were in a position to change things without adding things we hadn't specified yet.
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.
287
279
 
288
280
  To be continued...
289
281
 
@@ -1,4 +1,4 @@
1
- h2. A Simple Stack - when a new expectation passes
1
+ h2. A Simple Stack - when a new expectation passes - IN PROGRESS - DISREGARD THIS PAGE
2
2
 
3
3
  At this point stack_spec.rb should look like this...
4
4
 
@@ -20,10 +20,6 @@ context "An empty stack" do
20
20
  @stack = Stack.new
21
21
  end
22
22
 
23
- specify "should keep its mouth shut when you send it 'push'" do
24
- lambda { @stack.push Object.new }.should.not.raise
25
- end
26
-
27
23
  specify "should not be empty after 'push'" do
28
24
  @stack.push 37
29
25
  @stack.should_not_be_empty
@@ -67,7 +63,6 @@ A new stack
67
63
  - should be empty
68
64
 
69
65
  An empty stack
70
- - should keep its mouth shut when you send it 'push'
71
66
  - should not be empty after 'push'
72
67
 
73
68
  A stack with one item
@@ -78,7 +73,11 @@ Finished in 0.000741 seconds
78
73
  3 contexts, 4 specifications, 0 failures
79
74
  </pre>
80
75
 
81
- Again, a really nice feature of using the <code>--format specdoc</code> option (<code>-f s</code> for short) is that you can easily see all of the contexts you've specified and the balance of specifications between contexts. As your specification is evolving, this helps to inform you regarding the next step. Comparing "An empty stack" to "A stack with one item", there are a couple of ways to go here, which is nice (better than having no obvious next step). On "An empty stack", we know two things about the 'push' message. Let's balance "A stack with one item" with that, and specify the 'emptiness' of the stack after 'top'.
76
+ Again, a really nice feature of using the <code>--format specdoc</code> option (<code>-f s</code> for short) is that you can see the big picture very clearly.
77
+
78
+ Look closely at the "An empty stack" context. We say that it "should not be empty after 'push'". Does that strike you as confusing? It may not, but if you think about it, we're taking an object in one state ("An empty stack"), changing its state by pushing an item onto it and THEN setting an expectation about it. You could argue that we're not really specifying behaviour of an empty stack at all here, but rather behaviour of a stack with one element when you call push.
79
+
80
+ So let's add that spec to "A stack with one item".
82
81
 
83
82
  <ruby>
84
83
  context "A stack with one item" do
@@ -86,11 +85,12 @@ context "A stack with one item" do
86
85
  @stack = Stack.new
87
86
  @stack.push "one item"
88
87
  end
88
+
89
+ specify "should return top when you send it 'top'" do
90
+ @stack.top.should_equal "one item"
91
+ end
89
92
 
90
- ...
91
-
92
- specify "should not be empty after 'top'" do
93
- @stack.top
93
+ specify "should not be empty" do
94
94
  @stack.should_not_be_empty
95
95
  end
96
96
  end
@@ -103,101 +103,62 @@ A new stack
103
103
  - should be empty
104
104
 
105
105
  An empty stack
106
- - should keep its mouth shut when you send it 'push'
107
106
  - should not be empty after 'push'
108
107
 
109
108
  A stack with one item
110
109
  - should return top when you send it 'top'
111
- - should not be empty after 'top'
110
+ - should not be empty
112
111
 
113
- Finished in 0.000853 seconds
112
+ Finished in 0.000849 seconds
114
113
 
115
- 3 contexts, 5 specifications, 0 failures
114
+ 3 contexts, 4 specifications, 0 failures
116
115
  </pre>
117
116
 
118
- This one passes right away. This situation comes up a lot as you progress through a specification. You add a specification and the expectations are already met. You never saw the failure, so how do you know that you wrote the specification correctly, or that it exercises the code that you want to exercise? We should see the expectation fail before moving on. So now the question is what is the best approach to making it fail? Well, we want to see the failure so that when we make a change to the code to make it pass, we know that we've exercised the right place in the code from the spec. To ensure that, we really want to make the change in the code.
119
-
120
- In this case, the simplest way to approach this is to return <code>true</code> from <code>empty?</code>.
117
+ And now we can just remove "An empty spec" from stack_spec.rb.
121
118
 
122
119
  <ruby>
123
- class Stack
124
- def empty?
125
- true
126
- #@item.nil?
127
- end
128
- def push item
129
- @item = item
120
+ require 'stack'
121
+
122
+ context "A new stack" do
123
+ setup do
124
+ @stack = Stack.new
130
125
  end
131
- def top
132
- @item
126
+ specify "should be empty" do
127
+ @stack.should_be_empty
133
128
  end
134
129
  end
135
- </ruby>
136
- <br>
137
- <pre>
138
- $ spec stack_spec.rb -f s -s "A stack with one item should not be empty after 'top'"
139
-
140
- A stack with one item
141
- - should not be empty after 'top' (FAILED - 1)
142
-
143
- 1)
144
- ExpectationNotMetError in 'A stack with one item should not be empty after 'top''
145
- Stack #<Stack:0x36ad18 @item="one item"> should not be empty
146
- ./stack_spec.rb:39:in `should not be empty after 'top''
147
-
148
- Finished in 0.000398 seconds
149
130
 
150
- 1 context, 1 specification, 1 failure
151
- </pre>
152
-
153
- Here we used the <code>-s</code> option, which allows you to specify a single specification by supplying its full name (context name + space + spec name).
154
-
155
- The failure tells us that there was an ExpectationNotMetError, as we expected. Revert the code ...
131
+ context "A stack with one item" do
132
+ setup do
133
+ @stack = Stack.new
134
+ @stack.push "one item"
135
+ end
156
136
 
157
- <ruby>
158
- class Stack
159
- def empty?
160
- @item.nil?
137
+ specify "should return top when you send it 'top'" do
138
+ @stack.top.should_equal "one item"
139
+ end
140
+
141
+ specify "should not be empty" do
142
+ @stack.should_not_be_empty
161
143
  end
162
- ...
163
144
  end
164
145
  </ruby>
165
-
166
- ... run the single spec ...
167
-
168
- <pre>
169
- $ spec stack_spec.rb -f s -s "A stack with one item should not be empty after 'top'"
170
-
171
- A stack with one item
172
- - should not be empty after 'top'
173
-
174
- Finished in 0.00028 seconds
175
-
176
- 1 context, 1 specification, 0 failures
177
- </pre>
178
-
179
- ... and then run all the specs ...
180
-
146
+ <br>
181
147
  <pre>
182
148
  $ spec stack_spec.rb -f s
183
149
 
184
150
  A new stack
185
151
  - should be empty
186
152
 
187
- An empty stack
188
- - should keep its mouth shut when you send it 'push'
189
- - should not be empty after 'push'
190
-
191
153
  A stack with one item
192
154
  - should return top when you send it 'top'
193
- - should not be empty after 'top'
155
+ - should not be empty
194
156
 
195
- Finished in 0.000859 seconds
157
+ Finished in 0.000565 seconds
196
158
 
197
- 3 contexts, 5 specifications, 0 failures
159
+ 2 contexts, 3 specifications, 0 failures
198
160
  </pre>
199
161
 
200
- ... and we can press on with confidence that the last spec we added is really exercising and setting expectations on the code we want it to.
162
+ So keep your eye on the contexts and specifications as they evolve. Don't be afraid to move specs around. There are many different benefits that we get from these executable specifications. One is that it helps us to drive code, resulting in very simple and well tested code. Another very important benefit is that future developers can look at them and understand how to use a component (module, class, method, etc). Keep them in mind. "They" may even be you!
201
163
 
202
- <a href="stack_03.html">Previous</a> |
203
- <a href="stack_05.html">Next</a>
164
+ <a href="stack_03.html">Previous</a>
@@ -1,4 +1,4 @@
1
- h2. A Simple Stack - Moving specs between contexts
1
+ h2. A Simple Stack - Moving specs between contexts - IN PROGRESS - DISREGARD THIS PAGE
2
2
 
3
3
  So we now have the following spec.
4
4
 
@@ -4,38 +4,22 @@ context "A new stack" do
4
4
  setup do
5
5
  @stack = Stack.new
6
6
  end
7
-
8
7
  specify "should be empty" do
9
8
  @stack.should_be_empty
10
9
  end
11
10
  end
12
11
 
13
- context "An empty stack" do
14
- setup do
15
- @stack = Stack.new
16
- end
17
-
18
- specify "should keep its mouth shut when you send it 'push'" do
19
- lambda { @stack.push Object.new }.should.not.raise
20
- end
21
- end
22
-
23
12
  context "A stack with one item" do
24
13
  setup do
25
14
  @stack = Stack.new
26
15
  @stack.push "one item"
27
16
  end
28
17
 
29
- specify "should not be empty" do
30
- @stack.should_not_be_empty
31
- end
32
-
33
18
  specify "should return top when you send it 'top'" do
34
19
  @stack.top.should_equal "one item"
35
20
  end
36
21
 
37
- specify "should not be empty after 'top'" do
38
- @stack.top
22
+ specify "should not be empty" do
39
23
  @stack.should_not_be_empty
40
24
  end
41
- end
25
+ end
@@ -10,7 +10,7 @@ module RCov
10
10
  # Defaults to 'coverage/index.html'
11
11
  attr_accessor :index_html
12
12
 
13
- # Whether or not to output details
13
+ # Whether or not to output details. Defaults to true.
14
14
  attr_accessor :verbose
15
15
 
16
16
  # The threshold value (in percent) for coverage. If the
@@ -21,7 +21,7 @@ module RCov
21
21
  def initialize(name=:rcov_verify)
22
22
  @name = name
23
23
  @index_html = 'coverage/index.html'
24
- @verbose = false
24
+ @verbose = true
25
25
  yield self if block_given?
26
26
  raise "Threshold must be set" if @threshold.nil?
27
27
  define
@@ -82,6 +82,9 @@ module Rake
82
82
  lib_path = @libs.join(File::PATH_SEPARATOR)
83
83
  desc "Run specs" + (@name==:spec ? "" : " for #{@name}")
84
84
  task @name do
85
+ specs = file_list
86
+ raise "No spec files found." if specs.empty?
87
+
85
88
  spec = File.dirname(__FILE__) + '/../../../bin/spec'
86
89
  file_prefix = @rcov ? " -- " : ""
87
90
  interpreter = @rcov ? "rcov" : "ruby"
@@ -94,7 +97,7 @@ module Rake
94
97
  " \"#{spec}\" " +
95
98
  " #{@spec_opts.join(' ')} " +
96
99
  file_prefix +
97
- file_list.collect { |fn| "\"#{fn}\"" }.join(' ') +
100
+ specs.collect { |fn| "\"#{fn}\"" }.join(' ') +
98
101
  redirect
99
102
  end
100
103
  self
@@ -111,14 +114,6 @@ module Rake
111
114
  end
112
115
  end
113
116
 
114
- def find_file(fn) # :nodoc:
115
- $LOAD_PATH.each do |path|
116
- file_path = File.join(path, "#{fn}.rb")
117
- return file_path if File.exist? file_path
118
- end
119
- nil
120
- end
121
-
122
117
  def run(interpreter, *args, &block)
123
118
  if Hash === args.last
124
119
  options = args.pop
data/lib/spec/runner.rb CHANGED
@@ -10,3 +10,4 @@ require 'spec/runner/base_text_formatter'
10
10
  require 'spec/runner/progress_bar_formatter'
11
11
  require 'spec/runner/rdoc_formatter'
12
12
  require 'spec/runner/specdoc_formatter'
13
+ require 'spec/runner/spec_matcher'
@@ -27,6 +27,8 @@ module Spec
27
27
  line = nil if line =~ /\/lib\/spec\/api\//
28
28
  line = nil if line =~ /\/lib\/spec\/runner\//
29
29
  line = nil if line =~ /bin\/spec:/
30
+ # TextMate's Ruby plugin
31
+ line = nil if line =~ /Ruby\.tmbundle\/Support\/tmruby.rb:/
30
32
  line
31
33
  end
32
34
  error.backtrace.compact!
@@ -32,17 +32,19 @@ module Spec
32
32
  @specifications.length
33
33
  end
34
34
 
35
- def matches? name
36
- return false unless name =~ /^#{@name} /
35
+ def matches? name, matcher=nil
36
+ matcher ||= SpecMatcher.new name, @name
37
37
  @specifications.each do |spec|
38
- return true if spec.matches? name[(@name.length + 1)..-1]
38
+ return true if spec.matches_matcher? matcher
39
39
  end
40
40
  return false
41
41
  end
42
42
 
43
- def isolate name
43
+ def run_single_spec name
44
+ return if @name == name
45
+ matcher = SpecMatcher.new name, @name
44
46
  @specifications.reject! do |spec|
45
- !spec.matches? name[(@name.length + 1)..-1]
47
+ !spec.matches_matcher? matcher
46
48
  end
47
49
  end
48
50
  end