rspec-core 3.8.0 → 3.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +154 -0
  4. data/README.md +20 -20
  5. data/lib/rspec/core/bisect/fork_runner.rb +6 -2
  6. data/lib/rspec/core/bisect/server.rb +1 -1
  7. data/lib/rspec/core/bisect/utilities.rb +12 -1
  8. data/lib/rspec/core/configuration.rb +126 -30
  9. data/lib/rspec/core/did_you_mean.rb +46 -0
  10. data/lib/rspec/core/drb.rb +7 -0
  11. data/lib/rspec/core/example.rb +18 -5
  12. data/lib/rspec/core/example_group.rb +36 -16
  13. data/lib/rspec/core/example_status_persister.rb +2 -2
  14. data/lib/rspec/core/filter_manager.rb +1 -1
  15. data/lib/rspec/core/formatters/console_codes.rb +17 -9
  16. data/lib/rspec/core/formatters/documentation_formatter.rb +35 -3
  17. data/lib/rspec/core/formatters/exception_presenter.rb +40 -12
  18. data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
  19. data/lib/rspec/core/formatters/helpers.rb +9 -1
  20. data/lib/rspec/core/formatters/html_printer.rb +1 -3
  21. data/lib/rspec/core/formatters/html_snippet_extractor.rb +2 -2
  22. data/lib/rspec/core/formatters.rb +12 -2
  23. data/lib/rspec/core/hooks.rb +43 -21
  24. data/lib/rspec/core/invocations.rb +1 -1
  25. data/lib/rspec/core/memoized_helpers.rb +60 -15
  26. data/lib/rspec/core/metadata.rb +2 -3
  27. data/lib/rspec/core/metadata_filter.rb +1 -1
  28. data/lib/rspec/core/option_parser.rb +27 -13
  29. data/lib/rspec/core/ordering.rb +12 -1
  30. data/lib/rspec/core/pending.rb +8 -16
  31. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +2 -4
  32. data/lib/rspec/core/rake_task.rb +22 -2
  33. data/lib/rspec/core/reporter.rb +9 -1
  34. data/lib/rspec/core/runner.rb +16 -3
  35. data/lib/rspec/core/shared_example_group.rb +4 -2
  36. data/lib/rspec/core/version.rb +1 -1
  37. data/lib/rspec/core/world.rb +17 -5
  38. data/lib/rspec/core.rb +27 -0
  39. data.tar.gz.sig +0 -0
  40. metadata +21 -15
  41. metadata.gz.sig +0 -0
@@ -13,13 +13,14 @@ module RSpec
13
13
  # @overload before(scope, &block)
14
14
  # @param scope [Symbol] `:example`, `:context`, or `:suite`
15
15
  # (defaults to `:example`)
16
- # @overload before(scope, conditions, &block)
16
+ # @overload before(scope, *conditions, &block)
17
17
  # @param scope [Symbol] `:example`, `:context`, or `:suite`
18
18
  # (defaults to `:example`)
19
- # @param conditions [Hash]
20
- # constrains this hook to examples matching these conditions e.g.
19
+ # @param conditions [Array<Symbol>, Hash] constrains this hook to
20
+ # examples matching these conditions e.g.
21
21
  # `before(:example, :ui => true) { ... }` will only run with examples
22
- # or groups declared with `:ui => true`.
22
+ # or groups declared with `:ui => true`. Symbols will be transformed
23
+ # into hash entries with `true` values.
23
24
  # @overload before(conditions, &block)
24
25
  # @param conditions [Hash]
25
26
  # constrains this hook to examples matching these conditions e.g.
@@ -59,8 +60,10 @@ module RSpec
59
60
  # before(:example) # Declared in a parent group.
60
61
  # before(:example) # Declared in the current group.
61
62
  #
62
- # If more than one `before` is declared within any one scope, they are run
63
- # in the order in which they are declared.
63
+ # If more than one `before` is declared within any one example group, they
64
+ # are run in the order in which they are declared. Any `around` hooks will
65
+ # execute after `before` context hooks but before any `before` example
66
+ # hook regardless of where they are declared.
64
67
  #
65
68
  # ### Conditions
66
69
  #
@@ -74,11 +77,11 @@ module RSpec
74
77
  # end
75
78
  # end
76
79
  #
