1
1
module RSpec
2
2
module Core
3
3
# Wrapper for an instance of a subclass of {ExampleGroup}. An instance of
4
- # `RSpec::Core::Example` is returned by the {ExampleGroup#example example}
5
- # method exposed to examples, {Hooks#before before} and {Hooks#after after}
6
- # hooks, and yielded to {Hooks#around around} hooks.
4
+ # `RSpec::Core::Example` is returned by example definition methods
5
+ # such as {ExampleGroup.it it} and is yielded to the {ExampleGroup.it it},
6
+ # {Hooks#before before}, {Hooks#after after}, {Hooks#around around},
7
+ # {MemoizedHelpers::ClassMethods#let let} and
8
+ # {MemoizedHelpers::ClassMethods#subject subject} blocks.
7
9
#
8
10
# This allows us to provide rich metadata about each individual
9
11
# example without adding tons of methods directly to the ExampleGroup
@@ -15,17 +17,17 @@ module Core
15
17
# @example
16
18
#
17
19
# RSpec.configure do |config|
18
- # config.before do
20
+ # config.before do |example|
19
21
# log example.description
20
22
# end
21
23
#
22
- # config.after do
24
+ # config.after do |example|
23
25
# log example.description
24
26
# end
25
27
#
26
- # config.around do |ex |
28
+ # config.around do |example |
27
29
# log example.description
28
- # ex .run
30
+ # example .run
29
31
# end
30
32
# end
31
33
#
@@ -38,17 +40,32 @@ module Core
38
40
#
39
41
# @see ExampleGroup
40
42
# @note Example blocks are evaluated in the context of an instance
41
- # of an `ExampleGroup`, not in the context of an instance of `Example`.
43
+ # of an `ExampleGroup`, not in the context of an instance of `Example`.
42
44
class Example
43
45
# @private
44
46
#
45
47
# Used to define methods that delegate to this example's metadata
46
- def self . delegate_to_metadata ( * keys )
47
- keys . each { | key | define_method ( key ) { @metadata [ key ] } }
48
+ def self . delegate_to_metadata ( key )
49
+ define_method ( key ) { @metadata [ key ] }
48
50
end
49
51
50
- delegate_to_metadata :execution_result , :file_path , :full_description ,
51
- :location , :pending , :skip
52
+ # @return [ExecutionResult] represents the result of running this example.
53
+ delegate_to_metadata :execution_result
54
+ # @return [String] the relative path to the file where this example was defined.
55
+ delegate_to_metadata :file_path
56
+ # @return [String] the full description (including the docstrings of
57
+ # all parent example groups).
58
+ delegate_to_metadata :full_description
59
+ # @return [String] the exact source location of this example in a form
60
+ # like `./path/to/spec.rb:17`
61
+ delegate_to_metadata :location
62
+ # @return [Boolean] flag that indicates that the example is not expected to pass.
63
+ # It will be run and will either have a pending result (if a failure occurs)
64
+ # or a failed result (if no failure occurs).
65
+ delegate_to_metadata :pending
66
+ # @return [Boolean] flag that will cause the example to not run.
67
+ # The {ExecutionResult} status will be `:pending`.
68
+ delegate_to_metadata :skip
52
69
53
70
# Returns the string submitted to `example` or its aliases (e.g.
54
71
# `specify`, `it`, etc). If no string is submitted (e.g. `it { is_expected.to
@@ -161,12 +178,10 @@ def run(example_group_instance, reporter)
161
178
RSpec . current_example = nil
162
179
end
163
180
164
- # Wraps a `Proc` and exposes a `run` method for use in {Hooks#around
165
- # around} hooks.
166
- #
167
- # @note Procsy, itself, is not a public API, but we're documenting it
168
- # here to document how to interact with the object yielded to an
169
- # `around` hook.
181
+ # Wraps both a `Proc` and an {Example} for use in {Hooks#around
182
+ # around} hooks. In around hooks we need to yield this special
183
+ # kind of object (rather than the raw {Example}) because when
184
+ # there are multiple `around` hooks we have to wrap them recursively.
170
185
#
171
186
# @example
172
187
#
@@ -178,23 +193,30 @@ def run(example_group_instance, reporter)
178
193
# ex.run # run delegates to ex.call
179
194
# end
180
195
# end
196
+ #
197
+ # @note This class also exposes the instance methods of {Example},
198
+ # proxying them through to the wrapped {Example} instance.
181
199
class Procsy
182
- # The `metadata` of the {Example} instance.
183
- attr_reader :metadata
200
+ # The {Example} instance.
201
+ attr_reader :example
202
+
203
+ Example . public_instance_methods ( false ) . each do |name |
204
+ define_method ( name ) { |*a , &b | @example . __send__ ( name , *a , &b ) }
205
+ end
184
206
185
207
Proc . public_instance_methods ( false ) . each do |name |
186
208
define_method ( name ) { |*a , &b | @proc . __send__ ( name , *a , &b ) }
187
209
end
188
210
alias run call
189
211
190
- def initialize ( metadata , &block )
191
- @metadata = metadata
192
- @proc = block
212
+ def initialize ( example , &block )
213
+ @example = example
214
+ @proc = block
193
215
end
194
216
195
217
# @private
196
218
def wrap ( &block )
197
- self . class . new ( metadata , &block )
219
+ self . class . new ( example , &block )
198
220
end
199
221
end
200
222
@@ -276,7 +298,7 @@ def with_around_example_hooks(&block)
276
298
if around_example_hooks . empty?
277
299
yield
278
300
else
279
- @example_group_class . hooks . run ( :around , :example , self , Procsy . new ( metadata , &block ) )
301
+ @example_group_class . hooks . run ( :around , :example , self , Procsy . new ( self , &block ) )
280
302
end
281
303
rescue Exception => e
282
304
set_exception ( e , "in an `around(:example)` hook" )
0 commit comments