rspec-core 3.1.7 → 3.2.0

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 (51) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +1 -0
  5. data/Changelog.md +84 -0
  6. data/README.md +10 -1
  7. data/lib/rspec/core.rb +28 -8
  8. data/lib/rspec/core/backport_random.rb +12 -9
  9. data/lib/rspec/core/configuration.rb +350 -112
  10. data/lib/rspec/core/configuration_options.rb +14 -7
  11. data/lib/rspec/core/dsl.rb +7 -4
  12. data/lib/rspec/core/example.rb +86 -50
  13. data/lib/rspec/core/example_group.rb +247 -86
  14. data/lib/rspec/core/filter_manager.rb +38 -93
  15. data/lib/rspec/core/flat_map.rb +4 -4
  16. data/lib/rspec/core/formatters.rb +10 -6
  17. data/lib/rspec/core/formatters/base_formatter.rb +7 -4
  18. data/lib/rspec/core/formatters/base_text_formatter.rb +12 -12
  19. data/lib/rspec/core/formatters/console_codes.rb +8 -7
  20. data/lib/rspec/core/formatters/deprecation_formatter.rb +5 -3
  21. data/lib/rspec/core/formatters/documentation_formatter.rb +10 -4
  22. data/lib/rspec/core/formatters/helpers.rb +6 -4
  23. data/lib/rspec/core/formatters/html_formatter.rb +13 -8
  24. data/lib/rspec/core/formatters/html_printer.rb +26 -10
  25. data/lib/rspec/core/formatters/profile_formatter.rb +10 -7
  26. data/lib/rspec/core/formatters/protocol.rb +27 -18
  27. data/lib/rspec/core/formatters/snippet_extractor.rb +14 -7
  28. data/lib/rspec/core/hooks.rb +252 -211
  29. data/lib/rspec/core/memoized_helpers.rb +16 -16
  30. data/lib/rspec/core/metadata.rb +67 -28
  31. data/lib/rspec/core/metadata_filter.rb +151 -24
  32. data/lib/rspec/core/minitest_assertions_adapter.rb +5 -2
  33. data/lib/rspec/core/mocking_adapters/flexmock.rb +1 -1
  34. data/lib/rspec/core/mocking_adapters/mocha.rb +8 -8
  35. data/lib/rspec/core/notifications.rb +155 -94
  36. data/lib/rspec/core/option_parser.rb +16 -10
  37. data/lib/rspec/core/pending.rb +11 -9
  38. data/lib/rspec/core/project_initializer.rb +1 -1
  39. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +10 -8
  40. data/lib/rspec/core/rake_task.rb +37 -52
  41. data/lib/rspec/core/reporter.rb +30 -7
  42. data/lib/rspec/core/ruby_project.rb +12 -4
  43. data/lib/rspec/core/runner.rb +5 -8
  44. data/lib/rspec/core/sandbox.rb +37 -0
  45. data/lib/rspec/core/shared_example_group.rb +41 -15
  46. data/lib/rspec/core/test_unit_assertions_adapter.rb +3 -3
  47. data/lib/rspec/core/version.rb +1 -1
  48. data/lib/rspec/core/warnings.rb +2 -2
  49. data/lib/rspec/core/world.rb +12 -28
  50. metadata +44 -31
  51. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc437d7748b2d4e51abc67ecdee4b3222ddbee53
4
- data.tar.gz: fa6c35c84c11393fa3f72dd0bdd8712e31b8ca9e
3
+ metadata.gz: 64add3bc6c923a094fe43e64de951766afb3d546
4
+ data.tar.gz: a6edfdd40534051c51205124394016d6ee23b90c
5
5
  SHA512:
6
- metadata.gz: cc7190d5420cb26fa663b62e4355284b6a869300c118b6ea535d37f5d86bfc8ce9199259f1c1036be7b4193090e03db2e57ef8b7e41574cfb69c239349479a54
7
- data.tar.gz: 0f213b46212dfe8233f1d7466f7e519ef375b6eb1757db8f4a3cdaf630554d43588bf248385eaa79ae0b0d523acb3800493e84e3c31d9c26b1dfc23867db161a
6
+ metadata.gz: ee07178fc56ffde6a07f6f1488acc6a468eda931765714b06f995e073fe539a5468e1b4c31f878761f226fe9223252d078ef43bd2d7c114b03c2352c4baa0600
7
+ data.tar.gz: 370912d590a0243d8f2b532a49e513c87855cfe8ebf3d6d1e6bad896e5011c3fb9fcff932a09fdcefb1d7bef4ebfbf5153f023cac9ca2c2769747c2984d0168f
Binary file
data.tar.gz.sig CHANGED
Binary file
data/.yardopts CHANGED
@@ -3,5 +3,6 @@
3
3
  --markup markdown
4
4
  --default-return void
5
5
  -
6
+ Filtering.md
6
7
  Changelog.md
7
8
  License.txt
