rspec-core 3.2.3 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +75 -0
  5. data/README.md +137 -20
  6. data/lib/rspec/autorun.rb +1 -0
  7. data/lib/rspec/core.rb +8 -16
  8. data/lib/rspec/core/backtrace_formatter.rb +1 -3
  9. data/lib/rspec/core/bisect/coordinator.rb +66 -0
  10. data/lib/rspec/core/bisect/example_minimizer.rb +130 -0
  11. data/lib/rspec/core/bisect/runner.rb +139 -0
  12. data/lib/rspec/core/bisect/server.rb +61 -0
  13. data/lib/rspec/core/bisect/subset_enumerator.rb +39 -0
  14. data/lib/rspec/core/configuration.rb +134 -5
  15. data/lib/rspec/core/configuration_options.rb +21 -10
  16. data/lib/rspec/core/example.rb +84 -50
  17. data/lib/rspec/core/example_group.rb +46 -18
  18. data/lib/rspec/core/example_status_persister.rb +235 -0
  19. data/lib/rspec/core/filter_manager.rb +43 -28
  20. data/lib/rspec/core/flat_map.rb +2 -0
  21. data/lib/rspec/core/formatters.rb +30 -20
  22. data/lib/rspec/core/formatters/base_text_formatter.rb +1 -0
  23. data/lib/rspec/core/formatters/bisect_formatter.rb +68 -0
  24. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +115 -0
  25. data/lib/rspec/core/formatters/deprecation_formatter.rb +0 -1
  26. data/lib/rspec/core/formatters/documentation_formatter.rb +0 -4
  27. data/lib/rspec/core/formatters/exception_presenter.rb +389 -0
  28. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  29. data/lib/rspec/core/formatters/helpers.rb +22 -2
  30. data/lib/rspec/core/formatters/html_formatter.rb +1 -4
  31. data/lib/rspec/core/formatters/html_printer.rb +2 -6
  32. data/lib/rspec/core/formatters/json_formatter.rb +6 -4
  33. data/lib/rspec/core/formatters/snippet_extractor.rb +12 -7
  34. data/lib/rspec/core/hooks.rb +8 -2
  35. data/lib/rspec/core/memoized_helpers.rb +77 -17
  36. data/lib/rspec/core/metadata.rb +24 -10
  37. data/lib/rspec/core/metadata_filter.rb +16 -3
  38. data/lib/rspec/core/mutex.rb +63 -0
  39. data/lib/rspec/core/notifications.rb +84 -189
  40. data/lib/rspec/core/option_parser.rb +105 -32
  41. data/lib/rspec/core/ordering.rb +28 -25
  42. data/lib/rspec/core/profiler.rb +32 -0
  43. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +6 -1
  44. data/lib/rspec/core/rake_task.rb +6 -20
  45. data/lib/rspec/core/reentrant_mutex.rb +52 -0
  46. data/lib/rspec/core/reporter.rb +65 -17
  47. data/lib/rspec/core/runner.rb +38 -14
  48. data/lib/rspec/core/set.rb +49 -0
  49. data/lib/rspec/core/shared_example_group.rb +3 -1
  50. data/lib/rspec/core/shell_escape.rb +49 -0
  51. data/lib/rspec/core/version.rb +1 -1
  52. data/lib/rspec/core/world.rb +31 -20
  53. metadata +35 -7
  54. metadata.gz.sig +0 -0
  55. data/lib/rspec/core/backport_random.rb +0 -339
@@ -4,23 +4,36 @@ require 'optparse'
4
4
  module RSpec::Core
5
5
  # @private
6
6
  class Parser
7
- def self.parse(args)
8
- new.parse(args)
7
+ def self.parse(args, source=nil)
8
+ new(args).parse(source)
9
9
  end
10
10
 
11
- def parse(args)
12
- return {} if args.empty?
11
+ attr_reader :original_args
12
+
13
+ def initialize(original_args)
14
+ @original_args = original_args
15
+ end
16
+
17
+ def parse(source=nil)
18
+ return { :files_or_directories_to_run => [] } if original_args.empty?
19
+ args = original_args.dup
13
20
 
14
21
  options = args.delete('--tty') ? { :tty => true } : {}