77
- # describe Something, :authorized => true do
80
+ # RSpec.describe Something, :authorized => true do
78
81
  # # The before hook will run in before each example in this group.
79
82
  # end
80
83
  #
81
- # describe SomethingElse do
84
+ # RSpec.describe SomethingElse do
82
85
  # it "does something", :authorized => true do
83
86
  # # The before hook will run before this example.
84
87
  # end
@@ -159,7 +162,7 @@ module RSpec
159
162
  #
160
163
  # @example before(:example) declared in an {ExampleGroup}
161
164
  #
162
- # describe Thing do
165
+ # RSpec.describe Thing do
163
166
  # before(:example) do
164
167
  # @thing = Thing.new
165
168
  # end
@@ -171,7 +174,7 @@ module RSpec
171
174
  #
172
175
  # @example before(:context) declared in an {ExampleGroup}
173
176
  #
174
- # describe Parser do
177
+ # RSpec.describe Parser do
175
178
  # before(:context) do
176
179
  # File.open(file_to_parse, 'w') do |f|
177
180
  # f.write <<-CONTENT
@@ -213,13 +216,14 @@ module RSpec
213
216
  # @overload after(scope, &block)
214
217
  # @param scope [Symbol] `:example`, `:context`, or `:suite` (defaults to
215
218
  # `:example`)
216
- # @overload after(scope, conditions, &block)
219
+ # @overload after(scope, *conditions, &block)
217
220
  # @param scope [Symbol] `:example`, `:context`, or `:suite` (defaults to
218
221
  # `:example`)
219
- # @param conditions [Hash]
220
- # constrains this hook to examples matching these conditions e.g.
222
+ # @param conditions [Array<Symbol>, Hash] constrains this hook to
223
+ # examples matching these conditions e.g.
221
224
  # `after(:example, :ui => true) { ... }` will only run with examples
222
- # or groups declared with `:ui => true`.
225
+ # or groups declared with `:ui => true`. Symbols will be transformed
226
+ # into hash entries with `true` values.
223
227
  # @overload after(conditions, &block)
224
228
  # @param conditions [Hash]
225
229
  # constrains this hook to examples matching these conditions e.g.
@@ -260,8 +264,10 @@ module RSpec
260
264
  # after(:suite) # Declared in RSpec.configure.
261
265
  #
262
266
  # This is the reverse of the order in which `before` hooks are run.
263
- # Similarly, if more than one `after` is declared within any one scope,
264
- # they are run in reverse order of that in which they are declared.
267
+ # Similarly, if more than one `after` is declared within any example
268
+ # group, they are run in reverse order of that in which they are declared.
269
+ # Also `around` hooks will run after any `after` example hooks are
270
+ # invoked but before any `after` context hooks.
265
271
  #
266
272
  # @note The `:example` and `:context` scopes are also available as
267
273
  # `:each` and `:all`, respectively. Use whichever you prefer.
@@ -288,13 +294,15 @@ module RSpec
288
294
  # @param scope [Symbol] `:example` (defaults to `:example`)
289
295
  # present for syntax parity with `before` and `after`, but
290
296
  # `:example`/`:each` is the only supported value.
291
- # @overload around(scope, conditions, &block)
297
+ # @overload around(scope, *conditions, &block)
292
298
  # @param scope [Symbol] `:example` (defaults to `:example`)
293
299
  # present for syntax parity with `before` and `after`, but
294
300
  # `:example`/`:each` is the only supported value.
295
- # @param conditions [Hash] constrains this hook to examples matching
296
- # these conditions e.g. `around(:example, :ui => true) { ... }` will
297
- # only run with examples or groups declared with `:ui => true`.
301
+ # @param conditions [Array<Symbol>, Hash] constrains this hook to
302
+ # examples matching these conditions e.g.
303
+ # `around(:example, :ui => true) { ... }` will only run with examples
304
+ # or groups declared with `:ui => true`. Symbols will be transformed
305
+ # into hash entries with `true` values.
298
306
  # @overload around(conditions, &block)
299
307
  # @param conditions [Hash] constrains this hook to examples matching
300
308
  # these conditions e.g. `around(:example, :ui => true) { ... }` will
@@ -304,7 +312,7 @@ module RSpec
304
312
  #
305
313
  # @note the syntax of `around` is similar to that of `before` and `after`
306
314
  # but the semantics are quite different. `before` and `after` hooks are