@@ -1,3 +1,84 @@
1
+ ### 3.2.0 / 2015-02-03
2
+ [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.1.7...v3.2.0)
3
+
4
+ Enhancements:
5
+
6
+ * Improve the `inspect` output of example groups. (Mike Dalton, #1687)
7
+ * When rake task fails, only output the command if `verbose` flag is
8
+ set. (Ben Snape, #1704)
9
+ * Add `RSpec.clear_examples` as a clear way to reset examples in between
10
+ spec runs, whilst retaining user configuration. (Alexey Fedorov, #1706)
11
+ * Reduce string allocations when defining and running examples by 70%
12
+ and 50% respectively. (Myron Marston, #1738)
13
+ * Removed dependency on pathname from stdlib. (Sam Phippen, #1703)
14
+ * Improve the message presented when a user hits Ctrl-C.
15
+ (Alex Chaffee #1717, #1742)
16
+ * Improve shared example group inclusion backtrace displayed
17
+ in failed example output so that it works for all methods
18
+ of including shared example groups and shows all inclusion
19
+ locations. (Myron Marston, #1763)
20
+ * Issue seed notification at start (as well as the end) of the reporter
21
+ run. (Arlandis Word, #1761)
22
+ * Improve the documentation of around hooks. (Jim Kingdon, #1772)
23
+ * Support prepending of modules into example groups from config and allow
24
+ filtering based on metadata. (Arlandis Word, #1806)
25
+ * Emit warnings when `:suite` hooks are registered on an example group
26
+ (where it has always been ignored) or are registered with metadata
27
+ (which has always been ignored). (Myron Marston, #1805)
28
+ * Provide a friendly error message when users call RSpec example group
29
+ APIs (e.g. `context`, `describe`, `it`, `let`, `before`, etc) from
30
+ within an example where those APIs are unavailable. (Myron Marston, #1819)
31
+ * Provide a friendly error message when users call RSpec example
32
+ APIs (e.g. `expect`, `double`, `stub_const`, etc) from
33
+ within an example group where those APIs are unavailable.
34
+ (Myron Marston, #1819)
35
+ * Add new `RSpec::Core::Sandbox.sandboxed { }` API that facilitates
36
+ testing RSpec with RSpec, allowing you to define example groups
37
+ and example from within an example without affecting the global
38
+ `RSpec.world` state. (Tyler Ball, 1808)
39
+ * Apply line-number filters only to the files they are scoped to,
40
+ allowing you to mix filtered and unfiltered files. (Myron Marston, #1839)
41
+ * When dumping pending examples, include the failure details so that you
42
+ don't have to un-pend the example to see it. (Myron Marston, #1844)
43
+ * Make `-I` option support multiple values when separated by
44
+ `File::PATH_SEPARATOR`, such as `rspec -I foo:bar`. This matches
45
+ the behavior of Ruby's `-I` option. (Fumiaki Matsushima, #1855).
46
+
47
+ Bug Fixes:
48
+
49
+ * When assigning generated example descriptions, surface errors
50
+ raised by `matcher.description` in the example description.
51
+ (Myron Marston, #1771)
52
+ * Don't consider expectations from `after` hooks when generating
53
+ example descriptions. (Myron Marston, #1771)
54
+ * Don't apply metadata-filtered config hooks to examples in groups
55
+ with matching metadata when those examples override the parent
56
+ metadata value to not match. (Myron Marston, #1796)
57
+ * Fix `config.expect_with :minitest` so that `skip` uses RSpec's
58
+ implementation rather than Minitest's. (Jonathan Rochkind, #1822)
59
+ * Fix `NameError` caused when duplicate example group aliases are defined and
60
+ the DSL is not globally exposed. (Aaron Kromer, #1825)
61
+ * When a shared example defined in an external file fails, use the host
62
+ example group (from a loaded spec file) for the re-run command to
63
+ ensure the command will actually work. (Myron Marston, #1835)
64
+ * Fix location filtering to work properly for examples defined in
65
+ a nested example group within a shared example group defined in
66
+ an external file. (Bradley Schaefer, Xavier Shay, Myron Marston, #1837)
67
+ * When a pending example fails (as expected) due to a mock expectation,
68
+ set `RSpec::Core::Example::ExecutionResult#pending_exception` --
69
+ previously it was not being set but should have been. (Myron Marston, #1844)
70
+ * Fix rake task to work when `rspec-core` is installed in a directory
71
+ containing a space. (Guido Günther, #1845)
72
+ * Fix regression in 3.1 that caused `describe Regexp` to raise errors.
73
+ (Durran Jordan, #1853)
74
+ * Fix regression in 3.x that caused the profile information to be printed
75
+ after the summary. (Max Lincoln, #1857)
76
+ * Apply `--seed` before loading `--require` files so that required files
77
+ can access the provided seed. (Myron Marston, #1745)
78
+ * Handle `RSpec::Core::Formatters::DeprecationFormatter::FileStream` being
79
+ reopened with an IO stream, which sometimes happens with spring.
80
+ (Kevin Mook, #1757)
81
+
1
82
  ### 3.1.7 / 2014-10-11
2
83
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.1.6...v3.1.7)
3
84
 
@@ -456,6 +537,9 @@ Bug Fixes:
456
537
  directory (was broken in beta1). (Jon Rowe)
457
538
  * Prevent RSpec mangling file names that have substrings containing `line_number`
458
539
  or `default_path`. (Matijs van Zuijlen)
540
+ * Fix failure line detection so that it handles relative file paths
541
+ (which can happen when running specs through `ruby` using `rspec/autorun`).
542
+ (Myron Marston, #1829)
459
543
 
460
544
  ### 3.0.0.beta1 / 2013-11-07
461
545
  [Full Changelog](http://github.com/rspec/rspec-core/compare/v2.99.1...v3.0.0.beta1)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # rspec-core [![Build Status](https://secure.travis-ci.org/rspec/rspec-core.png?branch=master)](http://travis-ci.org/rspec/rspec-core) [![Code Climate](https://codeclimate.com/github/rspec/rspec-core.png)](https://codeclimate.com/github/rspec/rspec-core)
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)
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,6 +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
14
+ RSpec repos as well. Add the following to your `Gemfile`:
15
+
16
+ ```ruby
17
+ %w[rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
18
+ gem lib, :git => "git://github.com/rspec/#{lib}.git", :branch => 'master'
19
+ end
20
+ ```
21
+
13
22
  ## basic structure
14
23
 
15
24
  RSpec uses the words "describe" and "it" so we can express concepts like a conversation:
@@ -43,18 +43,38 @@ module RSpec
43
43
 
44
44
  extend RSpec::Core::Warnings
45
45
 
46
- # Used to ensure examples get reloaded between multiple runs in
47
- # the same process.
46
+ class << self
47
+ # Setters for shared global objects
48
+ # @api private
49
+ attr_writer :configuration, :world
50
+ end
51
+
52
+ # Used to ensure examples get reloaded and user configuration gets reset to
53
+ # defaults between multiple runs in the same process.
48
54
  #
49
55
  # Users must invoke this if they want to have the configuration reset when
50
- # they use runner multiple times within the same process.
56
+ # they use the runner multiple times within the same process. Users must deal
57
+ # themselves with re-configuration of RSpec before run.
51
58
  def self.reset
52
59
  @world = nil
53
60
  @configuration = nil
54
61
  end
55
62
 
56
- # Returns the global [Configuration](RSpec/Core/Configuration) object. While you
57
- # _can_ use this method to access the configuration, the more common
63
+ # Used to ensure examples get reloaded between multiple runs in the same
64
+ # process and ensures user configuration is persisted.
65
+ #
66
+ # Users must invoke this if they want to clear all examples but preserve
67
+ # current configuration when they use the runner multiple times within the
68
+ # same process.
69
+ def self.clear_examples
70
+ world.reset
71
+ configuration.reporter.reset
72
+ configuration.start_time = ::RSpec::Core::Time.now
73
+ configuration.reset_filters
74
+ end
75
+
76
+ # Returns the global [Configuration](RSpec/Core/Configuration) object. While
77
+ # you _can_ use this method to access the configuration, the more common
58
78
  # convention is to use [RSpec.configure](RSpec#configure-class_method).
59
79
  #
60
80
  # @example
@@ -116,11 +136,11 @@ module RSpec
116
136
  # A single thread local variable so we don't excessively pollute that
117
137
  # namespace.
118
138
  def self.thread_local_metadata
119
- Thread.current[:_rspec] ||= {}
139
+ Thread.current[:_rspec] ||= { :shared_example_group_inclusions => [] }
120
140
  end
121
141
 
122
142
  # @private
123
- # Internal container for global non-configuration data
143
+ # Internal container for global non-configuration data.
124
144
  def self.world
125
145
  @world ||= RSpec::Core::World.new
126
146
  end
@@ -137,7 +157,7 @@ module RSpec
137
157
  end
138
158
  end
139
159
 
140
- # @private path to executable file
160
+ # @private path to executable file.
141
161
  def self.path_to_executable
142
162
  @path_to_executable ||= File.expand_path('../../../exe/rspec', __FILE__)
143
163
  end
@@ -60,14 +60,14 @@ module RSpec
60
60
  coerce_to(obj, Integer, :to_int)
61
61
  end
62
62
 
63
- # Used internally to make it easy to deal with optional arguments
63
+ # Used internally to make it easy to deal with optional arguments.
64
64
  # (from Rubinius)
65
65
  Undefined = Object.new
66
66
 
67
67
  # @private
68
68
  class Random
69
69
  # @private
70
- # An implementation of Mersenne Twister MT19937 in Ruby
70
+ # An implementation of Mersenne Twister MT19937 in Ruby.
71
71
  class MT19937
72
72
  STATE_SIZE = 624
73
73
  LAST_STATE = STATE_SIZE - 1
@@ -92,9 +92,10 @@ module RSpec
92
92
  end
93
93
 
94
94
  # Seed must be either an Integer (only the first 32 bits will be used)
95
- # or an Array of Integers (of which only the first 32 bits will be used)
95
+ # or an Array of Integers (of which only the first 32 bits will be
96
+ # used).
96
97
  #
97
- # No conversion or type checking is done at this level
98
+ # No conversion or type checking is done at this level.
98
99
  def seed=(seed)
99
100
  case seed
100
101
  when Integer
@@ -129,7 +130,7 @@ module RSpec
129
130
  end
130
131
  end
131
132
 
132
- # Returns a random Integer from the range 0 ... (1 << 32)
133
+ # Returns a random Integer from the range 0 ... (1 << 32).
133
134
  def random_32_bits
134
135
  next_state if @last_read >= LAST_STATE
135
136
  @last_read += 1
@@ -146,12 +147,12 @@ module RSpec
146
147
  # No argument checking is done here either.
147
148
 
148
149
  FLOAT_FACTOR = 1.0/9007199254740992.0
149
- # generates a random number on [0,1) with 53-bit resolution
150
+ # Generates a random number on [0, 1) with 53-bit resolution.
150
151
  def random_float
151
152
  ((random_32_bits >> 5) * 67108864.0 + (random_32_bits >> 6)) * FLOAT_FACTOR;
152
153
  end
153
154
 
154
- # Returns an integer within 0...upto
155
+ # Returns an integer within 0...upto.
155
156
  def random_integer(upto)
156
157
  n = upto - 1
157
158
  nb_full_32 = 0
@@ -202,7 +203,8 @@ module RSpec
202
203
  end
203
204
  end
204
205
 
205
- # Convert an Integer seed of arbitrary size to either a single 32 bit integer, or an Array of 32 bit integers
206
+ # Convert an Integer seed of arbitrary size to either a single 32 bit
207
+ # integer, or an Array of 32 bit integers.
206
208
  def self.convert_seed(seed)
207
209
  seed = seed.abs
208
210
  long_values = []
@@ -211,7 +213,8 @@ module RSpec
211
213
  seed >>= 32
212
214
  end until seed == 0
213
215
 
214
- long_values.pop if long_values[-1] == 1 && long_values.size > 1 # Done to allow any kind of sequence of integers
216
+ # Done to allow any kind of sequence of integers.
217
+ long_values.pop if long_values[-1] == 1 && long_values.size > 1
215
218
 
216
219
  long_values.size > 1 ? long_values : long_values.first
217
220
  end
@@ -32,15 +32,23 @@ module RSpec
32
32
  class Configuration
33
33
  include RSpec::Core::Hooks
34
34
 
35
+ # Module that holds `attr_reader` declarations. It's in a separate
36
+ # module to allow us to override those methods and use `super`.
37
+ # @private
38
+ Readers = Module.new
39
+ include Readers
40
+
35
41
  # @private
36
42
  class MustBeConfiguredBeforeExampleGroupsError < StandardError; end
37
43
 
38
44
  # @private
39
45
  def self.define_reader(name)
40
- define_method(name) do
41
- variable = instance_variable_defined?("@#{name}") ? instance_variable_get("@#{name}") : nil
42
- value_for(name, variable)
46
+ Readers.class_eval do
47
+ remove_method name if method_defined?(name)
48
+ attr_reader name
43
49
  end
50
+
51
+ define_method(name) { value_for(name) { super() } }
44
52
  end
45
53
 
46
54
  # @private
@@ -71,7 +79,7 @@ module RSpec
71
79
 
72
80
  # @private
73
81
  #
74
- # As `add_setting` but only add the reader
82
+ # As `add_setting` but only add the reader.
75
83
  def self.add_read_only_setting(name, opts={})
76
84
  raise "Use the instance add_setting method if you want to set a default" if opts.key?(:default)
77
85
  define_reader name
@@ -90,8 +98,8 @@ module RSpec
90
98
  # `"spec"`). Allows you to just type `rspec` instead of `rspec spec` to
91
99
  # run all the examples in the `spec` directory.
92
100
  #
93
- # Note: Other scripts invoking `rspec` indirectly will ignore this
94
- # setting.
101
+ # @note Other scripts invoking `rspec` indirectly will ignore this
102
+ # setting.
95
103
  add_setting :default_path
96
104
 
97
105
  # @macro add_setting
@@ -160,11 +168,12 @@ module RSpec
160
168
  add_setting :failure_exit_code
161
169
 
162
170
  # @macro define_reader
163
- # Indicates files configured to be required
171
+ # Indicates files configured to be required.
164
172
  define_reader :requires
165
173
 
166
174
  # @macro define_reader
167
- # Returns dirs that have been prepended to the load path by the `-I` command line option
175
+ # Returns dirs that have been prepended to the load path by the `-I`
176
+ # command line option.
168
177
  define_reader :libs
169
178
 
170
179
  # @macro add_setting
@@ -172,7 +181,7 @@ module RSpec
172
181
  # Default: `$stdout`.
173
182
  define_reader :output_stream
174
183
 
175
- # Set the output stream for reporter
184
+ # Set the output stream for reporter.
176
185
  # @attr value [IO] value for output, defaults to $stdout
177
186
  def output_stream=(value)
178
187
  if @reporter && !value.equal?(@output_stream)
@@ -186,20 +195,20 @@ module RSpec
186
195
  end
187
196
 
188
197
  # @macro define_reader
189
- # Load files matching this pattern (default: `'**{,/*/**}/*_spec.rb'`)
198
+ # Load files matching this pattern (default: `'**{,/*/**}/*_spec.rb'`).
190
199
  define_reader :pattern
191
200
 
192
- # Set pattern to match files to load
201
+ # Set pattern to match files to load.
193
202
  # @attr value [String] the filename pattern to filter spec files by
194
203
  def pattern=(value)
195
204
  update_pattern_attr :pattern, value
196
205
  end
197
206
 
198
207
  # @macro define_reader
199
- # Exclude files matching this pattern
208
+ # Exclude files matching this pattern.
200
209
  define_reader :exclude_pattern
201
210
 
202
- # Set pattern to match files to exclude
211
+ # Set pattern to match files to exclude.
203
212
  # @attr value [String] the filename pattern to exclude spec files by
204
213
  def exclude_pattern=(value)
205
214
  update_pattern_attr :exclude_pattern, value
@@ -211,84 +220,93 @@ module RSpec
211
220
  add_setting :profile_examples
212
221
 
213
222
  # @macro add_setting
214
- # Run all examples if none match the configured filters (default: `false`).
223
+ # Run all examples if none match the configured filters
224
+ # (default: `false`).
215
225
  add_setting :run_all_when_everything_filtered
216
226
 
217
227
  # @macro add_setting
218
228
  # Color to use to indicate success.
219
229
  # @param color [Symbol] defaults to `:green` but can be set to one of the
220
- # following: `[:black, :white, :red, :green, :yellow,
221
- # :blue, :magenta, :cyan]`
230
+ # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
231
+ # :cyan]`
222
232
  add_setting :success_color
223
233
 
224
234
  # @macro add_setting
225
235
  # Color to use to print pending examples.
226
236
  # @param color [Symbol] defaults to `:yellow` but can be set to one of the
227
- # following: `[:black, :white, :red, :green, :yellow,
228
- # :blue, :magenta, :cyan]`
237
+ # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
238
+ # :cyan]`
229
239
  add_setting :pending_color
230
240
 
231
241
  # @macro add_setting
232
242
  # Color to use to indicate failure.
233
243
  # @param color [Symbol] defaults to `:red` but can be set to one of the
234
- # following: `[:black, :white, :red, :green, :yellow,
235
- # :blue, :magenta, :cyan]`
244
+ # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
245
+ # :cyan]`
236
246
  add_setting :failure_color
237
247
 
238
248
  # @macro add_setting
239
249
  # The default output color.
240
250
  # @param color [Symbol] defaults to `:white` but can be set to one of the
241
- # following:`[:black, :white, :red, :green, :yellow,
242
- # :blue, :magenta, :cyan]`
251
+ # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
252
+ # :cyan]`
243
253
  add_setting :default_color
244
254
 
245
255
  # @macro add_setting
246
256
  # Color used when a pending example is fixed.
247
257
  # @param color [Symbol] defaults to `:blue` but can be set to one of the
248
- # following: `[:black, :white, :red, :green, :yellow,
249
- # :blue, :magenta, :cyan]`
258
+ # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
259
+ # :cyan]`
250
260
  add_setting :fixed_color
251
261
 
252
262
  # @macro add_setting
253
263
  # Color used to print details.
254
264
  # @param color [Symbol] defaults to `:cyan` but can be set to one of the
255
- # following: `[:black, :white, :red, :green, :yellow,
256
- # :blue, :magenta, :cyan]`
265
+ # following: `[:black, :white, :red, :green, :yellow, :blue, :magenta,
266
+ # :cyan]`
257
267
  add_setting :detail_color
258
268
 
259
269
  # Deprecated. This config option was added in RSpec 2 to pave the way
260
270
  # for this being the default behavior in RSpec 3. Now this option is
261
271
  # a no-op.
262
272
  def treat_symbols_as_metadata_keys_with_true_values=(_value)
263
- RSpec.deprecate("RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values=",
264
- :message => "RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values= " \
265
- "is deprecated, it is now set to true as default and setting it to false has no effect.")
273
+ RSpec.deprecate(
274
+ "RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values=",
275
+ :message => "RSpec::Core::Configuration#treat_symbols_as_metadata_keys_with_true_values= " \
276
+ "is deprecated, it is now set to true as default and " \
277
+ "setting it to false has no effect."
278
+ )
266
279
  end
267
280
 
268
- # Record the start time of the spec suite to measure load time
281
+ # Record the start time of the spec suite to measure load time.
269
282
  add_setting :start_time
270
283
 
271
284
  # @private
272
285
  add_setting :tty
273
286
  # @private
274
- add_setting :include_or_extend_modules
275
- # @private
276
287
  attr_writer :files_to_run
277
288
  # @private
278
- add_setting :expecting_with_rspec
279
- # @private
280
289
  attr_accessor :filter_manager
281
290
  # @private
282
- attr_reader :backtrace_formatter, :ordering_manager
291
+ attr_accessor :static_config_filter_manager
292
+ # @private
293
+ attr_reader :backtrace_formatter, :ordering_manager, :loaded_spec_files
283
294
 
284
295
  def initialize
285
296
  # rubocop:disable Style/GlobalVars
286
297
  @start_time = $_rspec_core_load_started_at || ::RSpec::Core::Time.now
287
298
  # rubocop:enable Style/GlobalVars
288
299
  @expectation_frameworks = []
289
- @include_or_extend_modules = []
300
+ @include_modules = FilterableItemRepository::QueryOptimized.new(:any?)
301
+ @extend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
302
+ @prepend_modules = FilterableItemRepository::QueryOptimized.new(:any?)
303
+
304
+ @before_suite_hooks = []
305
+ @after_suite_hooks = []
306
+
290
307
  @mock_framework = nil
291
308
  @files_or_directories_to_run = []
309
+ @loaded_spec_files = Set.new
292
310
  @color = false
293
311
  @pattern = '**{,/*/**}/*_spec.rb'
294
312
  @exclude_pattern = ''
@@ -303,6 +321,7 @@ module RSpec
303
321
  @reporter = nil
304
322
  @reporter_buffer = nil
305
323
  @filter_manager = FilterManager.new
324
+ @static_config_filter_manager = FilterManager.new
306
325
  @ordering_manager = Ordering::ConfigurationManager.new
307
326
  @preferred_options = {}
308
327
  @failure_color = :red
@@ -314,7 +333,7 @@ module RSpec
314
333
  @profile_examples = false
315
334
  @requires = []
316
335
  @libs = []
317
- @derived_metadata_blocks = []
336
+ @derived_metadata_blocks = FilterableItemRepository::QueryOptimized.new(:any?)
318
337
  end
319
338
 
320
339
  # @private
@@ -332,18 +351,29 @@ module RSpec
332
351
  @formatter_loader = nil
333
352
  end
334
353
 
354
+ # @private
355
+ def reset_filters
356
+ self.filter_manager = FilterManager.new
357
+ filter_manager.include_only(
358
+ Metadata.deep_hash_dup(static_config_filter_manager.inclusions.rules)
359
+ )
360
+ filter_manager.exclude_only(
361
+ Metadata.deep_hash_dup(static_config_filter_manager.exclusions.rules)
362
+ )
363
+ end
364
+
335
365
  # @overload add_setting(name)
336
366
  # @overload add_setting(name, opts)
337
367
  # @option opts [Symbol] :default
338
368
  #
339
- # set a default value for the generated getter and predicate methods:
369
+ # Set a default value for the generated getter and predicate methods:
340
370
  #
341
371
  # add_setting(:foo, :default => "default value")
342
372
  #
343
373
  # @option opts [Symbol] :alias_with
344
374
  #
345
- # Use `:alias_with` to alias the setter, getter, and predicate to another
346
- # name, or names:
375
+ # Use `:alias_with` to alias the setter, getter, and predicate to
376
+ # another name, or names:
347
377
  #
348
378
  # add_setting(:foo, :alias_with => :bar)
349
379
  # add_setting(:foo, :alias_with => [:bar, :baz])
@@ -366,7 +396,7 @@ module RSpec
366
396
  #
367
397
  # RSpec.configuration.foo=(value)
368
398
  # RSpec.configuration.foo
369
- # RSpec.configuration.foo? # returns true if foo returns anything but nil or false
399
+ # RSpec.configuration.foo? # Returns true if foo returns anything but nil or false.
370
400
  def add_setting(name, opts={})
371
401
  default = opts.delete(:default)
372
402
  (class << self; self; end).class_exec do
@@ -375,7 +405,7 @@ module RSpec
375
405
  __send__("#{name}=", default) if default
376
406
  end
377
407
 
378
- # Returns the configured mock framework adapter module
408
+ # Returns the configured mock framework adapter module.
379
409
  def mock_framework
380
410
  if @mock_framework.nil?
381
411
  begin
@@ -387,7 +417,7 @@ module RSpec
387
417
  @mock_framework
388
418
  end
389
419
 
390
- # Delegates to mock_framework=(framework)
420
+ # Delegates to mock_framework=(framework).
391
421
  def mock_framework=(framework)
392
422
  mock_with framework
393
423
  end
@@ -395,19 +425,19 @@ module RSpec
395
425
  # Regexps used to exclude lines from backtraces.
396
426
  #
397
427
  # Excludes lines from ruby (and jruby) source, installed gems, anything
398
- # in any "bin" directory, and any of the rspec libs (outside gem
428
+ # in any "bin" directory, and any of the RSpec libs (outside gem
399
429
  # installs) by default.
400
430
  #
401
431
  # You can modify the list via the getter, or replace it with the setter.
402
432
  #
403
433
  # To override this behaviour and display a full backtrace, use
404
- # `--backtrace`on the command line, in a `.rspec` file, or in the
434
+ # `--backtrace` on the command line, in a `.rspec` file, or in the
405
435
  # `rspec_options` attribute of RSpec's rake task.
406
436
  def backtrace_exclusion_patterns
407
437
  @backtrace_formatter.exclusion_patterns
408
438
  end
409
439
 
410
- # Set regular expressions used to exclude lines in backtrace
440
+ # Set regular expressions used to exclude lines in backtrace.
411
441
  # @param patterns [Regexp] set the backtrace exlusion pattern
412
442
  def backtrace_exclusion_patterns=(patterns)
413
443
  @backtrace_formatter.exclusion_patterns = patterns
@@ -425,7 +455,7 @@ module RSpec
425
455
  @backtrace_formatter.inclusion_patterns
426
456
  end
427
457
 
428
- # Set regular expressions used to include lines in backtrace
458
+ # Set regular expressions used to include lines in backtrace.
429
459
  # @attr patterns [Regexp] set backtrace_formatter inclusion_patterns
430
460
  def backtrace_inclusion_patterns=(patterns)
431
461
  @backtrace_formatter.inclusion_patterns = patterns
@@ -485,8 +515,8 @@ module RSpec
485
515
  # teardown_mocks_for_rspec
486
516
  # - called after verify_mocks_for_rspec (even if there are errors)
487
517
  #
488
- # If the module responds to `configuration` and `mock_with` receives a block,
489
- # it will yield the configuration object to the block e.g.
518
+ # If the module responds to `configuration` and `mock_with` receives a
519
+ # block, it will yield the configuration object to the block e.g.
490
520
  #
491
521
  # config.mock_with OtherMockFrameworkAdapter do |mod_config|
492
522
  # mod_config.custom_setting = true
@@ -515,7 +545,8 @@ module RSpec
515
545
  end
516
546
 
517
547
  if block_given?
518
- raise "#{framework_module} must respond to `configuration` so that mock_with can yield it." unless framework_module.respond_to?(:configuration)
548
+ raise "#{framework_module} must respond to `configuration` so that " \
549
+ "mock_with can yield it." unless framework_module.respond_to?(:configuration)
519
550
  yield framework_module.configuration
520
551
  end
521
552
 
@@ -534,7 +565,7 @@ module RSpec
534
565
  @expectation_frameworks
535
566
  end
536
567
 
537
- # Delegates to expect_with(framework)
568
+ # Delegates to expect_with(framework).
538
569
  def expectation_framework=(framework)
539
570
  expect_with(framework)
540
571
  end
@@ -569,7 +600,6 @@ module RSpec
569
600
  framework
570
601
  when :rspec
571
602
  require 'rspec/expectations'
572
- self.expecting_with_rspec = true
573
603
  ::RSpec::Matchers
574
604
  when :test_unit
575
605
  require 'rspec/core/test_unit_assertions_adapter'
@@ -587,21 +617,24 @@ module RSpec
587
617
  end
588
618
 
589
619
  if block_given?
590
- raise "expect_with only accepts a block with a single argument. Call expect_with #{modules.length} times, once with each argument, instead." if modules.length > 1
591
- raise "#{modules.first} must respond to `configuration` so that expect_with can yield it." unless modules.first.respond_to?(:configuration)
620
+ raise "expect_with only accepts a block with a single argument. " \
621
+ "Call expect_with #{modules.length} times, " \
622
+ "once with each argument, instead." if modules.length > 1
623
+ raise "#{modules.first} must respond to `configuration` so that " \
624
+ "expect_with can yield it." unless modules.first.respond_to?(:configuration)
592
625
  yield modules.first.configuration
593
626
  end
594
627
 
595
628
  @expectation_frameworks.push(*modules)
596
629
  end
597
630
 
598
- # Check if full backtrace is enabled
631
+ # Check if full backtrace is enabled.
599
632
  # @return [Boolean] is full backtrace enabled
600
633
  def full_backtrace?
601
634
  @backtrace_formatter.full_backtrace?
602
635
  end
603
636
 
604
- # Toggle full backtrace
637
+ # Toggle full backtrace.
605
638
  # @attr true_or_false [Boolean] toggle full backtrace display
606
639
  def full_backtrace=(true_or_false)
607
640
  @backtrace_formatter.full_backtrace = true_or_false
@@ -613,10 +646,10 @@ module RSpec
613
646
  # @see color_enabled?
614
647
  # @return [Boolean]
615
648
  def color
616
- value_for(:color, @color)
649
+ value_for(:color) { @color }
617
650
  end
618
651
 
619
- # Check if color is enabled for a particular output
652
+ # Check if color is enabled for a particular output.
620
653
  # @param output [IO] an output stream to use, defaults to the current
621
654
  # `output_stream`
622
655
  # @return [Boolean]
@@ -624,13 +657,15 @@ module RSpec
624
657
  output_to_tty?(output) && color
625
658
  end
626
659
 
627
- # Toggle output color
660
+ # Toggle output color.
628
661
  # @attr true_or_false [Boolean] toggle color enabled
629
662
  def color=(true_or_false)
630
663
  return unless true_or_false
631
664
 
632
- if RSpec.world.windows_os? && !ENV['ANSICON']
633
- RSpec.warning "You must use ANSICON 1.31 or later (http://adoxa.3eeweb.com/ansicon/) to use colour on Windows"
665
+ if RSpec::Support::OS.windows? && !ENV['ANSICON']
666
+ RSpec.warning "You must use ANSICON 1.31 or later " \
667
+ "(http://adoxa.3eeweb.com/ansicon/) to use colour " \
668
+ "on Windows"
634
669
  @color = false
635
670
  else
636
671
  @color = true
@@ -743,10 +778,10 @@ module RSpec
743
778
 
744
779
  # @api private
745
780
  #
746
- # Defaults `profile_examples` to 10 examples when `@profile_examples` is `true`.
747
- #
781
+ # Defaults `profile_examples` to 10 examples when `@profile_examples` is
782
+ # `true`.
748
783
  def profile_examples
749
- profile = value_for(:profile_examples, @profile_examples)
784
+ profile = value_for(:profile_examples) { @profile_examples }
750
785
  if profile && !profile.is_a?(Integer)
751
786
  10
752
787
  else
@@ -762,7 +797,7 @@ module RSpec
762
797
  @files_to_run = nil
763
798
  end
764
799
 
765
- # The spec files RSpec will run
800
+ # The spec files RSpec will run.
766
801
  # @return [Array] specified files about to run
767
802
  def files_to_run
768
803
  @files_to_run ||= get_files_to_run(@files_or_directories_to_run)
@@ -776,8 +811,8 @@ module RSpec
776
811
  # @note The specific example alias below (`pending`) is already
777
812
  # defined for you.
778
813
  # @note Use with caution. This extends the language used in your
779
- # specs, but does not add any additional documentation. We use this
780
- # in rspec to define methods like `focus` and `xit`, but we also add
814
+ # specs, but does not add any additional documentation. We use this
815
+ # in RSpec to define methods like `focus` and `xit`, but we also add
781
816
  # docs for those methods.
782
817
  #
783
818
  # @example
@@ -860,8 +895,8 @@ module RSpec
860
895
  # # ...sortability examples here
861
896
  #
862
897
  # @note Use with caution. This extends the language used in your
863
- # specs, but does not add any additional documentation. We use this
864
- # in rspec to define `it_should_behave_like` (for backward
898
+ # specs, but does not add any additional documentation. We use this
899
+ # in RSpec to define `it_should_behave_like` (for backward
865
900
  # compatibility), but we also add docs for that method.
866
901
  def alias_it_behaves_like_to(new_name, report_label='')
867
902
  RSpec::Core::ExampleGroup.define_nested_shared_group_method(new_name, report_label)
@@ -878,28 +913,30 @@ module RSpec
878
913
  # or config files (e.g. `.rspec`).
879
914
  #
880
915
  # @example
881
- # # given this declaration
916
+ # # Given this declaration.
882
917
  # describe "something", :foo => 'bar' do
883
918
  # # ...
884
919
  # end
885
920
  #
886
- # # any of the following will include that group
921
+ # # Any of the following will include that group.
887
922
  # config.filter_run_including :foo => 'bar'
888
923
  # config.filter_run_including :foo => /^ba/
889
924
  # config.filter_run_including :foo => lambda {|v| v == 'bar'}
890
925
  # config.filter_run_including :foo => lambda {|v,m| m[:foo] == 'bar'}
891
926
  #
892
- # # given a proc with an arity of 1, the lambda is passed the value related to the key, e.g.
927
+ # # Given a proc with an arity of 1, the lambda is passed the value
928
+ # # related to the key, e.g.
893
929
  # config.filter_run_including :foo => lambda {|v| v == 'bar'}
894
930
  #
895
- # # given a proc with an arity of 2, the lambda is passed the value related to the key,
896
- # # and the metadata itself e.g.
931
+ # # Given a proc with an arity of 2, the lambda is passed the value
932
+ # # related to the key, and the metadata itself e.g.
897
933
  # config.filter_run_including :foo => lambda {|v,m| m[:foo] == 'bar'}
898
934
  #
899
935
  # filter_run_including :foo # same as filter_run_including :foo => true
900
936
  def filter_run_including(*args)
901
937
  meta = Metadata.build_hash_from(args, :warn_about_example_group_filtering)
902
938
  filter_manager.include_with_low_priority meta
939
+ static_config_filter_manager.include_with_low_priority Metadata.deep_hash_dup(meta)
903
940
  end
904
941
 
905
942
  alias_method :filter_run, :filter_run_including
@@ -936,28 +973,30 @@ module RSpec
936
973
  # or config files (e.g. `.rspec`).
937
974
  #
938
975
  # @example
939
- # # given this declaration
976
+ # # Given this declaration.
940
977
  # describe "something", :foo => 'bar' do
941
978
  # # ...
942
979
  # end
943
980
  #
944
- # # any of the following will exclude that group
981
+ # # Any of the following will exclude that group.
945
982
  # config.filter_run_excluding :foo => 'bar'
946
983
  # config.filter_run_excluding :foo => /^ba/
947
984
  # config.filter_run_excluding :foo => lambda {|v| v == 'bar'}
948
985
  # config.filter_run_excluding :foo => lambda {|v,m| m[:foo] == 'bar'}
949
986
  #
950
- # # given a proc with an arity of 1, the lambda is passed the value related to the key, e.g.
987
+ # # Given a proc with an arity of 1, the lambda is passed the value
988
+ # # related to the key, e.g.
951
989
  # config.filter_run_excluding :foo => lambda {|v| v == 'bar'}
952
990
  #
953
- # # given a proc with an arity of 2, the lambda is passed the value related to the key,
954
- # # and the metadata itself e.g.
991
+ # # Given a proc with an arity of 2, the lambda is passed the value
992
+ # # related to the key, and the metadata itself e.g.
955
993
  # config.filter_run_excluding :foo => lambda {|v,m| m[:foo] == 'bar'}
956
994
  #
957
995
  # filter_run_excluding :foo # same as filter_run_excluding :foo => true
958
996
  def filter_run_excluding(*args)
959
997
  meta = Metadata.build_hash_from(args, :warn_about_example_group_filtering)
960
998
  filter_manager.exclude_with_low_priority meta
999
+ static_config_filter_manager.exclude_with_low_priority Metadata.deep_hash_dup(meta)
961
1000
  end
962
1001
 
963
1002
  # Clears and reassigns the `exclusion_filter`. Set to `nil` if you don't
@@ -979,8 +1018,8 @@ module RSpec
979
1018
  end
980
1019
 
981
1020
  # Tells RSpec to include `mod` in example groups. Methods defined in
982
- # `mod` are exposed to examples (not example groups). Use `filters` to
983
- # constrain the groups in which to include the module.
1021
+ # `mod` are exposed to examples (not example groups). Use `filters` to
1022
+ # constrain the groups or examples in which to include the module.
984
1023
  #
985
1024
  # @example
986
1025
  #
@@ -1009,14 +1048,22 @@ module RSpec
1009
1048
  # end
1010
1049
  # end
1011
1050
  #
1051
+ # @note Filtered module inclusions can also be applied to
1052
+ # individual examples that have matching metadata. Just like
1053
+ # Ruby's object model is that every object has a singleton class
1054
+ # which has only a single instance, RSpec's model is that every
1055
+ # example has a singleton example group containing just the one
1056
+ # example.
1057
+ #
1012
1058
  # @see #extend
1059
+ # @see #prepend
1013
1060
  def include(mod, *filters)
1014
1061
  meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1015
- include_or_extend_modules << [:include, mod, meta]
1062
+ @include_modules.append(mod, meta)
1016
1063
  end
1017
1064
 
1018
- # Tells RSpec to extend example groups with `mod`. Methods defined in
1019
- # `mod` are exposed to example groups (not examples). Use `filters` to
1065
+ # Tells RSpec to extend example groups with `mod`. Methods defined in
1066
+ # `mod` are exposed to example groups (not examples). Use `filters` to
1020
1067
  # constrain the groups to extend.
1021
1068
  #
1022
1069
  # Similar to `include`, but behavior is added to example groups, which
@@ -1044,25 +1091,87 @@ module RSpec
1044
1091
  # end
1045
1092
  #
1046
1093
  # @see #include
1094
+ # @see #prepend
1047
1095
  def extend(mod, *filters)
1048
1096
  meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1049
- include_or_extend_modules << [:extend, mod, meta]
1097
+ @extend_modules.append(mod, meta)
1098
+ end
1099
+
1100
+ if RSpec::Support::RubyFeatures.module_prepends_supported?
1101
+ # Tells RSpec to prepend example groups with `mod`. Methods defined in
1102
+ # `mod` are exposed to examples (not example groups). Use `filters` to
1103
+ # constrain the groups in which to prepend the module.
1104
+ #
1105
+ # Similar to `include`, but module is included before the example group's class
1106
+ # in the ancestor chain.
1107
+ #
1108
+ # @example
1109
+ #
1110
+ # module OverrideMod
1111
+ # def override_me
1112
+ # "overridden"
1113
+ # end
1114
+ # end
1115
+ #
1116
+ # RSpec.configure do |config|
1117
+ # config.prepend(OverrideMod, :method => :prepend)
1118
+ # end
1119
+ #
1120
+ # describe "overriding example's class", :method => :prepend do
1121
+ # it "finds the user" do
1122
+ # self.class.class_eval do
1123
+ # def override_me
1124
+ # end
1125
+ # end
1126
+ # override_me # => "overridden"
1127
+ # # ...
1128
+ # end
1129
+ # end
1130
+ #
1131
+ # @see #include
1132
+ # @see #extend
1133
+ def prepend(mod, *filters)
1134
+ meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1135
+ @prepend_modules.append(mod, meta)
1136
+ end
1050
1137
  end
1051
1138
 
1052
1139
  # @private
1053
1140
  #
1054
- # Used internally to extend a group with modules using `include` and/or
1141
+ # Used internally to extend a group with modules using `include`, `prepend` and/or
1055
1142
  # `extend`.
1056
1143
  def configure_group(group)
1057
- include_or_extend_modules.each do |include_or_extend, mod, filters|
1058
- next unless filters.empty? || group.any_apply?(filters)
1059
- __send__("safe_#{include_or_extend}", mod, group)
1144
+ configure_group_with group, @include_modules, :safe_include
1145
+ configure_group_with group, @extend_modules, :safe_extend
1146
+ configure_group_with group, @prepend_modules, :safe_prepend
1147
+ end
1148
+
1149
+ # @private
1150
+ def configure_group_with(group, module_list, application_method)
1151
+ module_list.items_for(group.metadata).each do |mod|
1152
+ __send__(application_method, mod, group)
1060
1153
  end
1061
1154
  end
1062
1155
 
1063
1156
  # @private
1064
- def safe_include(mod, host)
1065
- host.__send__(:include, mod) unless host < mod
1157
+ #
1158
+ # Used internally to extend the singleton class of a single example's
1159
+ # example group instance with modules using `include` and/or `extend`.
1160
+ def configure_example(example)
1161
+ # We replace the metadata so that SharedExampleGroupModule#included
1162
+ # has access to the example's metadata[:location].
1163
+ example.example_group_instance.singleton_class.with_replaced_metadata(example.metadata) do
1164
+ @include_modules.items_for(example.metadata).each do |mod|
1165
+ safe_include(mod, example.example_group_instance.singleton_class)
1166
+ end
1167
+ end
1168
+ end
1169
+
1170
+ if RSpec::Support::RubyFeatures.module_prepends_supported?
1171
+ # @private
1172
+ def safe_prepend(mod, host)
1173
+ host.__send__(:prepend, mod) unless host < mod
1174
+ end
1066
1175
  end
1067
1176
 
1068
1177
  # @private
@@ -1075,11 +1184,21 @@ module RSpec
1075
1184
 
1076
1185
  # @private
1077
1186
  if RUBY_VERSION.to_f >= 1.9
1187
+ # @private
1188
+ def safe_include(mod, host)
1189
+ host.__send__(:include, mod) unless host < mod
1190
+ end
1191
+
1078
1192
  # @private
1079
1193
  def safe_extend(mod, host)
1080
1194
  host.extend(mod) unless host.singleton_class < mod
1081
1195
  end
1082
1196
  else
1197
+ # @private
1198
+ def safe_include(mod, host)
1199
+ host.__send__(:include, mod) unless host.included_modules.include?(mod)
1200
+ end
1201
+
1083
1202
  # @private
1084
1203
  def safe_extend(mod, host)
1085
1204
  host.extend(mod) unless (class << host; self; end).included_modules.include?(mod)
@@ -1102,7 +1221,12 @@ module RSpec
1102
1221
 
1103
1222
  # @private
1104
1223
  def load_spec_files
1105
- files_to_run.uniq.each { |f| load File.expand_path(f) }
1224
+ files_to_run.uniq.each do |f|
1225
+ file = File.expand_path(f)
1226
+ load file
1227
+ loaded_spec_files << file
1228
+ end
1229
+
1106
1230
  @spec_files_loaded = true
1107
1231
  end
1108
1232
 
@@ -1112,7 +1236,8 @@ module RSpec
1112
1236
  # Formats the docstring output using the block provided.
1113
1237
  #
1114
1238
  # @example
1115
- # # This will strip the descriptions of both examples and example groups.
1239
+ # # This will strip the descriptions of both examples and example
1240
+ # # groups.
1116
1241
  # RSpec.configure do |config|
1117
1242
  # config.format_docstrings { |s| s.strip }
1118
1243
  # end
@@ -1157,7 +1282,8 @@ module RSpec
1157
1282
 
1158
1283
  # @macro delegate_to_ordering_manager
1159
1284
  #
1160
- # Sets the default global order and, if order is `'rand:<seed>'`, also sets the seed.
1285
+ # Sets the default global order and, if order is `'rand:<seed>'`, also
1286
+ # sets the seed.
1161
1287
  delegate_to_ordering_manager :order=
1162
1288
 
1163
1289
  # @macro delegate_to_ordering_manager
@@ -1167,8 +1293,10 @@ module RSpec
1167
1293
  #
1168
1294
  # @param name [Symbol] The name of the ordering.
1169
1295
  # @yield Block that will order the given examples or example groups
1170
- # @yieldparam list [Array<RSpec::Core::Example>, Array<RSpec::Core::ExampleGroup>] The examples or groups to order
1171
- # @yieldreturn [Array<RSpec::Core::Example>, Array<RSpec::Core::ExampleGroup>] The re-ordered examples or groups
1296
+ # @yieldparam list [Array<RSpec::Core::Example>,
1297
+ # Array<RSpec::Core::ExampleGroup>] The examples or groups to order
1298
+ # @yieldreturn [Array<RSpec::Core::Example>,
1299
+ # Array<RSpec::Core::ExampleGroup>] The re-ordered examples or groups
1172
1300
  #
1173
1301
  # @example
1174
1302
  # RSpec.configure do |rspec|
@@ -1189,7 +1317,7 @@ module RSpec
1189
1317
  # @private
1190
1318
  delegate_to_ordering_manager :seed_used?, :ordering_registry
1191
1319
 
1192
- # Set Ruby warnings on or off
1320
+ # Set Ruby warnings on or off.
1193
1321
  def warnings=(value)
1194
1322
  $VERBOSE = !!value
1195
1323
  end
@@ -1252,7 +1380,7 @@ module RSpec
1252
1380
  # `shared_examples_for`, etc) onto `main` and `Module`, instead
1253
1381
  # requiring you to prefix these methods with `RSpec.`. It enables
1254
1382
  # expect-only syntax for rspec-mocks and rspec-expectations. It
1255
- # simply disables monkey patching on whatever pieces of rspec
1383
+ # simply disables monkey patching on whatever pieces of RSpec
1256
1384
  # the user is using.
1257
1385
  #
1258
1386
  # @note It configures rspec-mocks and rspec-expectations only
@@ -1265,7 +1393,7 @@ module RSpec
1265
1393
  #
1266
1394
  # @example
1267
1395
  #
1268
- # # It disables all monkey patching
1396
+ # # It disables all monkey patching.
1269
1397
  # RSpec.configure do |config|
1270
1398
  # config.disable_monkey_patching!
1271
1399
  # end
@@ -1295,33 +1423,142 @@ module RSpec
1295
1423
 
1296
1424
  # Defines a callback that can assign derived metadata values.
1297
1425
  #
1298
- # @param filters [Array<Symbol>, Hash] metadata filters that determine which example
1299
- # or group metadata hashes the callback will be triggered for. If none are given,
1300
- # the callback will be run against the metadata hashes of all groups and examples.
1301
- # @yieldparam metadata [Hash] original metadata hash from an example or group. Mutate this in
1302
- # your block as needed.
1426
+ # @param filters [Array<Symbol>, Hash] metadata filters that determine
1427
+ # which example or group metadata hashes the callback will be triggered
1428
+ # for. If none are given, the callback will be run against the metadata
1429
+ # hashes of all groups and examples.
1430
+ # @yieldparam metadata [Hash] original metadata hash from an example or
1431
+ # group. Mutate this in your block as needed.
1303
1432
  #
1304
1433
  # @example
1305
1434
  # RSpec.configure do |config|
1306
- # # Tag all groups and examples in the spec/unit directory with :type => :unit
1435
+ # # Tag all groups and examples in the spec/unit directory with
1436
+ # # :type => :unit
1307
1437
  # config.define_derived_metadata(:file_path => %r{/spec/unit/}) do |metadata|
1308
1438
  # metadata[:type] = :unit
1309
1439
  # end
1310
1440
  # end
1311
1441
  def define_derived_metadata(*filters, &block)
1312
1442
  meta = Metadata.build_hash_from(filters, :warn_about_example_group_filtering)
1313
- @derived_metadata_blocks << [meta, block]
1443
+ @derived_metadata_blocks.append(block, meta)
1314
1444
  end
1315
1445
 
1316
1446
  # @private
1317
1447
  def apply_derived_metadata_to(metadata)
1318
- @derived_metadata_blocks.each do |filter, block|
1319
- block.call(metadata) if filter.empty? || MetadataFilter.any_apply?(filter, metadata)
1448
+ @derived_metadata_blocks.items_for(metadata).each do |block|
1449
+ block.call(metadata)
1320
1450
  end
1321
1451
  end
1322
1452
 
1453
+ # Defines a `before` hook. See {Hooks#before} for full docs.
1454
+ #
1455
+ # This method differs from {Hooks#before} in only one way: it supports
1456
+ # the `:suite` scope. Hooks with the `:suite` scope will be run once before
1457
+ # the first example of the entire suite is executed.
1458
+ #
1459
+ # @see #prepend_before
1460
+ # @see #after
1461
+ # @see #append_after
1462
+ def before(*args, &block)
1463
+ handle_suite_hook(args, @before_suite_hooks, :push,
1464
+ Hooks::BeforeHook, block) || super(*args, &block)
1465
+ end
1466
+ alias_method :append_before, :before
1467
+
1468
+ # Adds `block` to the start of the list of `before` blocks in the same
1469
+ # scope (`:example`, `:context`, or `:suite`), in contrast to {#before},
1470
+ # which adds the hook to the end of the list.
1471
+ #
1472
+ # See {Hooks#before} for full `before` hook docs.
1473
+ #
1474
+ # This method differs from {Hooks#prepend_before} in only one way: it supports
1475
+ # the `:suite` scope. Hooks with the `:suite` scope will be run once before
1476
+ # the first example of the entire suite is executed.
1477
+ #
1478
+ # @see #before
1479
+ # @see #after
1480
+ # @see #append_after
1481
+ def prepend_before(*args, &block)
1482
+ handle_suite_hook(args, @before_suite_hooks, :unshift,
1483
+ Hooks::BeforeHook, block) || super(*args, &block)
1484
+ end
1485
+
1486
+ # Defines a `after` hook. See {Hooks#after} for full docs.
1487
+ #
1488
+ # This method differs from {Hooks#after} in only one way: it supports
1489
+ # the `:suite` scope. Hooks with the `:suite` scope will be run once after
1490
+ # the last example of the entire suite is executed.
1491
+ #
1492
+ # @see #append_after
1493
+ # @see #before
1494
+ # @see #prepend_before
1495
+ def after(*args, &block)
1496
+ handle_suite_hook(args, @after_suite_hooks, :unshift,
1497
+ Hooks::AfterHook, block) || super(*args, &block)
1498
+ end
1499
+ alias_method :prepend_after, :after
1500
+
1501
+ # Adds `block` to the end of the list of `after` blocks in the same
1502
+ # scope (`:example`, `:context`, or `:suite`), in contrast to {#after},
1503
+ # which adds the hook to the start of the list.
1504
+ #
1505
+ # See {Hooks#after} for full `after` hook docs.
1506
+ #
1507
+ # This method differs from {Hooks#append_after} in only one way: it supports
1508
+ # the `:suite` scope. Hooks with the `:suite` scope will be run once after
1509
+ # the last example of the entire suite is executed.
1510
+ #
1511
+ # @see #append_after
1512
+ # @see #before
1513
+ # @see #prepend_before
1514
+ def append_after(*args, &block)
1515
+ handle_suite_hook(args, @after_suite_hooks, :push,
1516
+ Hooks::AfterHook, block) || super(*args, &block)
1517
+ end
1518
+
1519
+ # @private
1520
+ def with_suite_hooks
1521
+ return yield if dry_run?
1522
+
1523
+ hook_context = SuiteHookContext.new
1524
+ begin
1525
+ run_hooks_with(@before_suite_hooks, hook_context)
1526
+ yield
1527
+ ensure
1528
+ run_hooks_with(@after_suite_hooks, hook_context)
1529
+ end
1530
+ end
1531
+
1532
+ # @private
1533
+ # Holds the various registered hooks. Here we use a FilterableItemRepository
1534
+ # implementation that is specifically optimized for the read/write patterns
1535
+ # of the config object.
1536
+ def hooks
1537
+ @hooks ||= HookCollections.new(self, FilterableItemRepository::QueryOptimized)
1538
+ end
1539
+
1323
1540
  private
1324
1541
 
1542
+ def handle_suite_hook(args, collection, append_or_prepend, hook_type, block)
1543
+ scope, meta = *args
1544
+ return nil unless scope == :suite
1545
+
1546
+ if meta
1547
+ # TODO: in RSpec 4, consider raising an error here.
1548
+ # We warn only for backwards compatibility.
1549
+ RSpec.warn_with "WARNING: `:suite` hooks do not support metadata since " \
1550
+ "they apply to the suite as a whole rather than " \
1551
+ "any individual example or example group that has metadata. " \
1552
+ "The metadata you have provided (#{meta.inspect}) will be ignored."
1553
+ end
1554
+
1555
+ collection.__send__(append_or_prepend, hook_type.new(block, {}))
1556
+ end
1557
+
1558
+ def run_hooks_with(hooks, hook_context)
1559
+ hooks.each { |h| h.run(hook_context) }
1560
+ end
1561
+
1325
1562
  def get_files_to_run(paths)
1326
1563
  FlatMap.flat_map(paths_to_check(paths)) do |path|
1327
1564
  path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
@@ -1331,7 +1568,7 @@ module RSpec
1331
1568
 
1332
1569
  def paths_to_check(paths)
1333
1570
  return paths if pattern_might_load_specs_from_vendored_dirs?
1334
- paths + ['.']
1571
+ paths + [Dir.getwd]
1335
1572
  end
1336
1573
 
1337
1574
  def pattern_might_load_specs_from_vendored_dirs?
@@ -1386,8 +1623,8 @@ module RSpec
1386
1623
  $0.split(File::SEPARATOR).last
1387
1624
  end
1388
1625
 
1389
- def value_for(key, default=nil)
1390
- @preferred_options.key?(key) ? @preferred_options[key] : default
1626
+ def value_for(key)
1627
+ @preferred_options.fetch(key) { yield }
1391
1628
  end
1392
1629
 
1393
1630
  def assert_no_example_groups_defined(config_option)
@@ -1428,7 +1665,8 @@ module RSpec
1428
1665
 
1429
1666
  def update_pattern_attr(name, value)
1430
1667
  if @spec_files_loaded
1431
- RSpec.warning "Configuring `#{name}` to #{value} has no effect since RSpec has already loaded the spec files."
1668
+ RSpec.warning "Configuring `#{name}` to #{value} has no effect since " \
1669
+ "RSpec has already loaded the spec files."
1432
1670
  end
1433
1671
 
1434
1672
  instance_variable_set(:"@#{name}", value)