15
22
  begin
16
23
  parser(options).parse!(args)
17
24
  rescue OptionParser::InvalidOption => e
18
- abort "#{e.message}\n\nPlease use --help for a listing of valid options"
25
+ failure = e.message
26
+ failure << " (defined in #{source})" if source
27
+ abort "#{failure}\n\nPlease use --help for a listing of valid options"
19
28
  end
20
29
 
30
+ options[:files_or_directories_to_run] = args
21
31
  options
22
32
  end
23
33
 
34
+ private
35
+
36
+ # rubocop:disable MethodLength
24
37
  def parser(options)
25
38
  OptionParser.new do |parser|
26
39
  parser.banner = "Usage: rspec [options] [files or directories]\n\n"
@@ -51,12 +64,13 @@ module RSpec::Core
51
64
  options[:order] = "rand:#{seed}"
52
65
  end
53
66
 
54
- parser.on('--fail-fast', 'Abort the run on first failure.') do |_o|
55
- options[:fail_fast] = true
67
+ parser.on('--bisect[=verbose]', 'Repeatedly runs the suite in order to isolate the failures to the ',
68
+ ' smallest reproducible case.') do |argument|
69
+ bisect_and_exit(argument)
56
70
  end
57
71
 
58
- parser.on('--no-fail-fast', 'Do not abort the run on first failure.') do |_o|
59
- options[:fail_fast] = false
72
+ parser.on('--[no-]fail-fast', 'Abort the run on first failure.') do |value|
73
+ set_fail_fast(options, value)
60
74
  end
61
75
 