307
- # run in the context of of the examples with which they are associated,
315
+ # run in the context of the examples with which they are associated,
308
316
  # whereas `around` hooks are actually responsible for running the
309
317
  # examples. Consequently, `around` hooks do not have direct access to
310
318
  # resources that are made available within the examples and their
@@ -329,6 +337,15 @@ module RSpec
329
337
  # around(:example) {|ex| Database.transaction(&ex)}
330
338
  # around(:example) {|ex| FakeFS(&ex)}
331
339
  #
340
+ # ### Order
341
+ #
342
+ # The `around` hooks execute surrounding an example and its hooks.
343
+ #
344
+ # This means after any `before` context hooks, but before any `before`
345
+ # example hooks, and similarly after any `after` example hooks but before
346
+ # any `after` context hooks.
347
+ #
348
+ # They are not a synonym for `before`/`after`.
332
349
  def around(*args, &block)
333
350
  hooks.register :prepend, :around, *args, &block
334
351
  end
@@ -440,6 +457,11 @@ module RSpec
440
457
  "`#{position}(:suite)` hook, registered on an example " \
441
458
  "group, will be ignored."
442
459
  return
460
+ elsif scope == :context && position == :around
461
+ # TODO: consider making this an error in RSpec 4. For SemVer reasons,
462
+ # we are only warning in RSpec 3.
463
+ RSpec.warn_with "WARNING: `around(:context)` hooks are not supported and " \
464
+ "behave like `around(:example)."
443
465
  end
444
466
 
445
467
  hook = HOOK_TYPES[position][scope].new(block, options)
@@ -37,7 +37,7 @@ module RSpec
37
37
  runner, options.args, formatter
38
38
  )
39
39
 
40
- success ? 0 : 1
40
+ runner.exit_code(success)
41
41
  end
42
42
 
43
43
  private
@@ -10,7 +10,7 @@ module RSpec
10
10
  # @note `subject` was contributed by Joe Ferris to support the one-liner
11
11
  # syntax embraced by shoulda matchers:
12
12
  #
13
- # describe Widget do
13
+ # RSpec.describe Widget do
14
14
  # it { is_expected.to validate_presence_of(:name) }
15
15
  # # or
16
16
  # it { should validate_presence_of(:name) }
@@ -23,7 +23,7 @@ module RSpec
23
23
  # @example
24
24
  #
25
25
  # # Explicit declaration of subject.
26
- # describe Person do
26
+ # RSpec.describe Person do
27
27
  # subject { Person.new(:birthdate => 19.years.ago) }
28
28
  # it "should be eligible to vote" do
29
29
  # subject.should be_eligible_to_vote
@@ -32,7 +32,7 @@ module RSpec
32
32
  # end
33
33
  #
34
34
  # # Implicit subject => { Person.new }.
35
- # describe Person do
35
+ # RSpec.describe Person do
36
36
  # it "should be eligible to vote" do
37
37
  # subject.should be_eligible_to_vote
38
38
  # # ^ ^ explicit reference to subject not recommended
@@ -40,7 +40,7 @@ module RSpec
40
40
  # end
41
41
  #
42
42
  # # One-liner syntax - expectation is set on the subject.
43
- # describe Person do
43
+ # RSpec.describe Person do
44
44
  # it { is_expected.to be_eligible_to_vote }
45
45
  # # or
46
46
  # it { should be_eligible_to_vote }
@@ -67,7 +67,7 @@ module RSpec
67
67
  #
68
68
  # @example
69
69
  #
70
- # describe Person do
70
+ # RSpec.describe Person do
71
71
  # it { should be_eligible_to_vote }
72
72
  # end
73
73
  #
@@ -78,6 +78,7 @@ module RSpec
78
78
  # @note If you are using RSpec's newer expect-based syntax you may
79
79
  # want to use `is_expected.to` instead of `should`.
80
80
  def should(matcher=nil, message=nil)
81
+ enforce_value_expectation(matcher, 'should')
81
82
  RSpec::Expectations::PositiveExpectationHandler.handle_matcher(subject, matcher, message)
82
83
  end
83
84
 
@@ -86,7 +87,7 @@ module RSpec
86
87
  #
87
88
  # @example
88
89
  #
89
- # describe Person do
90
+ # RSpec.describe Person do
90
91
  # it { should_not be_eligible_to_vote }
