Skip to content

Commit 838d982

Browse files
authored
Correct references in architecture docs (#233)
References to specific parts of the code are now invalid since the reorganization.
1 parent a13efa5 commit 838d982

File tree

2 files changed

+58
-54
lines changed

2 files changed

+58
-54
lines changed

docs/contributors/architecture/how-rspec-works.md

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ First, we will review several concepts in RSpec: [^fn1]
8686
The default formatter is "progress",
8787
[set in the configuration object][rspec-default-formatter-set],
8888
which maps to an instance of [`RSpec::Core::Formatters::ProgressFormatter`](https://github.com/rspec/rspec-core/blob/v3.13.0/lib/rspec/core/formatters/progress_formatter.rb).
89-
- [Notifications](https://github.com/rspec/rspec-core/blob/v3.13.0/lib/rspec/core/notifications.rb)
89+
- **[Notifications](https://github.com/rspec/rspec-core/blob/v3.13.0/lib/rspec/core/notifications.rb)**
9090
represent events that occur while running tests,
9191
such as "these tests failed"
9292
or "this test was skipped".
@@ -114,43 +114,45 @@ First, we will review several concepts in RSpec: [^fn1]
114114

115115
Given the above, RSpec performs the following sequence of events:
116116

117+
<!--prettier-ignore-start -->
118+
117119
1. The developer adds an failing assertion to a test using the following forms
118120
(filling in `<actual value>`, `<matcher>`, `<block>`, and `<args...>` appropriately):
119-
- `expect(<actual value>).to <matcher>(<args...>)`
120-
- `expect { <block> }.to <matcher>(<args...>)`
121-
- `expect(<actual value>).not_to <matcher>(<args...>)`
122-
- `expect { <block> }.not_to <matcher>(<args...>)`
121+
- `expect(<actual value>).to <matcher>(<args...>)`
122+
- `expect { <block> }.to <matcher>(<args...>)`
123+
- `expect(<actual value>).not_to <matcher>(<args...>)`
124+
- `expect { <block> }.not_to <matcher>(<args...>)`
123125
1. The developer runs the test using the `rspec` executable.
124126
1. The `rspec` executable [calls `RSpec::Core::Runner.invoke`][rspec-core-runner-call].
125127
1. Skipping a few steps, `RSpec::Core::Runner#run_specs` is called,
126128
which [runs all tests by surrounding them in a call to `RSpec::Core::Reporter#report`][rspec-reporter-report-call].
127129
1. Skipping a few more steps, [`RSpec::Core::Example#run` is called to run the current example][rspec-core-example-run-call].
128130
1. From here one of two paths is followed
129131
depending on whether the assertion is positive (`.to`) or negative (`.not_to`).
130-
- If the assertion is positive:
131-
1. Within the test,
132-
after `expect` is called to build a `RSpec::Expectations::ExpectationTarget`,
133-
[the `to` method calls `RSpec::Expectations::PositiveExpectationHandler.handle_matcher`][rspec-positive-expectation-handler-handle-matcher-call].
134-
1. The matcher is then used to know
135-
whether the assertion passes or fails:
136-
`PositiveExpectationHandler`
137-
[calls the `matches?` method on the matcher][rspec-positive-expectation-handler-matcher-matches].
138-
1. Assuming that `matches?` returns false,
139-
`PositiveExpectationHandler` then [calls `RSpec::Expectations::ExpectationHelper.handle_failure`][rspec-expectation-helper-handle-failure-call-positive],
140-
telling it to get the positive failure message from the matcher
141-
by calling `failure_message`.
142-
- If the assertion is negative:
143-
1. Within the test,
144-
after `expect` is called to build a `RSpec::Expectations::ExpectationTarget`,
145-
[the `not_to` method calls `RSpec::Expectations::NegativeExpectationHandler.handle_matcher`][rspec-negative-expectation-handler-handle-matcher-call].
146-
1. The matcher is then used to know
147-
whether the assertion passes or fails:
148-
`NegativeExpectationHandler`,
149-
[calls the `does_not_match?` method on the matcher][rspec-negative-expectation-handler-matcher-does-not-match].
150-
1. Assuming that `does_not_match?` returns false,
151-
`NegativeExpectationHandler` then [calls `RSpec::Expectations::ExpectationHelper.handle_failure`][via `NegativeExpectationHandler`][rspec-expectation-helper-handle-failure-call-negative],
152-
telling it to get the negative failure message from the matcher
153-
by calling `failure_message_when_negated`.
132+
- If the assertion is positive:
133+
1. Within the test,
134+
after `expect` is called to build a `RSpec::Expectations::ExpectationTarget`,
135+
[the `to` method calls `RSpec::Expectations::PositiveExpectationHandler.handle_matcher`][rspec-positive-expectation-handler-handle-matcher-call].
136+
1. The matcher is then used to know
137+
whether the assertion passes or fails:
138+
`PositiveExpectationHandler`
139+
[calls the `matches?` method on the matcher][rspec-positive-expectation-handler-matcher-matches].
140+
1. Assuming that `matches?` returns false,
141+
`PositiveExpectationHandler` then [calls `RSpec::Expectations::ExpectationHelper.handle_failure`][rspec-expectation-helper-handle-failure-call-positive],
142+
telling it to get the positive failure message from the matcher
143+
by calling `failure_message`.
144+
- If the assertion is negative:
145+
1. Within the test,
146+
after `expect` is called to build a `RSpec::Expectations::ExpectationTarget`,
147+
[the `not_to` method calls `RSpec::Expectations::NegativeExpectationHandler.handle_matcher`][rspec-negative-expectation-handler-handle-matcher-call].
148+
1. The matcher is then used to know
149+
whether the assertion passes or fails:
150+
`NegativeExpectationHandler`,
151+
[calls the `does_not_match?` method on the matcher][rspec-negative-expectation-handler-matcher-does-not-match].
152+
1. Assuming that `does_not_match?` returns false,
153+
`NegativeExpectationHandler` then [calls `RSpec::Expectations::ExpectationHelper.handle_failure`][via `NegativeExpectationHandler`][rspec-expectation-helper-handle-failure-call-negative],
154+
telling it to get the negative failure message from the matcher
155+
by calling `failure_message_when_negated`.
154156
1. `RSpec::Expectations::ExpectationHelper.handle_failure` [calls `RSpec::Expectations.fail_with`][rspec-expectations-fail-with-call].
155157
1. `RSpec::Expectations.fail_with` [creates a diff using `RSpec::Matchers::MultiMatcherDiff`,
156158
wraps it in an exception,
@@ -192,6 +194,8 @@ Given the above, RSpec performs the following sequence of events:
192194
the error and backtrace,
193195
and other pertinent details.
194196

197+
<!--prettier-ignore-end -->
198+
195199
[^fn1]: Note that the analysis of the RSpec source code in this document is accurate as of RSpec v3.13.0, released February 4, 2024.
196200

197201
[rspec-exp-syntax]: https://github.com/rspec/rspec-expectations/blob/v3.13.0/lib/rspec/expectations/syntax.rb#L73

docs/contributors/architecture/how-super-diff-works.md

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
## SuperDiff's cast of characters
44

5-
- An **inspection tree builder** (or, casually, an _inspector_)
5+
- An **inspection tree builder**
66
makes use of an **inspection tree**
77
to generate a multi-line textual representation of an object,
8-
similar to PrettyPrinter in Ruby or AwesomePrint,
8+
similar to PrettyPrinter in the Ruby standard library or the AwesomePrint gem,
99
but more appropriate for showing within a diff.
1010
- An **operation tree builder** makes a comparison between two objects
1111
(the "expected" vs. the "actual")
12-
and generates an **operation tree** to represent the differences.
13-
- An operation tree is made up of **operations**,
12+
and generates an operation tree to represent the differences.
13+
- An **operation tree** is made up of **operations**,
1414
which designate differences in the inner parts of the two objects.
15-
Those differences can be of type _delete_, _insert_, or _change_.
15+
Those differences can be of type _delete_, _insert_, _change_, or _noop_.
1616
Since objects can be nested,
1717
some operations can have children operations themselves,
1818
hence the tree.
@@ -33,9 +33,9 @@
3333

3434
As described in ["How RSpec works"](./how-rspec-works.md#what-rspec-does),
3535
when an assertion in a test fails —
36-
which happens when a matcher whose `matches?` method returns `false`
36+
which happens when a matcher whose `#matches?` method returns `false`
3737
is passed to `expect(...).to`,
38-
or when a matcher whose `does_not_match?` method returns `true`
38+
or when a matcher whose `#does_not_match?` method returns `true`
3939
is passed to `expect(...).not_to`
4040
RSpec will call the `RSpec::Expectations::ExpectationHelper#handle_failure` method,
4141
which will call `RSpec::Expectations.fail_with`.
@@ -60,7 +60,7 @@ in order to integrate fully with RSpec.
6060
the gem needs to provide intelligent diffing
6161
for all kinds of built-in matchers.
6262
Many matchers in RSpec are marked as non-diffable —
63-
their `diffable?` method returns `false`
63+
their `#diffable?` method returns `false`
6464
causing RSpec to not show a diff after the matcher's failure message
6565
in the failure output.
6666
The `contain_exactly` matcher is one such example.
@@ -88,7 +88,7 @@ Here are all of the places that SuperDiff patches RSpec:
8888
(to turn off syntax highlighting for code,
8989
as it interferes with the previous patches)
9090
- `RSpec::Support::ObjectFormatter`
91-
(to use SuperDiff's object inspectors)
91+
(to use SuperDiff's object inspection logic)
9292
- `RSpec::Matchers::ExpectedsForMultipleDiffs`
9393
(to add a key above the diff,
9494
add spacing around the diff,
@@ -109,10 +109,11 @@ Once a test fails
109109
and RSpec delegates to SuperDiff's differ,
110110
this sequence of events occurs:
111111

112-
1. `SuperDiff::Differs::Main.call` is called with a pair of values: `expected` and `actual`.
113-
This method looks for a differ that is suitable for the pair
114-
among a set of defaults and the list of differs registered via SuperDiff's configuration.
115-
It does this by calling `.applies_to?` on each,
112+
1. `SuperDiff.diff` is called with a pair of values: `expected` and `actual`.
113+
This method delegates to `SuperDiff::Core::DifferDispatcher.call`,
114+
which looks for a differ via `SuperDiff.configuration`
115+
which is suitable for the pair.
116+
It does this by calling `.applies_to?` on each one,
116117
passing the `expected` and `actual`;
117118
the first differ for whom this method returns `true` wins.
118119
(This is a common pattern throughout the codebase.)
@@ -121,15 +122,15 @@ this sequence of events occurs:
121122
although this is sometimes overridden.
122123
1. Once a differ is found,
123124
its `.call` method is called.
124-
Since all differs inherit from `SuperDiff::Differs::Base`,
125+
Since all differs inherit from `SuperDiff::Core::AbstractDiffer`,
125126
`.call` always builds an operation tree,
126127
but the type of operation tree to build
127128
— or, more specifically, the operation tree builder subclass —
128129
is determined by the differ itself,
129-
via the `operation_tree_builder_class` method.
130+
via the `#operation_tree_builder_class` method.
130131
For instance,
131-
`SuperDiff::Differs::Array` uses a `SuperDiff::OperationTreeBuilder::Array`,
132-
`SuperDiff::Differs::Hash` uses a `SuperDiff::OperationTreeBuilder::Hash`,
132+
`SuperDiff::Basic::Differs::Array` uses a `SuperDiff::Basic::OperationTreeBuilders::Array`,
133+
`SuperDiff::Basic::Differs::Hash` uses a `SuperDiff::Basic::OperationTreeBuilders::Hash`,
133134
etc.
134135
1. Once the differ has an operation tree builder,
135136
the differ calls `.call` on it
@@ -140,15 +141,15 @@ this sequence of events occurs:
140141
find the differences between them,
141142
and represent those differences as operations.
142143
An operation may be one of four types:
143-
`insert`, `delete`, `change`, or `noop`.
144+
`:insert`, `:delete`, `:change`, or `:noop`.
144145
In the case of collections —
145146
which covers most types of values —
146147
the diff is performed recursively.
147148
This means that just as collections can have multiple levels,
148149
so too can operation trees.
149150
1. Once the differ has an operation tree,
150-
it then calls `to_diff` on it.
151-
This method is defined in `SuperDiff::OperationTrees::Base`,
151+
it then calls `#to_diff` on it.
152+
This method is defined in `SuperDiff::Core::AbstractOperationTree`,
152153
and it starts by first flattening the tree.
153154
1. This means that we need an operation tree flattener class.
154155
Like differs,
@@ -165,22 +166,21 @@ this sequence of events occurs:
165166
1. Once the operation tree has been flattened,
166167
then if the user has configured the gem to do so,
167168
a step is performed to look for unchanged lines
168-
(that is, operations of type `noop`)
169+
(that is, operations of type `:noop`)
169170
and _elide_ them —
170171
collapse them in such a way that the surrounding context is still visible.
171172
1. Once a set of elided lines is obtained,
172-
the operation tree runs them through a formatter —
173-
so called `TieredLinesFormatter`
173+
the operation tree runs them through `SuperDiff::Core::TieredLinesFormatter`,
174174
which will add the `-`s and `+`s along with splashes of color
175175
to create the final format you see at the very end.
176176

177177
In summary:
178178

179179
```mermaid
180180
graph TB
181-
DiffersMain["Differs::Main"] -- Differs --> Differ;
181+
DifferDispatcher -- Configured differs --> Differ;
182182
Differ -- Operation tree builder --> OperationTree[Operation tree];
183183
OperationTree -- Operation tree flattener --> Lines;
184184
Lines -- Tiered lines elider --> ElidedLines[Elided lines];
185-
ElidedLines -- Tiered lines formatter --> FinalDiff[Final diff];
185+
ElidedLines -- Tiered lines formatter --> FinalDiff[Diff string];
186186
```

0 commit comments

Comments
 (0)