62
76
  parser.on('--failure-exit-code CODE', Integer,
@@ -78,9 +92,7 @@ module RSpec::Core
78
92
  end
79
93
 
80
94
  parser.on('--init', 'Initialize your project with RSpec.') do |_cmd|
81
- RSpec::Support.require_rspec_core "project_initializer"
82
- ProjectInitializer.new.run
83
- exit
95
+ initialize_project_and_exit
84
96
  end
85
97
 
86
98
  parser.separator("\n **** Output ****\n\n")
@@ -143,14 +155,29 @@ module RSpec::Core
143
155
 
144
156
  **** Filtering/tags ****
145
157
 
146
- In addition to the following options for selecting specific files, groups,
147
- or examples, you can select a single example by appending the line number to
158
+ In addition to the following options for selecting specific files, groups, or
159
+ examples, you can select individual examples by appending the line number(s) to
148
160
  the filename:
149
161
 
150
- rspec path/to/a_spec.rb:37
162
+ rspec path/to/a_spec.rb:37:87
163
+
164
+ You can also pass example ids enclosed in square brackets:
165
+
166
+ rspec path/to/a_spec.rb[1:5,1:6] # run the 5th and 6th examples/groups defined in the 1st group
151
167
 
152
168
  FILTERING
153
169
 
170
+ parser.on('--only-failures', "Filter to just the examples that failed the last time they ran.") do
171
+ configure_only_failures(options)
172
+ end
173
+
174
+ parser.on("--next-failure", "Apply `--only-failures` and abort after one failure.",
175
+ " (Equivalent to `--only-failures --fail-fast --order defined`)") do
176
+ configure_only_failures(options)
177
+ set_fail_fast(options, true)
178
+ options[:order] ||= 'defined'
179
+ end
180
+
154
181
  parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
155
182
  options[:pattern] = o
156
183
  end
@@ -175,18 +202,19 @@ FILTERING
175
202
  name, value = tag.gsub(/^(~@|~|@)/, '').split(':', 2)
176
203
  name = name.to_sym
177
204
 
178
- options[filter_type] ||= {}
179
- options[filter_type][name] = case value
180
- when nil then true # The default value for tags is true
181
- when 'true' then true
182
- when 'false' then false
183
- when 'nil' then nil
184
- when /^:/ then value[1..-1].to_sym
185
- when /^\d+$/ then Integer(value)
186
- when /^\d+.\d+$/ then Float(value)
187
- else
188
- value
189
- end
205
+ parsed_value = case value
206
+ when nil then true # The default value for tags is true
207
+ when 'true' then true
208
+ when 'false' then false
209
+ when 'nil' then nil
210
+ when /^:/ then value[1..-1].to_sym
211
+ when /^\d+$/ then Integer(value)
212
+ when /^\d+.\d+$/ then Float(value)
213
+ else
214
+ value
215
+ end
216
+
217
+ add_tag_filter(options, filter_type, name, parsed_value)
190
218
  end
191
219
 
192
220
  parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
@@ -197,8 +225,7 @@ FILTERING
197
225
  parser.separator("\n **** Utility ****\n\n")
198
226
 
199
227
  parser.on('-v', '--version', 'Display the version.') do
200
- puts RSpec::Core::Version::STRING
201
- exit
228
+ print_version_and_exit
202
229
  end
203
230
 
204
231
  # These options would otherwise be confusing to users, so we forcibly
@@ -210,9 +237,7 @@ FILTERING
210
237
  invalid_options = %w[-d --I]
211
238
 
212
239
  parser.on_tail('-h', '--help', "You're looking at it.") do
213
- # Removing the blank invalid options from the output.
214
- puts parser.to_s.gsub(/^\s+(#{invalid_options.join('|')})\s*$\n/, '')
215
- exit
240
+ print_help_and_exit(parser, invalid_options)
216
241
  end
217
242
 
218
243
  # This prevents usage of the invalid_options.
@@ -224,5 +249,53 @@ FILTERING
224
249
 
225
250
  end
226
251
  end
252
+ # rubocop:enable MethodLength
253
+
254
+ def add_tag_filter(options, filter_type, tag_name, value=true)
255
+ (options[filter_type] ||= {})[tag_name] = value
256
+ end
257
+
258
+ def set_fail_fast(options, value)
259
+ options[:fail_fast] = value
260
+ end
261
+
262
+ def configure_only_failures(options)
263
+ options[:only_failures] = true
264
+ add_tag_filter(options, :inclusion_filter, :last_run_status, 'failed')
265
+ end
266
+
267
+ def initialize_project_and_exit
268
+ RSpec::Support.require_rspec_core "project_initializer"
269
+ ProjectInitializer.new.run
270
+ exit
271
+ end
272
+
273
+ def bisect_and_exit(argument)
274
+ RSpec::Support.require_rspec_core "bisect/coordinator"
275
+
276
+ success = Bisect::Coordinator.bisect_with(
277
+ original_args,
278
+ RSpec.configuration,
279
+ bisect_formatter_for(argument)
280
+ )
281
+
282
+ exit(success ? 0 : 1)
283
+ end
284
+
285
+ def bisect_formatter_for(argument)
286
+ return Formatters::BisectDebugFormatter if argument == "verbose"
287
+ Formatters::BisectProgressFormatter
288
+ end
289
+
290
+ def print_version_and_exit
291
+ puts RSpec::Core::Version::STRING
292
+ exit
293
+ end
294
+
295
+ def print_help_and_exit(parser, invalid_options)
296
+ # Removing the blank invalid options from the output.
297
+ puts parser.to_s.gsub(/^\s+(#{invalid_options.join('|')})\s*$\n/, '')
298
+ exit
299
+ end
227
300
  end
228
301
  end
@@ -1,14 +1,5 @@
1
1
  module RSpec
2
2
  module Core
3
- if defined?(::Random)
4
- # @private
5
- RandomNumberGenerator = ::Random
6
- else
7
- RSpec::Support.require_rspec_core "backport_random"
8
- # @private
9
- RandomNumberGenerator = RSpec::Core::Backports::Random
10
- end
11
-
12
3
  # @private
13
4
  module Ordering
14
5
  # @private
@@ -33,26 +24,38 @@ module RSpec
33
24
 
34
25
  def order(items)
35
26
  @used = true
36
- rng = RandomNumberGenerator.new(@configuration.seed)
37
- shuffle items, rng
27
+
28
+ seed = @configuration.seed.to_s
29
+ items.sort_by { |item| jenkins_hash_digest(seed + item.id) }
38
30
  end
39
31
 
40
- if RUBY_VERSION > '1.9.3'
41
- def shuffle(list, rng)
42
- list.shuffle(:random => rng)
43
- end
44
- else
45
- def shuffle(list, rng)
46
- shuffled = list.dup
47
- shuffled.size.times do |i|
48
- j = i + rng.rand(shuffled.size - i)
49
- next if i == j
50
- shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
51
- end
52
-
53
- shuffled
32
+ private
33
+
34
+ # http://en.wikipedia.org/wiki/Jenkins_hash_function
35
+ # Jenkins provides a good distribution and is simpler than MD5.
36
+ # It's a bit slower than MD5 (primarily because `Digest::MD5` is
37
+ # implemented in C) but has the advantage of not requiring us
38
+ # to load another part of stdlib, which we try to minimize.
39
+ def jenkins_hash_digest(string)
40
+ hash = 0
41
+
42
+ string.each_byte do |byte|
43
+ hash += byte
44
+ hash &= MAX_32_BIT
45
+ hash += ((hash << 10) & MAX_32_BIT)
46
+ hash &= MAX_32_BIT
47
+ hash ^= hash >> 6
54
48
  end
49
+
50
+ hash += ((hash << 3) & MAX_32_BIT)
51
+ hash &= MAX_32_BIT
52
+ hash ^= hash >> 11
53
+ hash += ((hash << 15) & MAX_32_BIT)
54
+ hash &= MAX_32_BIT
55
+ hash
55
56
  end
57
+
58
+ MAX_32_BIT = 4_294_967_295
56
59
  end
57
60
 
58
61
  # @private
@@ -0,0 +1,32 @@
1
+ module RSpec
2
+ module Core
3
+ # @private
4
+ class Profiler
5
+ NOTIFICATIONS = [:example_group_started, :example_group_finished, :example_started]
6
+
7
+ def initialize
8
+ @example_groups = Hash.new { |h, k| h[k] = { :count => 0 } }
9
+ end
10
+
11
+ attr_reader :example_groups
12
+
13
+ def example_group_started(notification)
14
+ return unless notification.group.top_level?
15
+
16
+ @example_groups[notification.group][:start] = Time.now
17
+ @example_groups[notification.group][:description] = notification.group.top_level_description
18
+ end
19
+
20
+ def example_group_finished(notification)
21
+ return unless notification.group.top_level?
22
+
23
+ @example_groups[notification.group][:total_time] = Time.now - @example_groups[notification.group][:start]
24
+ end
25
+
26
+ def example_started(notification)
27
+ group = notification.example.example_group.parent_groups.last
28
+ @example_groups[group][:count] += 1
29
+ end
30
+ end
31
+ end
32
+ end
@@ -50,10 +50,15 @@ RSpec.configure do |config|
50
50
  config.filter_run :focus
51
51
  config.run_all_when_everything_filtered = true
52
52
 
53
+ # Allows RSpec to persist some state between runs in order to support
54
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
55
+ # you configure your source control system to ignore this file.
56
+ config.example_status_persistence_file_path = "spec/examples.txt"
57
+
53
58
  # Limits the available syntax to the non-monkey patched syntax that is
54
59
  # recommended. For more details, see:
55
60
  # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
56
- # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
61
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
57
62
  # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
58
63
  config.disable_monkey_patching!
59
64
 
@@ -1,6 +1,7 @@
1
1
  require 'rake'
2
2
  require 'rake/tasklib'
3
3
  require 'rspec/support/ruby_features'
4
+ require 'rspec/core/shell_escape'
4
5
 
5
6
  module RSpec
6
7
  module Core
@@ -9,6 +10,7 @@ module RSpec
9
10
  # @see Rakefile
10
11
  class RakeTask < ::Rake::TaskLib
11
12
  include ::Rake::DSL if defined?(::Rake::DSL)
13
+ include RSpec::Core::ShellEscape
12
14
 
13
15
  # Default path to the RSpec executable.
14
16
  DEFAULT_RSPEC_PATH = File.expand_path('../../../../exe/rspec', __FILE__)
@@ -63,16 +65,12 @@ module RSpec
63
65
  # @private
64
66
  def run_task(verbose)
65
67
  command = spec_command
68
+ puts command if verbose
66
69
 
67
- begin
68
- puts command if verbose
69
- success = system(command)
70
- rescue
71
- puts failure_message if failure_message
72
- end
73
-
74
- return unless fail_on_error && !success
70
+ return if system(command)
71
+ puts failure_message if failure_message
75
72
 
73
+ return unless fail_on_error
76
74
  $stderr.puts "#{command} failed" if verbose
77
75
  exit $?.exitstatus
78
76
  end
@@ -126,18 +124,6 @@ module RSpec
126
124
  end
127
125
  end
128
126
 
129
- if RSpec::Support::OS.windows?
130
- def escape(shell_command)
131
- "'#{shell_command.gsub("'", "\'")}'"
132
- end
133
- else
134
- require 'shellwords'
135
-
136
- def escape(shell_command)
137
- shell_command.shellescape
138
- end
139
- end
140
-
141
127
  def file_exclusion_specification
142
128
  " --exclude-pattern #{escape exclude_pattern}" if exclude_pattern
143
129
  end
@@ -0,0 +1,52 @@
1
+ module RSpec
2
+ module Core
3
+ # Allows a thread to lock out other threads from a critical section of code,
4
+ # while allowing the thread with the lock to reenter that section.
5
+ #
6
+ # Based on Monitor as of 2.2 - https://github.com/ruby/ruby/blob/eb7ddaa3a47bf48045d26c72eb0f263a53524ebc/lib/monitor.rb#L9
7
+ #
8
+ # Depends on Mutex, but Mutex is only available as part of core since 1.9.1:
9
+ # exists - http://ruby-doc.org/core-1.9.1/Mutex.html
10
+ # dne - http://ruby-doc.org/core-1.9.0/Mutex.html
11
+ #
12
+ # @private
13
+ class ReentrantMutex
14
+ def initialize
15
+ @owner = nil
16
+ @count = 0
17
+ @mutex = Mutex.new
18
+ end
19
+
20
+ def synchronize
21
+ enter
22
+ yield
23
+ ensure
24
+ exit
25
+ end
26
+
27
+ private
28
+
29
+ def enter
30
+ @mutex.lock if @owner != Thread.current
31
+ @owner = Thread.current
32
+ @count += 1
33
+ end
34
+
35
+ def exit
36
+ @count -= 1
37
+ return unless @count == 0
38
+ @owner = nil
39
+ @mutex.unlock
40
+ end
41
+ end
42
+
43
+ if defined? ::Mutex
44
+ # On 1.9 and up, this is in core, so we just use the real one
45
+ Mutex = ::Mutex
46
+ else # For 1.8.7
47
+ # :nocov:
48
+ RSpec::Support.require_rspec_core "mutex"
49
+ # :nocov:
50
+ end
51
+ end
52
+ end
@@ -2,6 +2,15 @@ module RSpec::Core
2
2
  # A reporter will send notifications to listeners, usually formatters for the
3
3
  # spec suite run.
4
4
  class Reporter
5
+ # @private
6
+ RSPEC_NOTIFICATIONS = Set.new(
7
+ [
8
+ :close, :deprecation, :deprecation_summary, :dump_failures, :dump_pending,
9
+ :dump_profile, :dump_summary, :example_failed, :example_group_finished,
10
+ :example_group_started, :example_passed, :example_pending, :example_started,
11
+ :message, :seed, :start, :start_dump, :stop
12
+ ])
13
+
5
14
  def initialize(configuration)
6
15
  @configuration = configuration
7
16
  @listeners = Hash.new { |h, k| h[k] = Set.new }
@@ -19,6 +28,13 @@ module RSpec::Core
19
28
  @examples = []
20
29
  @failed_examples = []
21
30
  @pending_examples = []
31
+ @profiler = Profiler.new if defined?(@profiler)
32
+ end
33
+
34
+ # @private
35
+ def setup_profiler
36
+ @profiler = Profiler.new
37
+ register_listener @profiler, *Profiler::NOTIFICATIONS
22
38
  end
23
39
 
24
40
  # Registers a listener to a list of notifications. The reporter will send
@@ -40,7 +56,6 @@ module RSpec::Core
40
56
  @listeners[notification].to_a
41
57
  end
42
58
 
43
- # @api
44
59
  # @overload report(count, &block)
45
60
  # @overload report(count, &block)
46
61
  # @param expected_example_count [Integer] the number of examples being run
@@ -73,11 +88,26 @@ module RSpec::Core
73
88
  notify :start, Notifications::StartNotification.new(expected_example_count, @load_time)
74
89
  end
75
90
 
76
- # @private
91
+ # @param message [#to_s] A message object to send to formatters
92
+ #
93
+ # Send a custom message to supporting formatters.
77
94
  def message(message)
78
95
  notify :message, Notifications::MessageNotification.new(message)
79
96
  end
80
97
 
98
+ # @param event [Symbol] Name of the custom event to trigger on formatters
99
+ # @param options [Hash] Hash of arguments to provide via `CustomNotification`
100
+ #
101
+ # Publish a custom event to supporting registered formatters.
102
+ # @see RSpec::Core::Notifications::CustomNotification
103
+ def publish(event, options={})
104
+ if RSPEC_NOTIFICATIONS.include? event
105
+ raise "RSpec::Core::Reporter#publish is intended for sending custom " \
106
+ "events not internal RSpec ones, please rename your custom event."
107
+ end
108
+ notify event, Notifications::CustomNotification.for(options)
109
+ end
110
+
81
111
  # @private
82
112
  def example_group_started(group)
83
113
  notify :example_group_started, Notifications::GroupNotification.new(group) unless group.descendant_filtered_examples.empty?
@@ -118,20 +148,28 @@ module RSpec::Core
118
148
 
119
149
  # @private
120
150
  def finish
121
- stop
122
- notify :start_dump, Notifications::NullNotification
123
- notify :dump_pending, Notifications::ExamplesNotification.new(self)
124
- notify :dump_failures, Notifications::ExamplesNotification.new(self)
125
- notify :deprecation_summary, Notifications::NullNotification
126
- unless mute_profile_output?
127
- notify :dump_profile, Notifications::ProfileNotification.new(@duration, @examples,
128
- @configuration.profile_examples)
151
+ close_after do
152
+ stop
153
+ notify :start_dump, Notifications::NullNotification
154
+ notify :dump_pending, Notifications::ExamplesNotification.new(self)
155
+ notify :dump_failures, Notifications::ExamplesNotification.new(self)
156
+ notify :deprecation_summary, Notifications::NullNotification
157
+ unless mute_profile_output?
158
+ notify :dump_profile, Notifications::ProfileNotification.new(@duration, @examples,
159
+ @configuration.profile_examples,
160
+ @profiler.example_groups)
161
+ end
162
+ notify :dump_summary, Notifications::SummaryNotification.new(@duration, @examples, @failed_examples,
163
+ @pending_examples, @load_time)
164
+ notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
129
165
  end
130
- notify :dump_summary, Notifications::SummaryNotification.new(@duration, @examples, @failed_examples,
131
- @pending_examples, @load_time)
132
- notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
166
+ end
167
+
168
+ # @private
169
+ def close_after
170
+ yield
133
171
  ensure
134
- notify :close, Notifications::NullNotification
172
+ close
135
173
  end
136
174
 
137
175
  # @private
@@ -147,8 +185,19 @@ module RSpec::Core
147
185
  end
148
186
  end
149
187
 
188
+ # @private
189
+ def abort_with(msg, exit_status)
190
+ message(msg)
191
+ close
192
+ exit!(exit_status)
193
+ end
194
+
150
195
  private
151
196
 
197
+ def close
198
+ notify :close, Notifications::NullNotification
199
+ end
200
+
152
201
  def mute_profile_output?
153
202
  # Don't print out profiled info if there are failures and `--fail-fast` is
154
203
  # used, it just clutters the output.
@@ -163,10 +212,9 @@ module RSpec::Core
163
212
  # @private
164
213
  # # Used in place of a {Reporter} for situations where we don't want reporting output.
165
214
  class NullReporter
166
- private
167
-
168
- def method_missing(*)
215
+ def self.method_missing(*)
169
216
  # ignore
170
217
  end
218
+ private_class_method :method_missing
171
219
  end
172
220
  end