91
92
  # end
92
93
  #
@@ -97,6 +98,7 @@ module RSpec
97
98
  # @note If you are using RSpec's newer expect-based syntax you may
98
99
  # want to use `is_expected.to_not` instead of `should_not`.
99
100
  def should_not(matcher=nil, message=nil)
101
+ enforce_value_expectation(matcher, 'should_not')
100
102
  RSpec::Expectations::NegativeExpectationHandler.handle_matcher(subject, matcher, message)
101
103
  end
102
104
 
@@ -144,6 +146,26 @@ module RSpec
144
146
  end
145
147
  end
146
148
 
149
+ # @private
150
+ def enforce_value_expectation(matcher, method_name)
151
+ return if matcher_supports_value_expectations?(matcher)
152
+
153
+ RSpec.deprecate(
154
+ "#{method_name} #{RSpec::Support::ObjectFormatter.format(matcher)}",
155
+ :message =>
156
+ "The implicit block expectation syntax is deprecated, you should pass " \
157
+ "a block to `expect` to use the provided block expectation matcher " \
158
+ "(#{RSpec::Support::ObjectFormatter.format(matcher)}), " \
159
+ "or the matcher must implement `supports_value_expectations?`."
160
+ )
161
+ end
162
+
163
+ def matcher_supports_value_expectations?(matcher)
164
+ matcher.supports_value_expectations?
165
+ rescue
166
+ true
167
+ end
168
+
147
169
  # @private
148
170
  class ThreadsafeMemoized
149
171
  def initialize
@@ -270,7 +292,7 @@ EOS
270
292
  #
271
293
  # @example
272
294
  #
273
- # describe Thing do
295
+ # RSpec.describe Thing do
274
296
  # let(:thing) { Thing.new }
275
297
  #
276
298
  # it "does something" do
@@ -285,10 +307,33 @@ EOS
285
307
  # We have to pass the block directly to `define_method` to
286
308
  # allow it to use method constructs like `super` and `return`.
287
309
  raise "#let or #subject called without a block" if block.nil?
288
- raise(
289
- "#let or #subject called with a reserved name #initialize"
290
- ) if :initialize == name
291
- MemoizedHelpers.module_for(self).__send__(:define_method, name, &block)
310
+
311
+ # A list of reserved words that can't be used as a name for a memoized helper
312
+ # Matches for both symbols and passed strings
313
+ if [:initialize, :to_s].include?(name.to_sym)
314
+ raise ArgumentError, "#let or #subject called with reserved name `#{name}`"
315
+ end
316
+
317
+ our_module = MemoizedHelpers.module_for(self)
318
+
319
+ # If we have a module clash in our helper module
320
+ # then we need to remove it to prevent a warning.
321
+ #
322
+ # Note we do not check ancestor modules (see: `instance_methods(false)`)
323
+ # as we can override them.
324
+ if our_module.instance_methods(false).include?(name)
325
+ our_module.__send__(:remove_method, name)
326
+ end
327
+ our_module.__send__(:define_method, name, &block)
328
+
329
+ # If we have a module clash in the example module
330
+ # then we need to remove it to prevent a warning.
331
+ #
332
+ # Note we do not check ancestor modules (see: `instance_methods(false)`)
333
+ # as we can override them.
334
+ if instance_methods(false).include?(name)
335
+ remove_method(name)
336
+ end
292
337
 
293
338
  # Apply the memoization. The method has been defined in an ancestor
294
339
  # module so we can use `super` here to get the value.
@@ -323,7 +368,7 @@ EOS
323
368
  # end
324
369
  # end
325
370
  #
326
- # describe Thing do
371
+ # RSpec.describe Thing do
327
372
  # after(:example) { Thing.reset_count }
328
373
  #
329
374
  # context "using let" do
@@ -379,13 +424,13 @@ EOS
379
424
  #
380
425
  # @example
381
426
  #
382
- # describe CheckingAccount, "with $50" do
427
+ # RSpec.describe CheckingAccount, "with $50" do
383
428
  # subject { CheckingAccount.new(Money.new(50, :USD)) }
384
429
  # it { is_expected.to have_a_balance_of(Money.new(50, :USD)) }
385
430
  # it { is_expected.not_to be_overdrawn }
386
431
  # end
387
432
  #
