Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 896291a

Browse files
committed
Merge pull request #1898 from rspec/add-scope-docs
README improvements
2 parents 4d19d2e + 82bd95e commit 896291a

File tree

1 file changed

+136
-19
lines changed

1 file changed

+136
-19
lines changed

README.md

Lines changed: 136 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ rspec-core provides the structure for writing executable examples of how your
44
code should behave, and an `rspec` command with tools to constrain which
55
examples get run and tailor the output.
66

7-
## install
7+
## Install
88

99
gem install rspec # for rspec-core, rspec-expectations, rspec-mocks
1010
gem install rspec-core # for rspec-core only
@@ -14,12 +14,12 @@ Want to run against the `master` branch? You'll need to include the dependent
1414
RSpec repos as well. Add the following to your `Gemfile`:
1515

1616
```ruby
17-
%w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
17+
%w[rspec rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
1818
gem lib, :git => "git://github.com/rspec/#{lib}.git", :branch => 'master'
1919
end
2020
```
2121

22-
## basic structure
22+
## Basic Structure
2323

2424
RSpec uses the words "describe" and "it" so we can express concepts like a conversation:
2525

@@ -30,13 +30,15 @@ RSpec uses the words "describe" and "it" so we can express concepts like a conve
3030
RSpec.describe Order do
3131
it "sums the prices of its line items" do
3232
order = Order.new
33+
3334
order.add_entry(LineItem.new(:item => Item.new(
3435
:price => Money.new(1.11, :USD)
3536
)))
3637
order.add_entry(LineItem.new(:item => Item.new(
3738
:price => Money.new(2.22, :USD),
3839
:quantity => 2
3940
)))
41+
4042
expect(order.total).to eq(Money.new(5.55, :USD))
4143
end
4244
end
@@ -49,7 +51,7 @@ Under the hood, an example group is a class in which the block passed to
4951
`describe` is evaluated. The blocks passed to `it` are evaluated in the
5052
context of an _instance_ of that class.
5153

52-
## nested groups
54+
## Nested Groups
5355

5456
You can also declare nested nested groups using the `describe` or `context`
5557
methods:
@@ -70,7 +72,10 @@ RSpec.describe Order do
7072
end
7173
```
7274

73-
## aliases
75+
Nested groups are subclasses of the outer example group class, providing
76+
the inheritance semantics you'd want for free.
77+
78+
## Aliases
7479

7580
You can declare example groups using either `describe` or `context`.
7681
For a top level example group, `describe` and `context` are available
@@ -81,7 +86,7 @@ patching.
8186
You can declare examples within a group using any of `it`, `specify`, or
8287
`example`.
8388

84-
## shared examples and contexts
89+
## Shared Examples and Contexts
8590

8691
Declare a shared example group using `shared_examples`, and then include it
8792
in any group using `include_examples`.
@@ -111,7 +116,7 @@ pretty much the same as `shared_examples` and `include_examples`, providing
111116
more accurate naming when you share hooks, `let` declarations, helper methods,
112117
etc, but no examples.
113118

114-
## metadata
119+
## Metadata
115120

116121
rspec-core stores a metadata hash with every example and group, which
117122
contains their descriptions, the locations at which they were
@@ -162,26 +167,106 @@ RSpec.describe Hash do
162167
end
163168
```
164169

