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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 01f0ed2875b8c4e0801d2857936e4a4116ceb309
4
- data.tar.gz: 58b9a780de52779ef48a2c510d99c14dd7a22f1d
2
+ SHA256:
3
+ metadata.gz: e105bb79ced0094703c116de121aced72afd16f580c3faba5aa9da6c7d84316d
4
+ data.tar.gz: 7f5df2dec8edeb01d39c2296331d5a24aa2b8c2f4122763045edf4d27531df56
5
5
  SHA512:
6
- metadata.gz: dc81061f5a9badff82a346285c6571447b9884906540c0502aeec96c1d100d4c764e2422f87dadd46148a8db96926b9c1a5e5d57a72adda28d6f05ddceae65e9
7
- data.tar.gz: 940193670454593373c80e55c407e31a70b3eb8f9579b108663ec9234e2025149a93aed2d8aec8e2e7eeffd124853bf1a5a068d2a79e4bbcaed551b769d485fd
6
+ metadata.gz: 64d5b3ad7ccd921c553ef73c7870d4118d5ad6de826a5ed26190983d802455c1caf80f62a9982aad70492ba40b568d2e84fb19f8ffde6940ecf37100953a20d7
7
+ data.tar.gz: 04ac5e2f690218999a7a936319d7e4f2a995cc796364d9c3af5a0db6065d271be0e2445c5f7038b85ccfe4bf03ae7d263600e4de36cca4c8e6e241e51fcb4bbb
checksums.yaml.gz.sig CHANGED
Binary file
data/Changelog.md CHANGED
@@ -1,3 +1,156 @@
1
+ ### Development
2
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.12.2...3-12-maintenance)
3
+
4
+ ### 3.12.2 / 2023-04-18
5
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.12.1...v3.12.2)
6
+
7
+ Bug fixes:
8
+
9
+ * Remove link to outdated documentation in generated output. (Jon Rowe, #3035)
10
+
11
+ ### 3.12.1 / 2023-02-03
12
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.12.0...v3.12.1)
13
+
14
+ Bug fixes:
15
+
16
+ * Prevent multiple calls to `extra_failure_lines` from adding additional whitespace
17
+ around them when the lines already contain whitespace. (Jon Rowe, #3006)
18
+
19
+ ### 3.12.0 / 2022-10-26
20
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.11.0...v3.12.0)
21
+
22
+ * No changes, released to support other gems.
23
+
24
+ ### 3.11.0 / 2022-02-09
25
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.10.2...v3.11.0)
26
+
27
+ Enhancements:
28
+
29
+ * Improve pluralisation of words ending with `s` (like process). (Joshua Pinter, #2779)
30
+ * Add ordering by file modification time (most recent first). (Matheus Richard, #2778)
31
+ * Add `to_s` to reserved names for #let and #subject. (Nick Flückiger, #2886)
32
+ * Introduce `RSpec.current_scope` to expose the current scope in which
33
+ RSpec is executing. e.g. `:before_example_hook`, `:example` etc. (@odinhb, #2895)
34
+ * Add named bold colours as options for custom colours. (#2913, #2914)
35
+ * Warn when (but not prevent) a `SystemExit` occurs. (Jared Beck, #2926)
36
+
37
+ ### 3.10.2 / 2022-01-27
38
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.10.1...v3.10.2)
39
+
40
+ Bug fixes:
41
+
42
+ * Ensure bisect communication uses consistent encoding. (Mike Jarema, #2852)
43
+ * Fix exception presenter when the root cause exception has nil backtrace.
44
+ (Zinovyev Ivan, #2903)
45
+ * Fix `inspect` output of `RSpec::Core::Example::Procsy` to namespace correctly.
46
+ (Keiko Kaneko, #2915)
47
+ * Ensure formatters not exposing `#output` will not crash duplicate check.
48
+ (@niceking, #2916)
49
+
50
+ ### 3.10.1 / 2020-12-27
51
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.10.0...v3.10.1)
52
+
53
+ Bug fixes:
54
+
55
+ * RSpec warning output was missing deprecations from Ruby, these are now included.
56
+ (Jon Rowe, #2811)
57
+
58
+ ### 3.10.0 / 2020-10-30
59
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.3...v3.10.0)
60
+
61
+ Enhancements:
62
+
63
+ * Memoize `RSpec::Core::Formatters::ExceptionPresenter#exception_lines` to improve performance
64
+ with slow exception messages. (Maxime Lapointe, #2743)
65
+ * Add configuration for an error exit code (to disambiguate errored builds from failed builds
66
+ by exit status). (Dana Sherson, #2749)
67
+
68
+ ### 3.9.3 / 2020-09-30
69
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.2...v3.9.3)
70
+
71
+ Bug Fixes:
72
+
73
+ * Declare `ruby2_keywords` on `method_missing` for other gems. (Jon Rowe, #2731)
74
+ * Ensure custom error codes are returned from bisect runs. (Jon Rowe, #2732)
75
+ * Ensure `RSpec::Core::Configuration` predicate config methods return booleans.
76
+ (Marc-André Lafortune, #2736)
77
+ * Prevent `rspec --bisect` from generating zombie processes while executing
78
+ bisect runs. (Benoit Tigeot, Jon Rowe, #2739)
79
+ * Predicates for pending examples, (in `RSpec::Core::Example`, `#pending?`, `#skipped?` and
80
+ `#pending_fixed?`) now return boolean values rather than truthy values.
81
+ (Marc-André Lafortune, #2756, #2758)
82
+ * Exceptions which have a message which cannot be cast to a string will no longer
83
+ cause a crash. (Jon Rowe, #2761)
84
+
85
+ ### 3.9.2 / 2020-05-02
86
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...v3.9.2)
87
+
88
+ Bug Fixes:
89
+
90
+ * Emit a warning when `around` hook is used with `:context` scope
91
+ (Phil Pirozhkov, #2687)
92
+ * Prevent invalid implementations of `Exception#cause` from being treated as a
93
+ valid cause (and causing strange errors) in `RSpec::Core::Formatters::ExceptionPresenter`.
94
+ (Jon Rowe, #2703)
95
+ * Correctly detect patterns when `rspec_opts` is an array in `RSpec::Core::RakeTask`.
96
+ (Marc-André Lafortune, #2704)
97
+ * Make `RSpec.clear_examples` reset example counts for example groups. This fixes
98
+ an issue with re-running specs not matching ids. (Agis Anastasopoulos, #2723)
99
+
100
+ ### 3.9.1 / 2019-12-28
101
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.0...v3.9.1)
102
+
103
+ Bug Fixes:
104
+
105
+ * Prevent bisect command from blocking when number of specs exceeds file
106
+ descriptor limit on OSX or Linux. (Benoit Tigeot, #2669)
107
+ * Prevent warnings being issued on Ruby 2.7.0. (Jon Rowe, #2680)
108
+
109
+ ### 3.9.0 / 2019-10-07
110
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.2...v3.9.0)
111
+
112
+ Enhancements:
113
+
114
+ * Improve the handling of errors during loading support files, if a file
115
+ errors before loading specs, RSpec will now skip loading the specs.
116
+ (David Rodríguez, #2568)
117
+ * Add support for --example-matches to run examples by regular expression.
118
+ (Sam Joseph, Matt Rider, @okothkongo1, #2586)
119
+ * Add `did_you_mean` suggestions for file names encountering a `LoadError`
120
+ outside of examples. (@obromios, #2601)
121
+ * Add a minimalist quick fix style formatter, only outputs failures as
122
+ `file:line:message`. (Romain Tartière, #2614)
123
+ * Convert string number values to integer when used for `RSpec::Configuration#fail_fast`
124
+ (Viktor Fonic, #2634)
125
+ * Issue warning when invalid values are used for `RSpec::Configuration#fail_fast`
126
+ (Viktor Fonic, #2634)
127
+ * Add support for running the Rake task in a clean environment.
128
+ (Jon Rowe, #2632)
129
+ * Indent messages by there example group / example in the documentation formatter.
130
+ (Samuel Williams, #2649)
131
+
132
+ ### 3.8.2 / 2019-06-29
133
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.1...v3.8.2)
134
+
135
+ Bug Fixes:
136
+
137
+ * Fix `config.define_derived_metadata` so that cascades are not triggered
138
+ until metadata has been assigned to the example or example group
139
+ (Myron Marston, #2635).
140
+
141
+ ### 3.8.1 / 2019-06-13
142
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.0...v3.8.1)
143
+
144
+ Bug Fixes:
145
+
146
+ * Handle RSpec description(s) with japanese chars in CP932 encoded files.
147
+ (Benoit Tigeot, #2575)
148
+ * When defining `let` methods that overwrite an existing method, prevent
149
+ a warning being issued by removing the old definition. (Jon Rowe, #2593)
150
+ * Prevent warning on Ruby 2.6.0-rc1 (Keiji Yoshimi, #2582)
151
+ * Fix `config.define_derived_metadata` so that it supports cascades.
152
+ (Myron Marston, #2630).
153
+
1
154
  ### 3.8.0 / 2018-08-04
2
155
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.7.1...v3.8.0)
3
156
 
@@ -2075,6 +2228,7 @@ Bug fixes
2075
2228
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v2.2.0...v2.2.1)
2076
2229
 
2077
2230
  Bug fixes
2231
+
2078
2232
  * alias_method instead of override Kernel#method_missing (John Wilger)
2079
2233
  * changed --autotest to --tty in generated command (MIKAMI Yoshiyuki)
2080
2234
  * revert change to debugger (had introduced conflict with Rails)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # rspec-core [![Build Status](https://secure.travis-ci.org/rspec/rspec-core.svg?branch=master)](http://travis-ci.org/rspec/rspec-core) [![Code Climate](https://codeclimate.com/github/rspec/rspec-core.svg)](https://codeclimate.com/github/rspec/rspec-core)
1
+ # rspec-core [![Build Status](https://github.com/rspec/rspec-core/workflows/RSpec%20CI/badge.svg)](https://github.com/rspec/rspec-core/actions) [![Code Climate](https://codeclimate.com/github/rspec/rspec-core.svg)](https://codeclimate.com/github/rspec/rspec-core)
2
2
 
3
3
  rspec-core provides the structure for writing executable examples of how your
4
4
  code should behave, and an `rspec` command with tools to constrain which
@@ -10,29 +10,15 @@ examples get run and tailor the output.
10
10
  gem install rspec-core # for rspec-core only
11
11
  rspec --help
12
12
 
13
- Want to run against the `master` branch? You'll need to include the dependent
13
+ Want to run against the `main` branch? You'll need to include the dependent
14
14
  RSpec repos as well. Add the following to your `Gemfile`:
15
15
 
16
16
  ```ruby
17
17
  %w[rspec rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
18
- gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'master'
18
+ gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main'
19
19
  end
20
20
  ```
21
21
 
22
- ## Contributing
23
-
24
- Once you've set up the environment, you'll need to cd into the working
25
- directory of whichever repo you want to work in. From there you can run the
26
- specs and cucumber features, and make patches.
27
-
28
- NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
29
- can treat each RSpec repo as an independent project.
30
-
31
- * [Build details](BUILD_DETAIL.md)
32
- * [Code of Conduct](CODE_OF_CONDUCT.md)
33
- * [Detailed contributing guide](CONTRIBUTING.md)
34
- * [Development setup guide](DEVELOPMENT.md)
35
-
36
22
  ## Basic Structure
37
23
 
38
24
  RSpec uses the words "describe" and "it" so we can express concepts like a conversation:
@@ -67,7 +53,7 @@ context of an _instance_ of that class.
67
53
 
68
54
  ## Nested Groups
69
55
 
70
- You can also declare nested nested groups using the `describe` or `context`
56
+ You can also declare nested groups using the `describe` or `context`
71
57
  methods:
72
58
 
73
59
  ```ruby
@@ -336,14 +322,14 @@ Failures:
336
322
  got: nil
337
323
 
338
324
  (compared using ==)
339
- # ./spec/calcalator_spec.rb:6:in `block (3 levels) in <top (required)>'
325
+ # ./spec/calculator_spec.rb:6:in `block (3 levels) in <top (required)>'
340
326
 
341
327
  Finished in 0.00131 seconds (files took 0.10968 seconds to load)
342
328
  1 example, 1 failure
343
329
 
344
330
  Failed examples:
345
331
 
346
- rspec ./spec/calcalator_spec.rb:5 # Calculator#add returns the sum of its arguments
332
+ rspec ./spec/calculator_spec.rb:5 # Calculator#add returns the sum of its arguments
347
333
  ```
348
334
 
349
335
  Implement the simplest solution, by changing the definition of `Calculator#add` to:
@@ -376,6 +362,20 @@ Finished in 0.000379 seconds
376
362
  1 example, 0 failures
377
363
  ```
378
364
 
365
+ ## Contributing
366
+
367
+ Once you've set up the environment, you'll need to cd into the working
368
+ directory of whichever repo you want to work in. From there you can run the
369
+ specs and cucumber features, and make patches.
370
+
371
+ NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
372
+ can treat each RSpec repo as an independent project.
373
+
374
+ * [Build details](BUILD_DETAIL.md)
375
+ * [Code of Conduct](CODE_OF_CONDUCT.md)
376
+ * [Detailed contributing guide](CONTRIBUTING.md)
377
+ * [Development setup guide](DEVELOPMENT.md)
378
+
379
379
  ## Also see
380
380
 
381
381
  * [https://github.com/rspec/rspec](https://github.com/rspec/rspec)
@@ -6,7 +6,7 @@ module RSpec
6
6
  module Core
7
7
  module Bisect
8
8
  # A Bisect runner that runs requested subsets of the suite by forking
9
- # sub-processes. The master process bootstraps RSpec and the application
9
+ # sub-processes. The main process bootstraps RSpec and the application
10
10
  # environment (including preloading files specified via `--require`) so
11
11
  # that the individual spec runs do not have to re-pay that cost. Each
12
12
  # spec run happens in a forked process, ensuring that the spec files are
@@ -92,7 +92,11 @@ module RSpec
92
92
 
93
93
  def dispatch_specs(run_descriptor)
94
94
  pid = fork { run_specs(run_descriptor) }
95
- Process.waitpid(pid)
95
+ # We don't use Process.waitpid here as it was causing bisects to
96
+ # block due to the file descriptor limit on OSX / Linux. We need
97
+ # to detach the process to avoid having zombie processes
98
+ # consuming slots in the kernel process table during bisect runs.
99
+ Process.detach(pid)
96
100
  end
97
101
 
98
102
  private
@@ -33,7 +33,7 @@ module RSpec
33
33
 
34
34
  def start
35
35
  # Only allow remote DRb requests from this machine.
36
- DRb.install_acl ACL.new(%w[ deny all allow localhost allow 127.0.0.1 ])
36
+ DRb.install_acl ACL.new(%w[ deny all allow localhost allow 127.0.0.1 allow ::1 ])
37
37
 
38
38
  # We pass `nil` as the first arg to allow it to pick a DRb port.
39
39
  @drb = DRb.start_service(nil, self)
@@ -29,11 +29,22 @@ module RSpec
29
29
  end
30
30
 
31
31
  # Wraps a pipe to support sending objects between a child and
32
- # parent process.
32
+ # parent process. Where supported, encoding is explicitly
33
+ # set to ensure binary data is able to pass from child to
34
+ # parent.
33
35
  # @private
34
36
  class Channel
37
+ if String.method_defined?(:encoding)
38
+ MARSHAL_DUMP_ENCODING = Marshal.dump("").encoding
39
+ end
40
+
35
41
  def initialize
36
42
  @read_io, @write_io = IO.pipe
43
+
44
+ if defined?(MARSHAL_DUMP_ENCODING) && IO.method_defined?(:set_encoding)
45
+ # Ensure the pipe can send any content produced by Marshal.dump
46
+ @write_io.set_encoding MARSHAL_DUMP_ENCODING
47
+ end
37
48
  end
38
49
 
39
50
  def send(message)
@@ -67,15 +67,17 @@ module RSpec
67
67
  end
68
68
 
69
69
  # @private
70
- def self.define_aliases(name, alias_name)
70
+ def self.define_alias(name, alias_name)
71
71
  alias_method alias_name, name
72
72
  alias_method "#{alias_name}=", "#{name}="
73
- define_predicate_for alias_name
73
+ define_predicate alias_name
74
74
  end
75
75
 
76
76
  # @private
77
- def self.define_predicate_for(*names)
78
- names.each { |name| alias_method "#{name}?", name }
77
+ def self.define_predicate(name)
78
+ define_method "#{name}?" do
79
+ !!send(name)
80
+ end
79
81
  end
80
82
 
81
83
  # @private
@@ -88,7 +90,7 @@ module RSpec
88
90
  add_read_only_setting name
89
91
 
90
92
  Array(opts[:alias_with]).each do |alias_name|
91
- define_aliases(name, alias_name)
93
+ define_alias(name, alias_name)
92
94
  end
93
95
  end
94
96
 
@@ -98,7 +100,7 @@ module RSpec
98
100
  def self.add_read_only_setting(name, opts={})
99
101
  raise "Use the instance add_setting method if you want to set a default" if opts.key?(:default)
100
102
  define_reader name
101
- define_predicate_for name
103
+ define_predicate name
102
104
  end
103
105
 
104
106
  # @macro [attach] add_setting
@@ -202,10 +204,33 @@ module RSpec
202
204
  only_failures? && !example_status_persistence_file_path
203
205
  end
204
206
 
205
- # @macro add_setting
207
+ # @macro define_reader
206
208
  # If specified, indicates the number of failures required before cleaning
207
- # up and exit (default: `nil`).
208
- add_setting :fail_fast
209
+ # up and exit (default: `nil`). Can also be `true` to fail and exit on first
210
+ # failure
211
+ define_reader :fail_fast
212
+
213
+ # @see fail_fast
214
+ def fail_fast=(value)
215
+ case value
216
+ when true, 'true'
217
+ @fail_fast = true
218
+ when false, 'false', 0
219
+ @fail_fast = false
220
+ when nil
221
+ @fail_fast = nil
222
+ else
223
+ @fail_fast = value.to_i
224
+
225
+ if value.to_i == 0
226
+ # TODO: in RSpec 4, consider raising an error here.
227
+ RSpec.warning "Cannot set `RSpec.configuration.fail_fast`" \
228
+ " to `#{value.inspect}`. Only `true`, `false`, `nil` and integers" \
229
+ " are valid values."
230
+ @fail_fast = true
231
+ end
232
+ end
233
+ end
209
234
 
210
235
  # @macro add_setting
211
236
  # Prints the formatter output of your suite without running any
@@ -217,6 +242,11 @@ module RSpec
217
242
  # @return [Integer]
218
243
  add_setting :failure_exit_code
219
244
 
245
+ # @macro add_setting
246
+ # The exit code to return if there are any errors outside examples (default: failure_exit_code)
247
+ # @return [Integer]
248
+ add_setting :error_exit_code
249
+
220
250
  # @macro add_setting
221
251
  # Whether or not to fail when there are no RSpec examples (default: false).
222
252
  # @return [Boolean]
@@ -289,7 +319,8 @@ module RSpec
289
319
  # Report the times for the slowest examples (default: `false`).
290
320
  # Use this to specify the number of examples to include in the profile.
291
321
  # @return [Boolean]
292
- add_setting :profile_examples
322
+ attr_writer :profile_examples
323
+ define_predicate :profile_examples
293
324
 
294
325
  # @macro add_setting
295
326
  # Run all examples if none match the configured filters
@@ -471,7 +502,8 @@ module RSpec
471
502
  # @private
472
503
  attr_reader :backtrace_formatter, :ordering_manager, :loaded_spec_files
473
504
 
474
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
505
+ # rubocop:disable Metrics/AbcSize
506
+ # rubocop:disable Metrics/MethodLength
475
507
 
476
508
  # Build an object to store runtime configuration options and set defaults
477
509
  def initialize
@@ -497,6 +529,7 @@ module RSpec
497
529
  @pattern = '**{,/*/**}/*_spec.rb'
498
530
  @exclude_pattern = ''
499
531
  @failure_exit_code = 1
532
+ @error_exit_code = nil # so it can be overridden by failure exit code
500
533
  @fail_if_no_examples = false
501
534
  @spec_files_loaded = false
502
535
 
@@ -529,7 +562,8 @@ module RSpec
529
562
 
530
563
  define_built_in_hooks
531
564
  end
532
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
565
+ # rubocop:enable Metrics/AbcSize
566
+ # rubocop:enable Metrics/MethodLength
533
567
 
534
568
  # @private
535
569
  #
@@ -644,7 +678,7 @@ module RSpec
644
678
  end
645
679
 
646
680
  # Set regular expressions used to exclude lines in backtrace.
647
- # @param patterns [Array<Regexp>] set backtrace_formatter exlusion_patterns
681
+ # @param patterns [Array<Regexp>] set backtrace_formatter exclusion_patterns
648
682
  def backtrace_exclusion_patterns=(patterns)
649
683
  @backtrace_formatter.exclusion_patterns = patterns
650
684
  end
@@ -1106,7 +1140,7 @@ module RSpec
1106
1140
  #
1107
1141
  # # This lets you do this:
1108
1142
  #
1109
- # describe Thing do
1143
+ # RSpec.describe Thing do
1110
1144
  # pending "does something" do
1111
1145
  # thing = Thing.new
1112
1146
  # end
@@ -1114,7 +1148,7 @@ module RSpec
1114
1148
  #
1115
1149
  # # ... which is the equivalent of
1116
1150
  #
1117
- # describe Thing do
1151
+ # RSpec.describe Thing do
1118
1152
  # it "does something", :pending => true do
1119
1153
  # thing = Thing.new
1120
1154
  # end
@@ -1167,7 +1201,7 @@ module RSpec
1167
1201
  #
1168
1202
  # # allows the user to include a shared example group like:
1169
1203
  #
1170
- # describe Entity do
1204
+ # RSpec.describe Entity do
1171
1205
  # it_has_behavior 'sortability' do
1172
1206
  # let(:sortable) { Entity.new }
1173
1207
  # end
@@ -1327,6 +1361,12 @@ module RSpec
1327
1361
  # end
1328
1362
  # end
1329
1363
  #
1364
+ # module PreferencesHelpers
1365
+ # def preferences(user, preferences = {})
1366
+ # # ...
1367
+ # end
1368
+ # end
1369
+ #
1330
1370
  # module UserHelpers
1331
1371
  # def users(username)
1332
1372
  # # ...
@@ -1335,12 +1375,17 @@ module RSpec
1335
1375
  #
1336
1376
  # RSpec.configure do |config|
1337
1377
  # config.include(UserHelpers) # included in all groups
1378
+ #
1379
+ # # included in examples with `:preferences` metadata
1380
+ # config.include(PreferenceHelpers, :preferences)
1381
+ #
1382
+ # # included in examples with `:type => :request` metadata
1338
1383
  # config.include(AuthenticationHelpers, :type => :request)
1339
1384
  # end
1340
1385
  #
1341
- # describe "edit profile", :type => :request do
1386
+ # describe "edit profile", :preferences, :type => :request do
1342
1387
  # it "can be viewed by owning user" do
1343
- # login_as users(:jdoe)
1388
+ # login_as preferences(users(:jdoe), :lang => 'es')
1344
1389
  # get "/profiles/jdoe"
1345
1390
  # assert_select ".username", :text => 'jdoe'
1346
1391
  # end
@@ -1368,17 +1413,21 @@ module RSpec
1368
1413
  #
1369
1414
  # @example
1370
1415
  #
1371
- # RSpec.shared_context "example users" do
1416
+ # RSpec.shared_context "example admin user" do
1372
1417
  # let(:admin_user) { create_user(:admin) }
1418
+ # end
1419
+ #
1420
+ # RSpec.shared_context "example guest user" do
1373
1421
  # let(:guest_user) { create_user(:guest) }
1374
1422
  # end
1375
1423
  #
1376
1424
  # RSpec.configure do |config|
1377
- # config.include_context "example users", :type => :request
1425
+ # config.include_context "example guest user", :type => :request
1426
+ # config.include_context "example admin user", :admin, :type => :request
1378
1427
  # end
1379
1428
  #
1380
1429
  # RSpec.describe "The admin page", :type => :request do
1381
- # it "can be viewed by admins" do
1430
+ # it "can be viewed by admins", :admin do
1382
1431
  # login_with admin_user
1383
1432
  # get "/admin"
1384
1433
  # expect(response).to be_ok
@@ -1420,12 +1469,20 @@ module RSpec
1420
1469
  # end
1421
1470
  # end
1422
1471
  #
1472
+ # module PermissionHelpers
1473
+ # def define_permissions
1474
+ # # ...
1475
+ # end
1476
+ # end
1477
+ #
1423
1478
  # RSpec.configure do |config|
1424
1479
  # config.extend(UiHelpers, :type => :request)
1480
+ # config.extend(PermissionHelpers, :with_permissions, :type => :request)
1425
1481
  # end
1426
1482
  #
1427
- # describe "edit profile", :type => :request do
1483
+ # describe "edit profile", :with_permissions, :type => :request do
1428
1484
  # run_in_browser
1485
+ # define_permissions
1429
1486
  #
1430
1487
  # it "does stuff in the client" do
1431
1488
  # # ...
@@ -1718,7 +1775,7 @@ module RSpec
1718
1775
  # rspec.expose_current_running_example_as :example
1719
1776
  # end
1720
1777
  #
1721
- # describe MyClass do
1778
+ # RSpec.describe MyClass do
1722
1779
  # before do
1723
1780
  # # `example` can be used here because of the above config.
1724
1781
  # do_something if example.metadata[:type] == "foo"
@@ -1763,7 +1820,7 @@ module RSpec
1763
1820
  # by not setting `mock_with` or `expect_with` to anything else).
1764
1821
  #
1765
1822
  # @note If the user uses this options with `mock_with :mocha`
1766
- # (or similiar) they will still have monkey patching active
1823
+ # (or similar) they will still have monkey patching active
1767
1824
  # in their test environment from mocha.
1768
1825
  #
1769
1826
  # @example
@@ -1855,16 +1912,36 @@ module RSpec
1855
1912
 
1856
1913
  # @private
1857
1914
  def apply_derived_metadata_to(metadata)
1858
- @derived_metadata_blocks.items_for(metadata).each do |block|
1859
- block.call(metadata)
1915
+ already_run_blocks = Set.new
1916
+
1917
+ # We loop and attempt to re-apply metadata blocks to support cascades
1918
+ # (e.g. where a derived bit of metadata triggers the application of
1919
+ # another piece of derived metadata, etc)
1920
+ #
1921
+ # We limit our looping to 200 times as a way to detect infinitely recursing derived metadata blocks.
1922
+ # It's hard to imagine a valid use case for a derived metadata cascade greater than 200 iterations.
1923
+ 200.times do
1924
+ return if @derived_metadata_blocks.items_for(metadata).all? do |block|
1925
+ already_run_blocks.include?(block).tap do |skip_block|
1926
+ block.call(metadata) unless skip_block
1927
+ already_run_blocks << block
1928
+ end
1929
+ end
1860
1930
  end
1931
+
1932
+ # If we got here, then `@derived_metadata_blocks.items_for(metadata).all?` never returned
1933
+ # `true` above and we treat this as an attempt to recurse infinitely. It's better to fail
1934
+ # with a clear # error than hang indefinitely, which is what would happen if we didn't limit
1935
+ # the looping above.
1936
+ raise SystemStackError, "Attempted to recursively derive metadata indefinitely."
1861
1937
  end
1862
1938
 
1863
1939
  # Defines a `before` hook. See {Hooks#before} for full docs.
1864
1940
  #
1865
1941
  # This method differs from {Hooks#before} in only one way: it supports
1866
1942
  # the `:suite` scope. Hooks with the `:suite` scope will be run once before
1867
- # the first example of the entire suite is executed.
1943
+ # the first example of the entire suite is executed. Conditions passed along
1944
+ # with `:suite` are effectively ignored.
1868
1945
  #
1869
1946
  # @see #prepend_before
1870
1947
  # @see #after
@@ -1893,7 +1970,8 @@ module RSpec
1893
1970
  #
1894
1971
  # This method differs from {Hooks#prepend_before} in only one way: it supports
1895
1972
  # the `:suite` scope. Hooks with the `:suite` scope will be run once before
1896
- # the first example of the entire suite is executed.
1973
+ # the first example of the entire suite is executed. Conditions passed along
1974
+ # with `:suite` are effectively ignored.
1897
1975
  #
1898
1976
  # @see #before
1899
1977
  # @see #after
@@ -1917,7 +1995,8 @@ module RSpec
1917
1995
  #
1918
1996
  # This method differs from {Hooks#after} in only one way: it supports
1919
1997
  # the `:suite` scope. Hooks with the `:suite` scope will be run once after
1920
- # the last example of the entire suite is executed.
1998
+ # the last example of the entire suite is executed. Conditions passed along
1999
+ # with `:suite` are effectively ignored.
1921
2000
  #
1922
2001
  # @see #append_after
1923
2002
  # @see #before
@@ -1946,7 +2025,8 @@ module RSpec
1946
2025
  #
1947
2026
  # This method differs from {Hooks#append_after} in only one way: it supports
1948
2027
  # the `:suite` scope. Hooks with the `:suite` scope will be run once after
1949
- # the last example of the entire suite is executed.
2028
+ # the last example of the entire suite is executed. Conditions passed along
2029
+ # with `:suite` are effectively ignored.
1950
2030
  #
1951
2031
  # @see #append_after
1952
2032
  # @see #before
@@ -1985,10 +2065,13 @@ module RSpec
1985
2065
  return yield if dry_run?
1986
2066
 
1987
2067
  begin
2068
+ RSpec.current_scope = :before_suite_hook
1988
2069
  run_suite_hooks("a `before(:suite)` hook", @before_suite_hooks)
1989
2070
  yield
1990
2071
  ensure
2072
+ RSpec.current_scope = :after_suite_hook
1991
2073
  run_suite_hooks("an `after(:suite)` hook", @after_suite_hooks)
2074
+ RSpec.current_scope = :suite
1992
2075
  end
1993
2076
  end
1994
2077
 
@@ -2032,10 +2115,23 @@ module RSpec
2032
2115
 
2033
2116
  def load_file_handling_errors(method, file)
2034
2117
  __send__(method, file)
2118
+ rescue LoadError => ex
2119
+ relative_file = Metadata.relative_path(file)
2120
+ suggestions = DidYouMean.new(relative_file).call
2121
+ reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.#{suggestions}")
2122
+ RSpec.world.wants_to_quit = true
2035
2123
  rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
2036
2124
  relative_file = Metadata.relative_path(file)
2037
2125
  reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.")
2038
2126
  RSpec.world.wants_to_quit = true
2127
+ rescue SystemExit => ex
2128
+ relative_file = Metadata.relative_path(file)
2129
+ reporter.notify_non_example_exception(
2130
+ ex,
2131
+ "While loading #{relative_file} an `exit` / `raise SystemExit` occurred, RSpec will now quit."
2132
+ )
2133
+ RSpec.world.rspec_is_quitting = true
2134
+ raise ex
2039
2135
  end
2040
2136
 
2041
2137
  def handle_suite_hook(scope, meta)