388
- # describe CheckingAccount, "with a non-zero starting balance" do
433
+ # RSpec.describe CheckingAccount, "with a non-zero starting balance" do
389
434
  # subject(:account) { CheckingAccount.new(Money.new(50, :USD)) }
390
435
  # it { is_expected.not_to be_overdrawn }
391
436
  # it "has a balance equal to the starting balance" do
@@ -433,7 +478,7 @@ EOS
433
478
  # end
434
479
  # end
435
480
  #
436
- # describe Thing do
481
+ # RSpec.describe Thing do
437
482
  # after(:example) { Thing.reset_count }
438
483
  #
439
484
  # context "using subject" do
@@ -7,7 +7,7 @@ module RSpec
7
7
  # In addition to metadata that is used internally, this also stores
8
8
  # user-supplied metadata, e.g.
9
9
  #
10
- # describe Something, :type => :ui do
10
+ # RSpec.describe Something, :type => :ui do
11
11
  # it "does something", :slow => true do
12
12
  # # ...
13
13
  # end
@@ -136,7 +136,6 @@ module RSpec
136
136
 
137
137
  populate_location_attributes
138
138
  metadata.update(user_metadata)
139
- RSpec.configuration.apply_derived_metadata_to(metadata)
140
139
  end
141
140
 
142
141
  private
@@ -169,7 +168,7 @@ module RSpec
169
168
  end
170
169
 
171
170
  def description_separator(parent_part, child_part)
172
- if parent_part.is_a?(Module) && child_part =~ /^(#|::|\.)/
171
+ if parent_part.is_a?(Module) && /^(?:#|::|\.)/.match(child_part.to_s)
173
172
  ''.freeze
174
173
  else
175
174
  ' '.freeze
@@ -92,7 +92,7 @@ module RSpec
92
92
  #
93
93
  # This is ideal for use by a example or example group, which may
94
94
  # be updated multiple times with globally configured hooks, etc,
95
- # but will not be queried frequently by other examples or examle
95
+ # but will not be queried frequently by other examples or example
96
96
  # groups.
97
97
  # @private
98
98
  class UpdateOptimized
@@ -22,9 +22,8 @@ module RSpec::Core
22
22
  begin
23
23
  parser(options).parse!(args)
24
24
  rescue OptionParser::InvalidOption => e
25
- failure = e.message
26
- failure << " (defined in #{source})" if source
27
- abort "#{failure}\n\nPlease use --help for a listing of valid options"
25
+ abort "#{e.message}#{" (defined in #{source})" if source}\n\n" \
26
+ "Please use --help for a listing of valid options"
28
27
  end
29
28
 
30
29
  options[:files_or_directories_to_run] = args
@@ -33,10 +32,10 @@ module RSpec::Core
33
32
 
34
33
  private
35
34
 
36
- # rubocop:disable MethodLength
37
35
  # rubocop:disable Metrics/AbcSize
38
- # rubocop:disable CyclomaticComplexity
39
- # rubocop:disable PerceivedComplexity
36
+ # rubocop:disable Metrics/MethodLength
37
+ # rubocop:disable Metrics/CyclomaticComplexity
38
+ # rubocop:disable Metrics/PerceivedComplexity
40
39
  def parser(options)
41
40
  OptionParser.new do |parser|
42
41
  parser.summary_width = 34
@@ -58,10 +57,11 @@ module RSpec::Core
58
57
  end
59
58
 
60
59
  parser.on('--order TYPE[:SEED]', 'Run examples by the specified order type.',
61
- ' [defined] examples and groups are run in the order they are defined',
62
- ' [rand] randomize the order of groups and examples',
63
- ' [random] alias for rand',
64
- ' [random:SEED] e.g. --order random:123') do |o|
60
+ ' [defined] examples and groups are run in the order they are defined',
61
+ ' [rand] randomize the order of groups and examples',
62
+ ' [random] alias for rand',
63
+ ' [random:SEED] e.g. --order random:123',
64
+ ' [recently-modified] run the most recently modified files first') do |o|
65
65
  options[:order] = o
66
66
  end
67
67
 
@@ -95,6 +95,11 @@ module RSpec::Core
95
95
  options[:failure_exit_code] = code
96
96
  end
97
97
 
98
+ parser.on('--error-exit-code CODE', Integer,
99
+ 'Override the exit code used when there are errors loading or running specs outside of examples.') do |code|
100
+ options[:error_exit_code] = code
101
+ end
102
+
98
103
  parser.on('-X', '--[no-]drb', 'Run examples via DRb.') do |use_drb|
99
104
  options[:drb] = use_drb
100
105
  options[:runner] = RSpec::Core::Invocations::DRbWithFallback.new if use_drb
@@ -111,6 +116,7 @@ module RSpec::Core
111
116
  ' [d]ocumentation (group and example names)',
112
117
  ' [h]tml',
113
118
  ' [j]son',
119
+ ' [f]ailures ("file:line:reason", suitable for editors integration)',
114
120
  ' custom formatter class name') do |o|
115
121
  options[:formatters] ||= []
116
122
  options[:formatters] << [o]
@@ -178,6 +184,9 @@ module RSpec::Core
178
184
  end
179
185
 
180
186
  parser.on('-w', '--warnings', 'Enable ruby warnings') do
187
+ if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
188
+ Warning[:deprecated] = true
189
+ end
181
190
  $VERBOSE = true
182
191
  end
183
192
 
@@ -226,6 +235,11 @@ FILTERING
226
235
  (options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o))