165-
## the `rspec` command
170+
## A Word on Scope
171+
172+
RSpec has two scopes:
173+
174+
* **Example Group**: Example groups are defined by a `describe` or
175+
`context` block, which is eagerly evaluated when the spec file is
176+
loaded. The block is evaluated in the context of a subclass of
177+
`RSpec::Core::ExampleGroup`, or a subclass of the parent example group
178+
when you're nesting them.
179+
* **Example**: Examples -- typically defined by an `it` block -- and any other
180+
blocks with per-example semantics -- such as a `before(:example)` hook -- are
181+
evaluated in the context of
182+
an _instance_ of the example group class to which the example belongs.
183+
Examples are _not_ executed when the spec file is loaded; instead,
184+
RSpec waits to run any examples until all spec files have been loaded,
185+
at which point it can apply filtering, randomization, etc.
186+
187+
To make this more concrete, consider this code snippet:
188+
189+
``` ruby
190+
RSpec.describe "Using an array as a stack" do
191+
def build_stack
192+
[]
193+
end
194+
195+
before(:example) do
196+
@stack = build_stack
197+
end
198+
199+
it 'is initially empty' do
200+
expect(@stack).to be_empty
201+
end
202+
203+
context "after an item has been pushed" do
204+
before(:example) do
205+
@stack.push :item
206+
end
207+
208+
it 'allows the pushed item to be popped' do
209+
expect(@stack.pop).to eq(:item)
210+
end
211+
end
212+
end
213+
```
214+
215+
Under the covers, this is (roughly) equivalent to:
216+
217+
``` ruby
218+
class UsingAnArrayAsAStack < RSpec::Core::ExampleGroup
219+
def build_stack
220+
[]
221+
end
222+
223+
def before_example_1
224+
@stack = build_stack
225+
end
226+
227+
def it_is_initially_empty
228+
expect(@stack).to be_empty
229+
end
230+
231+
class AfterAnItemHasBeenPushed < self
232+
def before_example_2
233+
@stack.push :item
234+
end
235+
236+
def it_allows_the_pushed_item_to_be_popped
237+
expect(@stack.pop).to eq(:item)
238+
end
239+
end
240+
end
241+
```
242+
243+
To run these examples, RSpec would (roughly) do the following:
244+
245+
``` ruby
246+
example_1 = UsingAnArrayAsAStack.new
247+
example_1.before_example_1
248+
example_1.it_is_initially_empty
249+
250+
example_2 = UsingAnArrayAsAStack::AfterAnItemHasBeenPushed.new
251+
example_2.before_example_1
252+
example_2.before_example_2
253+
example_2.it_allows_the_pushed_item_to_be_popped
254+
```
255+
256+
## The `rspec` Command
166257

167258
When you install the rspec-core gem, it installs the `rspec` executable,
168259
which you'll use to run rspec. The `rspec` command comes with many useful
169260
options.
170261
Run `rspec --help` to see the complete list.
171262

172-
## store command line options `.rspec`
263+
## Store Command Line Options `.rspec`
173264

174265
You can store command line options in a `.rspec` file in the project's root
175266
directory, and the `rspec` command will read them as though you typed them on
176267
the command line.
177268

178-
## autotest integration
179-
180-
rspec-core no longer ships with an Autotest extension, if you require Autotest
181-
integration, please use the `rspec-autotest` gem and see [rspec/rspec-autotest](https://github.com/rspec/rspec-autotest)
182-
for details
183-
184-
## get started
269+
## Get Started
185270

186271
Start with a simple example of behavior you expect from your system. Do
187272
this before you write any implementation code:
@@ -204,13 +289,12 @@ $ rspec spec/calculator_spec.rb
204289
./spec/calculator_spec.rb:1: uninitialized constant Calculator
205290
```
206291

207-
Implement the simplest solution:
292+
Address the failure by defining a skeleton of the `Calculator` class:
208293

209294
```ruby
210295
# in lib/calculator.rb
211296
class Calculator
212-
def add(a,b)
213-
a + b
297+
def add(a, b)
214298
end
215299
end
216300
```
@@ -223,6 +307,39 @@ Be sure to require the implementation file in the spec:
223307
require "calculator"
224308
```
225309

310+
Now run the spec again, and watch the expectation fail:
311+
312+
```
313+
$ rspec spec/calculator_spec.rb
314+
F
315+
316+
Failures:
317+
318+
1) Calculator#add returns the sum of its arguments
319+
Failure/Error: expect(Calculator.new.add(1, 2)).to eq(3)
320+
321+
expected: 3
322+
got: nil
323+
324+
(compared using ==)
325+
# ./spec/calcalator_spec.rb:6:in `block (3 levels) in <top (required)>'
326+
327+
Finished in 0.00131 seconds (files took 0.10968 seconds to load)
328+
1 example, 1 failure
329+
330+
Failed examples:
331+
332+
rspec ./spec/calcalator_spec.rb:5 # Calculator#add returns the sum of its arguments
333+
```
334+
335+
Implement the simplest solution, by changing the definition of `Calculator#add` to:
336+
337+
```ruby
338+
def add(a, b)
339+
a + b
340+
end
341+
```
342+
226343
Now run the spec again, and watch it pass:
227344

228345
```

0 commit comments

Comments
 (0)