Skip to content
Newer
Older
100644 831 lines (712 sloc) 28.6 KB
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
1 RSpec::Support.require_rspec_support 'recursive_const_methods'
2
bcb1dfa @dchelimsky change top-level module from Rspec to RSpec
dchelimsky authored
3 module RSpec
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
4 module Core
b9bd7df @bootstraponline Add example_group.remove_example and example_group.add_example
bootstraponline authored
5 # rubocop:disable Metrics/ClassLength
d024dc9 @dchelimsky rdoc - use the {name} syntax for links [ci skip]
dchelimsky authored
6 # ExampleGroup and {Example} are the main structural elements of
5fc29a1 @yous Fix grammer
yous authored
7 # rspec-core. Consider this example:
480f419 @dchelimsky rename ClassMethods/InstanceMethods to ExampleGroupMethods/ExampleMet…
dchelimsky authored
8 #
9 # describe Thing do
10 # it "does something" do
11 # end
12 # end
13 #
14 # The object returned by `describe Thing` is a subclass of ExampleGroup.
15 # The object returned by `it "does something"` is an instance of Example,
16 # which serves as a wrapper for an instance of the ExampleGroup in which it
17 # is declared.
3951d7c @myronmarston Improve docs.
myronmarston authored
18 #
19 # Example group bodies (e.g. `describe` or `context` blocks) are evaluated
20 # in the context of a new subclass of ExampleGroup. Individual examples are
0ecabf9 @yous Keep comment line length to 80
yous authored
21 # evaluated in the context of an instance of the specific ExampleGroup
22 # subclass to which they belong.
a443297 @myronmarston Improve docs some more.
myronmarston authored
23 #
24 # Besides the class methods defined here, there are other interesting macros
0ecabf9 @yous Keep comment line length to 80
yous authored
25 # defined in {Hooks}, {MemoizedHelpers::ClassMethods} and
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
26 # {SharedExampleGroup}. There are additional instance methods available to
27 # your examples defined in {MemoizedHelpers} and {Pending}.
6cbbaa7 @spicycode Renamed spec/core/behaviour -> spec/core/example_group
spicycode authored
28 class ExampleGroup
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
29 extend Hooks
17782b0 @dchelimsky easier on the eyes
dchelimsky authored
30
0c70d63 @exviva Combine Let and Subject modules into one
exviva authored
31 include MemoizedHelpers
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
32 extend MemoizedHelpers::ClassMethods
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
33 include Pending
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
34 extend SharedExampleGroup
e9f9556 @spicycode Initial metadata reorg, still needs cleanup
spicycode authored
35
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
36 # @private
37 def self.idempotently_define_singleton_method(name, &definition)
38 (class << self; self; end).module_exec do
3932d82 Check if method belongs to singleton_class before removing it
Alex Kwiatkowski and Ryan Ong authored
39 remove_method(name) if method_defined?(name) && instance_method(name).owner == self
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
40 define_method(name, &definition)
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
41 end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
42 end
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
43
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
44 # @!group Metadata
45
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
46 # The [Metadata](Metadata) object associated with this group.
47 # @see Metadata
48 def self.metadata
a1a3dc4 @myronmarston Improve perf of metadata-based shared group inclusion.
myronmarston authored
49 @metadata ||= nil
50 end
51
52 # Temporarily replace the provided metadata.
53 # Intended primarily to allow an example group's singleton class
54 # to return the metadata of the example that it exists for. This
55 # is necessary for shared example group inclusion to work properly
56 # with singleton example groups.
57 # @private
58 def self.with_replaced_metadata(meta)
59 orig_metadata = metadata
60 @metadata = meta
61 yield
62 ensure
63 @metadata = orig_metadata
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
64 end
65
66 # @private
67 # @return [Metadata] belonging to the parent of a nested {ExampleGroup}
68 def self.superclass_metadata
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
69 @superclass_metadata ||= superclass.respond_to?(:metadata) ? superclass.metadata : nil
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
70 end
71
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
72 # @private
73 def self.delegate_to_metadata(*names)
74 names.each do |name|
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
75 idempotently_define_singleton_method(name) { metadata.fetch(name) }
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
76 end
77 end
763eaab @dchelimsky better messages for xit, xspecify, xexample
dchelimsky authored
78
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
79 delegate_to_metadata :described_class, :file_path, :location
80
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
81 # @return [String] the current example group description
82 def self.description
83 description = metadata[:description]
84 RSpec.configuration.format_docstrings_block.call(description)
85 end
86
87 # Returns the class or module passed to the `describe` method (or alias).
88 # Returns nil if the subject is not a class or module.
89 # @example
90 # describe Thing do
91 # it "does something" do
92 # described_class == Thing
93 # end
94 # end
95 #
96 def described_class
97 self.class.described_class
98 end
99
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
100 # @!endgroup
101
102 # @!group Defining Examples
103
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
104 # @private
105 # @macro [attach] define_example_method
3951d7c @myronmarston Improve docs.
myronmarston authored
106 # @!scope class
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
107 # @overload $1
108 # @overload $1(&example_implementation)
109 # @param example_implementation [Block] The implementation of the example.
110 # @overload $1(doc_string, *metadata_keys, metadata={})
111 # @param doc_string [String] The example's doc string.
112 # @param metadata [Hash] Metadata for the example.
113 # @param metadata_keys [Array<Symbol>] Metadata tags for the example.
114 # Will be transformed into hash entries with `true` values.
115 # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation)
116 # @param doc_string [String] The example's doc string.
117 # @param metadata [Hash] Metadata for the example.
118 # @param metadata_keys [Array<Symbol>] Metadata tags for the example.
119 # Will be transformed into hash entries with `true` values.
120 # @param example_implementation [Block] The implementation of the example.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
121 # @yield [Example] the example object
3951d7c @myronmarston Improve docs.
myronmarston authored
122 # @example
123 # $1 do
124 # end
125 #
126 # $1 "does something" do
127 # end
128 #
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
129 # $1 "does something", :slow, :uses_js do
130 # end
131 #
3951d7c @myronmarston Improve docs.
myronmarston authored
132 # $1 "does something", :with => 'additional metadata' do
133 # end
134 #
135 # $1 "does something" do |ex|
136 # # ex is the Example object that contains metadata about the example
137 # end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
138 def self.define_example_method(name, extra_options={})
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
139 idempotently_define_singleton_method(name) do |*all_args, &block|
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
140 desc, *args = *all_args
55d699a @myronmarston Fix `:pending` metadata to always work.
myronmarston authored
141
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
142 options = Metadata.build_hash_from(args)
143 options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
144 options.update(extra_options)
145
42f8694 @myronmarston Refactor example creation.
myronmarston authored
146 example = RSpec::Core::Example.new(self, desc, options, block)
147 examples << example
148 example
43ec3a8 @dchelimsky RDoc improvements for shared examples, Example, and Procsy.
dchelimsky authored
149 end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
150 end
921a744 @dchelimsky more refactoring
dchelimsky authored
151
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
152 # Defines an example within a group.
153 define_example_method :example
154 # Defines an example within a group.
3951d7c @myronmarston Improve docs.
myronmarston authored
155 # This is the primary API to define a code example.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
156 define_example_method :it
157 # Defines an example within a group.
3951d7c @myronmarston Improve docs.
myronmarston authored
158 # Useful for when your docstring does not read well off of `it`.
159 # @example
160 # RSpec.describe MyClass do
161 # specify "#do_something is deprecated" do
162 # # ...
163 # end
164 # end
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
165 define_example_method :specify
166
5fc29a1 @yous Fix grammer
yous authored
167 # Shortcut to define an example with `:focus => true`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
168 # @see example
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
169 define_example_method :focus, :focus => true
5fc29a1 @yous Fix grammer
yous authored
170 # Shortcut to define an example with `:focus => true`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
171 # @see example
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
172 define_example_method :fexample, :focus => true
5fc29a1 @yous Fix grammer
yous authored
173 # Shortcut to define an example with `:focus => true`.
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
174 # @see example
175 define_example_method :fit, :focus => true
5fc29a1 @yous Fix grammer
yous authored
176 # Shortcut to define an example with `:focus => true`.
fbcceb2 @myronmarston Add fspecify and fexample for parity with fit.
myronmarston authored
177 # @see example
178 define_example_method :fspecify, :focus => true
5fc29a1 @yous Fix grammer
yous authored
179 # Shortcut to define an example with `:skip => 'Temporarily skipped with xexample'`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
180 # @see example
181 define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
5fc29a1 @yous Fix grammer
yous authored
182 # Shortcut to define an example with `:skip => 'Temporarily skipped with xit'`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
183 # @see example
184 define_example_method :xit, :skip => 'Temporarily skipped with xit'
5fc29a1 @yous Fix grammer
yous authored
185 # Shortcut to define an example with `:skip => 'Temporarily skipped with xspecify'`.
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
186 # @see example
187 define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
3951d7c @myronmarston Improve docs.
myronmarston authored
188 # Shortcut to define an example with `:skip => true`
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
189 # @see example
190 define_example_method :skip, :skip => true
3951d7c @myronmarston Improve docs.
myronmarston authored
191 # Shortcut to define an example with `:pending => true`
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
192 # @see example
193 define_example_method :pending, :pending => true
43ec3a8 @dchelimsky RDoc improvements for shared examples, Example, and Procsy.
dchelimsky authored
194
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
195 # @!endgroup
196
197 # @!group Defining Example Groups
198
909fd04 @myronmarston Refactor example group macros.
myronmarston authored
199 # @private
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
200 # @macro [attach] define_example_group_method
3951d7c @myronmarston Improve docs.
myronmarston authored
201 # @!scope class
2e27245 @myronmarston Fix docs for example/example_group alias methods.
myronmarston authored
202 # @overload $1
203 # @overload $1(&example_group_definition)
204 # @param example_group_definition [Block] The definition of the example group.
205 # @overload $1(doc_string, *metadata_keys, metadata={}, &example_implementation)
206 # @param doc_string [String] The group's doc string.
207 # @param metadata [Hash] Metadata for the group.
208 # @param metadata_keys [Array<Symbol>] Metadata tags for the group.
209 # Will be transformed into hash entries with `true` values.
210 # @param example_group_definition [Block] The definition of the example group.
7a72f38 @dchelimsky rdoc
dchelimsky authored
211 #
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
212 # Generates a subclass of this example group which inherits
213 # everything except the examples themselves.
214 #
215 # @example
7a72f38 @dchelimsky rdoc
dchelimsky authored
216 #
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
217 # RSpec.describe "something" do # << This describe method is defined in
218 # # << RSpec::Core::DSL, included in the
219 # # << global namespace (optional)
7a72f38 @dchelimsky rdoc
dchelimsky authored
220 # before do
221 # do_something_before
222 # end
223 #
224 # let(:thing) { Thing.new }
225 #
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
226 # $1 "attribute (of something)" do
7a72f38 @dchelimsky rdoc
dchelimsky authored
227 # # examples in the group get the before hook
228 # # declared above, and can access `thing`
229 # end
230 # end
231 #
232 # @see DSL#describe
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
233 def self.define_example_group_method(name, metadata={})
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
234 idempotently_define_singleton_method(name) do |*args, &example_group_block|
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
235 thread_data = RSpec::Support.thread_local_data
a56d9e8 @xaviershay Prevent creating an isolated context when already inside a context.
xaviershay authored
236 top_level = self == ExampleGroup
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
237
a56d9e8 @xaviershay Prevent creating an isolated context when already inside a context.
xaviershay authored
238 if top_level
239 if thread_data[:in_example_group]
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
240 raise "Creating an isolated context from within a context is " \
241 "not allowed. Change `RSpec.#{name}` to `#{name}` or " \
a56d9e8 @xaviershay Prevent creating an isolated context when already inside a context.
xaviershay authored
242 "move this to a top-level scope."
243 end
244
245 thread_data[:in_example_group] = true
246 end
247
248 begin
249
250 description = args.shift
251 combined_metadata = metadata.dup
252 combined_metadata.merge!(args.pop) if args.last.is_a? Hash
253 args << combined_metadata
254
255 subclass(self, description, args, &example_group_block).tap do |child|
256 children << child
257 end
258
259 ensure
260 thread_data.delete(:in_example_group) if top_level
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
261 end
000a5d5 @myronmarston Allow hashes and symbols to be used as an implicit subject.
myronmarston authored
262 end
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
263
264 RSpec::Core::DSL.expose_example_group_alias(name)
4b4ff67 @dchelimsky Refactor example group hierarchy into a tree
dchelimsky authored
265 end
266
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
267 define_example_group_method :example_group
268
0ecabf9 @yous Keep comment line length to 80
yous authored
269 # An alias of `example_group`. Generally used when grouping examples by a
270 # thing you are describing (e.g. an object, class or method).
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
271 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
272 define_example_group_method :describe
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
273
274 # An alias of `example_group`. Generally used when grouping examples
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
275 # contextually (e.g. "with xyz", "when xyz" or "if xyz").
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
276 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
277 define_example_group_method :context
17a3b5a @dchelimsky small refactorings
dchelimsky authored
278
e156ec1 @myronmarston Further doc improvements.
myronmarston authored
279 # Shortcut to temporarily make an example group skipped.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
280 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
281 define_example_group_method :xdescribe, :skip => "Temporarily skipped with xdescribe"
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
282
e156ec1 @myronmarston Further doc improvements.
myronmarston authored
283 # Shortcut to temporarily make an example group skipped.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
284 # @see example_group
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
285 define_example_group_method :xcontext, :skip => "Temporarily skipped with xcontext"
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
286
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
287 # Shortcut to define an example group with `:focus => true`.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
288 # @see example_group
2d1004f @myronmarston Remove `:focused` metadata.
myronmarston authored
289 define_example_group_method :fdescribe, :focus => true
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
290
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
291 # Shortcut to define an example group with `:focus => true`.
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
292 # @see example_group
2d1004f @myronmarston Remove `:focused` metadata.
myronmarston authored
293 define_example_group_method :fcontext, :focus => true
59590ef @myronmarston Add additional example group aliases.
myronmarston authored
294
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
295 # @!endgroup
296
297 # @!group Including Shared Example Groups
298
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
299 # @private
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
300 # @macro [attach] define_nested_shared_group_method
301 # @!scope class
302 #
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
303 # @see SharedExampleGroup
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
304 def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
350fe50 @myronmarston Make example group alias definitions idempotent w/ no warnings.
myronmarston authored
305 idempotently_define_singleton_method(new_name) do |name, *args, &customization_block|
5fc29a1 @yous Fix grammer
yous authored
306 # Pass :caller so the :location metadata is set properly.
307 # Otherwise, it'll be set to the next line because that's
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
308 # the block's source_location.
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
309 group = example_group("#{report_label} #{name}", :caller => (the_caller = caller)) do
310 find_and_eval_shared("examples", name, the_caller.first, *args, &customization_block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
311 end
312 group.metadata[:shared_group_name] = name
313 group
314 end
315 end
316
317 # Generates a nested example group and includes the shared content
318 # mapped to `name` in the nested group.
319 define_nested_shared_group_method :it_behaves_like, "behaves like"
320 # Generates a nested example group and includes the shared content
321 # mapped to `name` in the nested group.
322 define_nested_shared_group_method :it_should_behave_like
323
324 # Includes shared content mapped to `name` directly in the group in which
325 # it is declared, as opposed to `it_behaves_like`, which creates a nested
0ecabf9 @yous Keep comment line length to 80
yous authored
326 # group. If given a block, that block is also eval'd in the current
327 # context.
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
328 #
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
329 # @see SharedExampleGroup
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
330 def self.include_context(name, *args, &block)
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
331 find_and_eval_shared("context", name, caller.first, *args, &block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
332 end
333
334 # Includes shared content mapped to `name` directly in the group in which
335 # it is declared, as opposed to `it_behaves_like`, which creates a nested
0ecabf9 @yous Keep comment line length to 80
yous authored
336 # group. If given a block, that block is also eval'd in the current
337 # context.
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
338 #
9653904 @myronmarston Revert "Reify shared example groups as a first-class type."
myronmarston authored
339 # @see SharedExampleGroup
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
340 def self.include_examples(name, *args, &block)
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
341 find_and_eval_shared("examples", name, caller.first, *args, &block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
342 end
343
b9bd7df @bootstraponline Add example_group.remove_example and example_group.add_example
bootstraponline authored
344 # Clear memoized values when adding/removing examples
345 # @private
346 def self.reset_memoized
347 @descendant_filtered_examples = nil
348 @_descendants = nil
349 @parent_groups = nil
358733a @myronmarston When filtering, do not consider declaration lines from other files.
myronmarston authored
350 @declaration_locations = nil
b9bd7df @bootstraponline Add example_group.remove_example and example_group.add_example
bootstraponline authored
351 end
352
353 # Adds an example to the example group
354 def self.add_example(example)
355 reset_memoized
356 examples << example
357 end
358
359 # Removes an example from the example group
360 def self.remove_example(example)
361 reset_memoized
362 examples.delete example
363 end
364
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
365 # @private
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
366 def self.find_and_eval_shared(label, name, inclusion_location, *args, &customization_block)
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
367 shared_block = RSpec.world.shared_example_group_registry.find(parent_groups, name)
368
369 unless shared_block
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
370 raise ArgumentError, "Could not find shared #{label} #{name.inspect}"
371 end
372
a1a3dc4 @myronmarston Improve perf of metadata-based shared group inclusion.
myronmarston authored
373 SharedExampleGroupInclusionStackFrame.with_frame(name, Metadata.relative_path(inclusion_location)) do
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
374 module_exec(*args, &shared_block)
375 module_exec(&customization_block) if customization_block
376 end
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
377 end
378
6ccf70b @myronmarston Provide doc groupings.
myronmarston authored
379 # @!endgroup
380
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
381 # @private
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
382 def self.subclass(parent, description, args, &example_group_block)
8363707 @dchelimsky Add specs to show after(:each) is run
dchelimsky authored
383 subclass = Class.new(parent)
b8acc5c @myronmarston Refactor example group aliasing.
myronmarston authored
384 subclass.set_it_up(description, *args, &example_group_block)
8d89dbe @myronmarston Prefer *_exec over *_eval.
myronmarston authored
385 subclass.module_exec(&example_group_block) if example_group_block
a43d59d @myronmarston Delay inclusion of `LetDefinitions` module.
myronmarston authored
386
387 # The LetDefinitions module must be included _after_ other modules
e795f1a @cupakromer Minor typo and trailing whitespace fix.
cupakromer authored
388 # to ensure that it takes precedence when there are name collisions.
a43d59d @myronmarston Delay inclusion of `LetDefinitions` module.
myronmarston authored
389 # Thus, we delay including it until after the example group block
390 # has been eval'd.
690a294 @alindeman Small refactor to add intention revealing message
alindeman authored
391 MemoizedHelpers.define_helpers_on(subclass)
a43d59d @myronmarston Delay inclusion of `LetDefinitions` module.
myronmarston authored
392
8363707 @dchelimsky Add specs to show after(:each) is run
dchelimsky authored
393 subclass
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
394 end
395
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
396 # @private
f251894 @myronmarston Remove unnecessary shift/unshift.
myronmarston authored
397 def self.set_it_up(description, *args, &example_group_block)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
398 # Ruby 1.9 has a bug that can lead to infinite recursion and a
399 # SystemStackError if you include a module in a superclass after
400 # including it in a subclass: https://gist.github.com/845896
0ecabf9 @yous Keep comment line length to 80
yous authored
401 # To prevent this, we must include any modules in
402 # RSpec::Core::ExampleGroup before users create example groups and have
403 # a chance to include the same module in a subclass of
404 # RSpec::Core::ExampleGroup. So we need to configure example groups
405 # here.
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
406 ensure_example_groups_are_configured
407
408 user_metadata = Metadata.build_hash_from(args)
409
410 @metadata = Metadata::ExampleGroupHash.create(
057e729 @myronmarston Add ids to examples and groups.
myronmarston authored
411 superclass_metadata, user_metadata,
412 superclass.method(:next_runnable_index_for),
413 description, *args, &example_group_block
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
414 )
5dc5088 @myronmarston Assign example group constant earlier.
myronmarston authored
415 ExampleGroups.assign_const(self)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
416
f8e555d @samphippen Add `currently_executing_a_context_hook?` to ExampleGroup
samphippen authored
417 @currently_executing_a_context_hook = false
418
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
419 hooks.register_globals(self, RSpec.configuration.hooks)
1160685 @myronmarston Remove unneeded layer of indirection.
myronmarston authored
420 RSpec.configuration.configure_group(self)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
421 end
422
423 # @private
424 def self.examples
425 @examples ||= []
426 end
427
428 # @private
429 def self.filtered_examples
430 RSpec.world.filtered_examples[self]
431 end
432
433 # @private
434 def self.descendant_filtered_examples
e3cd4b7 @yous Reduce line length to 130
yous authored
435 @descendant_filtered_examples ||= filtered_examples +
15de144 @myronmarston Prefer `flat_map` to `inject`.
myronmarston authored
436 FlatMap.flat_map(children, &:descendant_filtered_examples)
e41ae45 @myronmarston Organize ExampleGroup methods into a logical order.
myronmarston authored
437 end
438
439 # @private
b84371e @dchelimsky Move filtering examples to world, reducing feature envy
dchelimsky authored
440 def self.children
a755aa6 @alindeman Example groups can override the default ordering.
alindeman authored
441 @children ||= []
b84371e @dchelimsky Move filtering examples to world, reducing feature envy
dchelimsky authored
442 end
443
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
444 # @private
057e729 @myronmarston Add ids to examples and groups.
myronmarston authored
445 def self.next_runnable_index_for(file)
446 if self == ExampleGroup
447 RSpec.world.num_example_groups_defined_in(file)
448 else
449 children.count + examples.count
450 end + 1
451 end
452
453 # @private
fa42f5b @dchelimsky it's descendant, silly
dchelimsky authored
454 def self.descendants
15de144 @myronmarston Prefer `flat_map` to `inject`.
myronmarston authored
455 @_descendants ||= [self] + FlatMap.flat_map(children, &:descendants)
b84371e @dchelimsky Move filtering examples to world, reducing feature envy
dchelimsky authored
456 end
457
9e8b6b9 @myronmarston Don't override #ancestors.
myronmarston authored
458 ## @private
459 def self.parent_groups
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
460 @parent_groups ||= ancestors.select { |a| a < RSpec::Core::ExampleGroup }
ff4df6b @dchelimsky select from Ruby's ancestors instead of building up our own
dchelimsky authored
461 end
462
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
463 # @private
bc11555 @myronmarston Fix group profile output regressions introduced in #1971.
myronmarston authored
464 def self.top_level?
465 superclass == ExampleGroup
466 end
467
468 # @private
622a4b7 @myronmarston Fix how RSpec::Matchers is included in RSpec::Core::Example group to …
myronmarston authored
469 def self.ensure_example_groups_are_configured
2b2ef40 @dchelimsky Change class level instance var to class's class var so the block is
dchelimsky authored
470 unless defined?(@@example_groups_configured)
622a4b7 @myronmarston Fix how RSpec::Matchers is included in RSpec::Core::Example group to …
myronmarston authored
471 RSpec.configuration.configure_mock_framework
472 RSpec.configuration.configure_expectation_framework
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
473 # rubocop:disable Style/ClassVars
2b2ef40 @dchelimsky Change class level instance var to class's class var so the block is
dchelimsky authored
474 @@example_groups_configured = true
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
475 # rubocop:enable Style/ClassVars
622a4b7 @myronmarston Fix how RSpec::Matchers is included in RSpec::Core::Example group to …
myronmarston authored
476 end
477 end
478
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
479 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
480 def self.before_context_ivars
481 @before_context_ivars ||= {}
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
482 end
483
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
484 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
485 def self.store_before_context_ivars(example_group_instance)
c1356c7 @myronmarston Fewer array allocations.
myronmarston authored
486 each_instance_variable_for_example(example_group_instance) do |ivar|
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
487 before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar)
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
488 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
489 end
e9f9556 @spicycode Initial metadata reorg, still needs cleanup
spicycode authored
490
f8e555d @samphippen Add `currently_executing_a_context_hook?` to ExampleGroup
samphippen authored
491 # Returns true if a `before(:context)` or `after(:context)`
492 # hook is currently executing.
493 def self.currently_executing_a_context_hook?
494 @currently_executing_a_context_hook
495 end
496
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
497 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
498 def self.run_before_context_hooks(example_group_instance)
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
499 set_ivars(example_group_instance, superclass_before_context_ivars)
108649a @myronmarston Include caller in warning msg for `let` usage in `before(:all)`.
myronmarston authored
500
f8e555d @samphippen Add `currently_executing_a_context_hook?` to ExampleGroup
samphippen authored
501 @currently_executing_a_context_hook = true
502
ffe00a1 @JoshCheek Make memoized helpers threadsafe
JoshCheek authored
503 ContextHookMemoized::Before.isolate_for_context_hook(example_group_instance) do
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
504 hooks.run(:before, :context, example_group_instance)
49370db @samphippen Ensure before(:all) state is always propagated to after(:all)
samphippen authored
505 end
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
506 ensure
507 store_before_context_ivars(example_group_instance)
f8e555d @samphippen Add `currently_executing_a_context_hook?` to ExampleGroup
samphippen authored
508 @currently_executing_a_context_hook = false
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
509 end
510
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
511 if RUBY_VERSION.to_f >= 1.9
512 # @private
513 def self.superclass_before_context_ivars
514 superclass.before_context_ivars
515 end
516 else # 1.8.7
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
517 # :nocov:
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
518 # @private
519 def self.superclass_before_context_ivars
520 if superclass.respond_to?(:before_context_ivars)
521 superclass.before_context_ivars
522 else
523 # `self` must be the singleton class of an ExampleGroup instance.
524 # On 1.8.7, the superclass of a singleton class of an instance of A
525 # is A's singleton class. On 1.9+, it's A. On 1.8.7, the first ancestor
526 # is A, so we can mirror 1.8.7's behavior here. Note that we have to
527 # search for the first that responds to `before_context_ivars`
528 # in case a module has been included in the singleton class.
529 ancestors.find { |a| a.respond_to?(:before_context_ivars) }.before_context_ivars
530 end
531 end
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
532 # :nocov:
639db76 @myronmarston Run `:context` hooks from shared contexts that apply to one example.
myronmarston authored
533 end
534
84cb5f2 @dchelimsky rdoc
dchelimsky authored
535 # @private
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
536 def self.run_after_context_hooks(example_group_instance)
537 set_ivars(example_group_instance, before_context_ivars)
9e7dcd3 @myronmarston Rescue errors in after(:all) and print them out.
myronmarston authored
538
f8e555d @samphippen Add `currently_executing_a_context_hook?` to ExampleGroup
samphippen authored
539 @currently_executing_a_context_hook = true
540
ffe00a1 @JoshCheek Make memoized helpers threadsafe
JoshCheek authored
541 ContextHookMemoized::After.isolate_for_context_hook(example_group_instance) do
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
542 hooks.run(:after, :context, example_group_instance)
f5930e7 @myronmarston Error rather than warn when `let` accessed in :all hook.
myronmarston authored
543 end
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
544 ensure
545 before_context_ivars.clear
f8e555d @samphippen Add `currently_executing_a_context_hook?` to ExampleGroup
samphippen authored
546 @currently_executing_a_context_hook = false
21d6f6b @dchelimsky make sure before/after(:all) gets run even in subclasses
dchelimsky authored
547 end
548
5fc29a1 @yous Fix grammer
yous authored
549 # Runs all the examples in this group.
2633182 @JonRowe switch NullReporter to not be an instance
JonRowe authored
550 def self.run(reporter=RSpec::Core::NullReporter)
e747c7f @myronmarston Don't purge example groups when a `--fail-fast` failure is hit.
myronmarston authored
551 return if RSpec.world.wants_to_quit
f80e68a @dchelimsky Deprecate add_example_group in formatters
dchelimsky authored
552 reporter.example_group_started(self)
b25fea3 @spicycode gh#21 Resolution, 1 remaining pending test
spicycode authored
553
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
554 should_run_context_hooks = descendant_filtered_examples.any?
20389a4 @dchelimsky ensure the things that happen after the return val is set
dchelimsky authored
555 begin
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
556 run_before_context_hooks(new('before(:context) hook')) if should_run_context_hooks
1012613 @dchelimsky object per example
dchelimsky authored
557 result_for_this_group = run_examples(reporter)
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
558 results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
d6964f7 @dchelimsky Ensure that child groups are run even when there are failures in parent
dchelimsky authored
559 result_for_this_group && results_for_descendants
5c21c76 @xaviershay Remove support for pending in before(:all) hooks.
xaviershay authored
560 rescue Pending::SkipDeclaredInExample => ex
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
561 for_filtered_examples(reporter) { |example| example.skip_with_exception(reporter, ex) }
8e69df1 @myronmarston Groups with `before(:all) { skip }` should pass.
myronmarston authored
562 true
a257d19 @myronmarston Stop rescuing all exceptions.
myronmarston authored
563 rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
564 for_filtered_examples(reporter) { |example| example.fail_with_exception(reporter, ex) }
46cba8f @myronmarston Followups from #2065.
myronmarston authored
565 RSpec.world.wants_to_quit = true if reporter.fail_fast_limit_met?
795c22d @myronmarston Explicitly indicate that the example group failed.
myronmarston authored
566 false
20389a4 @dchelimsky ensure the things that happen after the return val is set
dchelimsky authored
567 ensure
b847426 @myronmarston Refactor how context hooks get run.
myronmarston authored
568 run_after_context_hooks(new('after(:context) hook')) if should_run_context_hooks
4dc8bfb @iromeo Add example_group_finished message to reporter/formatters.
iromeo authored
569 reporter.example_group_finished(self)
20389a4 @dchelimsky ensure the things that happen after the return val is set
dchelimsky authored
570 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
571 end
e9f9556 @spicycode Initial metadata reorg, still needs cleanup
spicycode authored
572
a755aa6 @alindeman Example groups can override the default ordering.
alindeman authored
573 # @private
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
574 def self.ordering_strategy
9b16f3e @myronmarston Refactoring: use `:global` for global ordering.
myronmarston authored
575 order = metadata.fetch(:order, :global)
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
576 registry = RSpec.configuration.ordering_registry
2f1d906 @myronmarston Print a warning when given an unrecognized :order option.
myronmarston authored
577
578 registry.fetch(order) do
579 warn <<-WARNING.gsub(/^ +\|/, '')
580 |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata.
581 | Falling back to configured global ordering.
7a01061 @myronmarston Leverage metadata delegation a bit more.
myronmarston authored
582 | Unrecognized ordering specified at: #{location}
2f1d906 @myronmarston Print a warning when given an unrecognized :order option.
myronmarston authored
583 WARNING
584
9b16f3e @myronmarston Refactoring: use `:global` for global ordering.
myronmarston authored
585 registry.fetch(:global)
2f1d906 @myronmarston Print a warning when given an unrecognized :order option.
myronmarston authored
586 end
587 end
588
589 # @private
7a72f38 @dchelimsky rdoc
dchelimsky authored
590 def self.run_examples(reporter)
10aca90 @myronmarston Simplify ordering API.
myronmarston authored
591 ordering_strategy.order(filtered_examples).map do |example|
0b42695 @xaviershay Move private methods from RSpec to RSpec.world.
xaviershay authored
592 next if RSpec.world.wants_to_quit
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
593 instance = new(example.inspect_output)
b123c6a @myronmarston Make `:example` and `:context` scopes primary.
myronmarston authored
594 set_ivars(instance, before_context_ivars)
7a72f38 @dchelimsky rdoc
dchelimsky authored
595 succeeded = example.run(instance, reporter)
46cba8f @myronmarston Followups from #2065.
myronmarston authored
596 if !succeeded && reporter.fail_fast_limit_met?
c6819f0 @jackscotti Make ExampleGroup stop running examples when appropriate
jackscotti authored
597 RSpec.world.wants_to_quit = true
598 end
7a72f38 @dchelimsky rdoc
dchelimsky authored
599 succeeded
600 end.all?
601 end
602
84cb5f2 @dchelimsky rdoc
dchelimsky authored
603 # @private
5c21c76 @xaviershay Remove support for pending in before(:all) hooks.
xaviershay authored
604 def self.for_filtered_examples(reporter, &block)
605 filtered_examples.each(&block)
135009c @myronmarston Fix before(:all) error handling so that it fails examples in nested g…
myronmarston authored
606
607 children.each do |child|
608 reporter.example_group_started(child)
5c21c76 @xaviershay Remove support for pending in before(:all) hooks.
xaviershay authored
609 child.for_filtered_examples(reporter, &block)
135009c @myronmarston Fix before(:all) error handling so that it fails examples in nested g…
myronmarston authored
610 reporter.example_group_finished(child)
611 end
79273a7 @dnurzynski Fix exit_status after Exception raised in before :all hook
dnurzynski authored
612 false
b25fea3 @spicycode gh#21 Resolution, 1 remaining pending test
spicycode authored
613 end
614
84cb5f2 @dchelimsky rdoc
dchelimsky authored
615 # @private
358733a @myronmarston When filtering, do not consider declaration lines from other files.
myronmarston authored
616 def self.declaration_locations
617 @declaration_locations ||= [Metadata.location_tuple_from(metadata)] +
618 examples.map { |e| Metadata.location_tuple_from(e.metadata) } +
619 FlatMap.flat_map(children, &:declaration_locations)
40d471b @dchelimsky refactor some names, abstactions, scopes, etc
dchelimsky authored
620 end
621
057e729 @myronmarston Add ids to examples and groups.
myronmarston authored
622 # @return [String] the unique id of this example group. Pass
623 # this at the command line to re-run this exact example group.
624 def self.id
625 Metadata.id_from(metadata)
626 end
627
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
628 # @private
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
629 def self.top_level_description
9e8b6b9 @myronmarston Don't override #ancestors.
myronmarston authored
630 parent_groups.last.description
9415f86 @dchelimsky add group.top_level_description
dchelimsky authored
631 end
632
feb5e85 @dchelimsky rdoc - use yard's @private tag to hide a lot of noise. More to go, bu…
dchelimsky authored
633 # @private
6730505 @dchelimsky remove __reset__ from ExampleGroup instance namespace
dchelimsky authored
634 def self.set_ivars(instance, ivars)
d06ffe8 @alex-tan Setup rubocop
alex-tan authored
635 ivars.each { |name, value| instance.instance_variable_set(name, value) }
6730505 @dchelimsky remove __reset__ from ExampleGroup instance namespace
dchelimsky authored
636 end
637
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
638 if RUBY_VERSION.to_f < 1.9
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
639 # :nocov:
1d5020b @benmoss Add missing private doc markers
benmoss authored
640 # @private
c1356c7 @myronmarston Fewer array allocations.
myronmarston authored
641 INSTANCE_VARIABLE_TO_IGNORE = '@__inspect_output'.freeze
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
642 # :nocov:
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
643 else
1d5020b @benmoss Add missing private doc markers
benmoss authored
644 # @private
c1356c7 @myronmarston Fewer array allocations.
myronmarston authored
645 INSTANCE_VARIABLE_TO_IGNORE = :@__inspect_output
646 end
647
648 # @private
649 def self.each_instance_variable_for_example(group)
650 group.instance_variables.each do |ivar|
651 yield ivar unless ivar == INSTANCE_VARIABLE_TO_IGNORE
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
652 end
653 end
654
655 def initialize(inspect_output=nil)
656 @__inspect_output = inspect_output || '(no description provided)'
ffe00a1 @JoshCheek Make memoized helpers threadsafe
JoshCheek authored
657 super() # no args get passed
ffd7492 @kcdragon Add better `inspect` output for ExampleGroup
kcdragon authored
658 end
659
660 # @private
661 def inspect
662 "#<#{self.class} #{@__inspect_output}>"
663 end
13c6674 @myronmarston Provide friendly errors when users call RSpec APIs from the wrong con…
myronmarston authored
664
ab2b613 @myronmarston Got things to work on 1.8.7.
myronmarston authored
665 unless method_defined?(:singleton_class) # for 1.8.7
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
666 # :nocov:
ab2b613 @myronmarston Got things to work on 1.8.7.
myronmarston authored
667 # @private
668 def singleton_class
669 class << self; self; end
670 end
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
671 # :nocov:
ab2b613 @myronmarston Got things to work on 1.8.7.
myronmarston authored
672 end
673
13c6674 @myronmarston Provide friendly errors when users call RSpec APIs from the wrong con…
myronmarston authored
674 # Raised when an RSpec API is called in the wrong scope, such as `before`
675 # being called from within an example rather than from within an example
676 # group block.
677 WrongScopeError = Class.new(NoMethodError)
678
679 def self.method_missing(name, *args)
680 if method_defined?(name)
681 raise WrongScopeError,
682 "`#{name}` is not available on an example group (e.g. a " \
683 "`describe` or `context` block). It is only available from " \
684 "within individual examples (e.g. `it` blocks) or from " \
685 "constructs that run in the scope of an example (e.g. " \
686 "`before`, `let`, etc)."
687 end
688
689 super
690 end
691 private_class_method :method_missing
692
693 private
694
695 def method_missing(name, *args)
696 if self.class.respond_to?(name)
697 raise WrongScopeError,
698 "`#{name}` is not available from within an example (e.g. an " \
699 "`it` block) or from constructs that run in the scope of an " \
700 "example (e.g. `before`, `let`, etc). It is only available " \
701 "on an example group (e.g. a `describe` or `context` block)."
702 end
703
704 super
705 end
ab88b2e @myronmarston Clean up `instance_exec_with_rescue`.
myronmarston authored
706 end
b9bd7df @bootstraponline Add example_group.remove_example and example_group.add_example
bootstraponline authored
707 # rubocop:enable Metrics/ClassLength
6ddb29d @spicycode Lets make ivars not so leaky between examples (WIP)
spicycode authored
708
ab88b2e @myronmarston Clean up `instance_exec_with_rescue`.
myronmarston authored
709 # @private
710 # Unnamed example group used by `SuiteHookContext`.
711 class AnonymousExampleGroup < ExampleGroup
712 def self.metadata
713 {}
e516329 @dchelimsky resolve minor feature envy
dchelimsky authored
714 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
715 end
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
716
717 # Contains information about the inclusion site of a shared example group.
a0f02d0 @myronmarston Improve shared group backtrace in failure output.
myronmarston authored
718 class SharedExampleGroupInclusionStackFrame
719 # @return [String] the name of the shared example group
720 attr_reader :shared_group_name
721 # @return [String] the location where the shared example was included
722 attr_reader :inclusion_location
723
724 def initialize(shared_group_name, inclusion_location)
725 @shared_group_name = shared_group_name
726 @inclusion_location = inclusion_location
727 end
728
729 # @return [String] The {#inclusion_location}, formatted for display by a formatter.
730 def formatted_inclusion_location
731 @formatted_inclusion_location ||= begin
732 RSpec.configuration.backtrace_formatter.backtrace_line(
733 inclusion_location.sub(/(:\d+):in .+$/, '\1')
734 )
735 end
736 end
737
738 # @return [String] Description of this stack frame, in the form used by
739 # RSpec's built-in formatters.
740 def description
741 @description ||= "Shared Example Group: #{shared_group_name.inspect} " \
742 "called from #{formatted_inclusion_location}"
743 end
744
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
745 # @private
746 def self.current_backtrace
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
747 shared_example_group_inclusions.reverse
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
748 end
749
750 # @private
751 def self.with_frame(name, location)
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
752 current_stack = shared_example_group_inclusions
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
753 current_stack << new(name, location)
754 yield
755 ensure
756 current_stack.pop
757 end
6a18dbd @myronmarston Standardize on rspec-support’s thread local data hash.
myronmarston authored
758
759 # @private
760 def self.shared_example_group_inclusions
761 RSpec::Support.thread_local_data[:shared_example_group_inclusions] ||= []
762 end
fdd33ef @myronmarston Add shared group inclusion backtrace to example metadata.
myronmarston authored
763 end
afca728 @spicycode Initial migration of Micronaut to Spec/Core
spicycode authored
764 end
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
765
526ed4e Achieve 100% doc coverage
Adam Farhi authored
766 # @private
767 #
0ecabf9 @yous Keep comment line length to 80
yous authored
768 # Namespace for the example group subclasses generated by top-level
769 # `describe`.
3923c7e @myronmarston Rename UserGroups to ExampleGroups.
myronmarston authored
770 module ExampleGroups
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
771 extend Support::RecursiveConstMethods
772
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
773 def self.assign_const(group)
774 base_name = base_name_for(group)
775 const_scope = constant_scope_for(group)
776 name = disambiguate(base_name, const_scope)
777
778 const_scope.const_set(name, group)
779 end
780
781 def self.constant_scope_for(group)
782 const_scope = group.superclass
380c1bd Prevent load-order issue in constant_scope_for with more explicit use of
Daniela Wellisz authored
783 const_scope = self if const_scope == ::RSpec::Core::ExampleGroup
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
784 const_scope
785 end
786
787 def self.base_name_for(group)
788 return "Anonymous" if group.description.empty?
789
5fc29a1 @yous Fix grammer
yous authored
790 # Convert to CamelCase.
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
791 name = ' ' << group.description
792 name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) do
d7f5e3e @durran Allow Regexp class to be described
durran authored
793 match = ::Regexp.last_match[1]
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
794 match.upcase!
795 match
796 end
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
797
f61bb6f @JonRowe whitespace cleanup
JonRowe authored
798 name.lstrip! # Remove leading whitespace
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
799 name.gsub!(/\W/, ''.freeze) # JRuby, RBX and others don't like non-ascii in const names
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
800
801 # Ruby requires first const letter to be A-Z. Use `Nested`
802 # as necessary to enforce that.
70bc97d @myronmarston Use fewer string allocations when creating the example group constant.
myronmarston authored
803 name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1'.freeze)
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
804
805 name
806 end
807
a0acf2e @JonRowe deal with 1.9.2 issue by appending a _ on all constant names
JonRowe authored
808 if RUBY_VERSION == '1.9.2'
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
809 # :nocov:
a0acf2e @JonRowe deal with 1.9.2 issue by appending a _ on all constant names
JonRowe authored
810 class << self
811 alias _base_name_for base_name_for
812 def base_name_for(group)
813 _base_name_for(group) + '_'
814 end
815 end
816 private_class_method :_base_name_for
76e6976 @myronmarston Exclude version/platform-specific code from simplecov.
myronmarston authored
817 # :nocov:
a0acf2e @JonRowe deal with 1.9.2 issue by appending a _ on all constant names
JonRowe authored
818 end
819
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
820 def self.disambiguate(name, const_scope)
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
821 return name unless const_defined_on?(const_scope, name)
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
822
0ecabf9 @yous Keep comment line length to 80
yous authored
823 # Add a trailing number if needed to disambiguate from an existing
824 # constant.
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
825 name << "_2"
2014378 @jimmycuadra Prevent example groups named "Config" from generating a deprecation w…
jimmycuadra authored
826 name.next! while const_defined_on?(const_scope, name)
4dd5ff5 @myronmarston Give example group classes a friendly const name.
myronmarston authored
827 name
828 end
829 end
98f4077 @spicycode Initial shared behaviour work.
spicycode authored
830 end
Something went wrong with that request. Please try again.