227
236
  end
228
237
 
238
+ parser.on('-E', '--example-matches REGEX', "Run examples whose full nested names match REGEX (may be",
239
+ " used more than once)") do |o|
240
+ (options[:full_description] ||= []) << Regexp.compile(o)
241
+ end
242
+
229
243
  parser.on('-t', '--tag TAG[:VALUE]',
230
244
  'Run examples with the specified tag, or exclude examples',
231
245
  'by adding ~ before the tag.',
@@ -289,9 +303,9 @@ FILTERING
289
303
  end
290
304
  end
291
305
  # rubocop:enable Metrics/AbcSize
292
- # rubocop:enable MethodLength
293
- # rubocop:enable CyclomaticComplexity
294
- # rubocop:enable PerceivedComplexity
306
+ # rubocop:enable Metrics/MethodLength
307
+ # rubocop:enable Metrics/CyclomaticComplexity
308
+ # rubocop:enable Metrics/PerceivedComplexity
295
309
 
296
310
  def add_tag_filter(options, filter_type, tag_name, value=true)
297
311
  (options[filter_type] ||= {})[tag_name] = value
@@ -58,6 +58,14 @@ module RSpec
58
58
  MAX_32_BIT = 4_294_967_295
59
59
  end
60
60
 
61
+ # @private
62
+ # Orders items by modification time (most recent modified first).
63
+ class RecentlyModified
64
+ def order(list)
65
+ list.sort_by { |item| -File.mtime(item.metadata[:absolute_file_path]).to_i }
66
+ end
67
+ end
68
+
61
69
  # @private
62
70
  # Orders items based on a custom block.
63
71
  class Custom
@@ -77,7 +85,8 @@ module RSpec
77
85
  @configuration = configuration
78
86
  @strategies = {}
79
87
 
80
- register(:random, Random.new(configuration))
88
+ register(:random, Random.new(configuration))
89
+ register(:recently_modified, RecentlyModified.new)
81
90
 
82
91
  identity = Identity.new
83
92
  register(:defined, identity)
@@ -132,6 +141,8 @@ module RSpec
132
141
  :random
133
142
  elsif order == 'defined'
134
143
  :defined
144
+ elsif order == 'recently-modified'
145
+ :recently_modified
135
146
  end
136
147
 
137
148
  register_ordering(:global, ordering_registry.fetch(ordering_name)) if ordering_name
@@ -38,7 +38,7 @@ module RSpec
38
38
  # @param message [String] optional message to add to the summary report.
39
39
  #
40
40
  # @example
41
- # describe "an example" do
41
+ # describe "some behaviour" do
42
42
  # # reported as "Pending: no reason given"
43
43
  # it "is pending with no message" do
44
44
  # pending
@@ -52,21 +52,13 @@ module RSpec
52
52
  # end
53
53
  # end
54
54
  #
55
- # @note `before(:example)` hooks are eval'd when you use the `pending`
56
- # method within an example. If you want to declare an example `pending`
57
- # and bypass the `before` hooks as well, you can pass `:pending => true`
58
- # to the `it` method:
59
- #
60
- # it "does something", :pending => true do
61
- # # ...
62
- # end
63
- #
64
- # or pass `:pending => "something else getting finished"` to add a
65
- # message to the summary report:
66
- #
67
- # it "does something", :pending => "something else getting finished" do
68
- # # ...
69
- # end
55
+ # @note When using `pending` inside an example body using this method
56
+ # hooks, such as `before(:example)`, have already be run. This means that
57
+ # a failure from the code in the `before` hook will prevent the example
58
+ # from being considered pending, as the example body would not be
59
+ # executed. If you need to consider hooks as pending as well you can use
60
+ # the pending metadata as an alternative, e.g.
61
+ # `it "does something", pending: "message"`.
70
62
  def pending(message=nil)
71
63
  current_example = RSpec.current_example
72
64
 
@@ -12,7 +12,7 @@
12
12
  # the additional setup, and require it from the spec files that actually need
13
13
  # it.
14
14
  #
15
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
15
+ # See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
16
  RSpec.configure do |config|
17
17
  # rspec-expectations config goes here. You can use an alternate
18
18
  # assertion/expectation library such as wrong or the stdlib/minitest
@@ -61,9 +61,7 @@ RSpec.configure do |config|
61
61
 
62
62
  # Limits the available syntax to the non-monkey patched syntax that is
63
63
  # recommended. For more details, see:
64
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
65
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
64
+ # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/
67
65
  config.disable_monkey_patching!
68
66
 
69
67
  # This setting enables warnings. It's recommended, but in some cases may
@@ -45,6 +45,21 @@ module RSpec
45
45
  # A message to print to stderr when there are failures.
46
46
  attr_accessor :failure_message
47
47
 
48
+ if RUBY_VERSION < "1.9.0" || Support::Ruby.jruby?
49
+ # Run RSpec with a clean (empty) environment is not supported
50
+ def with_clean_environment=(_value)
51
+ raise ArgumentError, "Running in a clean environment is not supported on Ruby versions before 1.9.0"
52
+ end
53
+
54
+ # Run RSpec with a clean (empty) environment is not supported
55
+ def with_clean_environment
56
+ false
57
+ end
58
+ else
59
+ # Run RSpec with a clean (empty) environment.
60
+ attr_accessor :with_clean_environment
61
+ end
62
+
48
63
  # Use verbose output. If this is set to true, the task will print the
49
64
  # executed spec command to stdout. Defaults to `true`.
50
65
  attr_accessor :verbose
@@ -76,7 +91,12 @@ module RSpec
76
91
  command = spec_command
77
92
  puts command if verbose
78
93
 
79
- return if system(command)
94
+ if with_clean_environment
95
+ return if system({}, command, :unsetenv_others => true)
96
+ else
97
+ return if system(command)
98
+ end
99
+
80
100
  puts failure_message if failure_message
81
101
 
82
102
  return unless fail_on_error
@@ -102,7 +122,7 @@ module RSpec
102
122
  if ENV['SPEC']
103
123
  FileList[ENV['SPEC']].sort
104
124
  elsif String === pattern && !File.exist?(pattern)
105
- return if rspec_opts =~ /--pattern/
125
+ return if [*rspec_opts].any? { |opt| opt =~ /--pattern/ }
106
126
  "--pattern #{escape pattern}"
107
127
  else
108
128
  # Before RSpec 3.1, we used `FileList` to get the list of matched
@@ -30,7 +30,7 @@ module RSpec::Core
30
30
  # Registers a listener to a list of notifications. The reporter will send
31
31
  # notification of events to all registered listeners.
32
32
  #
33
- # @param listener [Object] An obect that wishes to be notified of reporter
33
+ # @param listener [Object] An object that wishes to be notified of reporter
34
34
  # events
35
35
  # @param notifications [Array] Array of symbols represents the events a
36
36
  # listener wishes to subscribe too
@@ -77,6 +77,14 @@ module RSpec::Core
77
77
  end
78
78
  end
79
79
 
80
+ # @param exit_code [Integer] the exit_code to be return by the reporter
81
+ #
82
+ # Reports a run that exited early without having run any examples.
83
+ #
84
+ def exit_early(exit_code)
85
+ report(0) { exit_code }
86
+ end
87
+
80
88
  # @private
81
89
  def start(expected_example_count, time=RSpec::Core::Time.now)
82
90
  @start = time