rspec-core 3.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.document +5 -0
  5. data/.yardopts +8 -0
  6. data/Changelog.md +2243 -0
  7. data/LICENSE.md +26 -0
  8. data/README.md +384 -0
  9. data/exe/rspec +4 -0
  10. data/lib/rspec/autorun.rb +3 -0
  11. data/lib/rspec/core.rb +185 -0
  12. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  13. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  14. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  15. data/lib/rspec/core/bisect/fork_runner.rb +134 -0
  16. data/lib/rspec/core/bisect/server.rb +61 -0
  17. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  18. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  19. data/lib/rspec/core/bisect/utilities.rb +58 -0
  20. data/lib/rspec/core/configuration.rb +2308 -0
  21. data/lib/rspec/core/configuration_options.rb +233 -0
  22. data/lib/rspec/core/drb.rb +113 -0
  23. data/lib/rspec/core/dsl.rb +98 -0
  24. data/lib/rspec/core/example.rb +656 -0
  25. data/lib/rspec/core/example_group.rb +889 -0
  26. data/lib/rspec/core/example_status_persister.rb +235 -0
  27. data/lib/rspec/core/filter_manager.rb +231 -0
  28. data/lib/rspec/core/flat_map.rb +20 -0
  29. data/lib/rspec/core/formatters.rb +269 -0
  30. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  31. data/lib/rspec/core/formatters/base_formatter.rb +70 -0
  32. data/lib/rspec/core/formatters/base_text_formatter.rb +75 -0
  33. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  34. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  35. data/lib/rspec/core/formatters/console_codes.rb +68 -0
  36. data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
  37. data/lib/rspec/core/formatters/documentation_formatter.rb +70 -0
  38. data/lib/rspec/core/formatters/exception_presenter.rb +508 -0
  39. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  40. data/lib/rspec/core/formatters/helpers.rb +110 -0
  41. data/lib/rspec/core/formatters/html_formatter.rb +153 -0
  42. data/lib/rspec/core/formatters/html_printer.rb +414 -0
  43. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  44. data/lib/rspec/core/formatters/json_formatter.rb +102 -0
  45. data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
  46. data/lib/rspec/core/formatters/progress_formatter.rb +29 -0
  47. data/lib/rspec/core/formatters/protocol.rb +182 -0
  48. data/lib/rspec/core/formatters/snippet_extractor.rb +134 -0
  49. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  50. data/lib/rspec/core/hooks.rb +624 -0
  51. data/lib/rspec/core/invocations.rb +87 -0
  52. data/lib/rspec/core/memoized_helpers.rb +554 -0
  53. data/lib/rspec/core/metadata.rb +498 -0
  54. data/lib/rspec/core/metadata_filter.rb +255 -0
  55. data/lib/rspec/core/minitest_assertions_adapter.rb +31 -0
  56. data/lib/rspec/core/mocking_adapters/flexmock.rb +31 -0
  57. data/lib/rspec/core/mocking_adapters/mocha.rb +57 -0
  58. data/lib/rspec/core/mocking_adapters/null.rb +14 -0
  59. data/lib/rspec/core/mocking_adapters/rr.rb +31 -0
  60. data/lib/rspec/core/mocking_adapters/rspec.rb +32 -0
  61. data/lib/rspec/core/notifications.rb +521 -0
  62. data/lib/rspec/core/option_parser.rb +309 -0
  63. data/lib/rspec/core/ordering.rb +158 -0
  64. data/lib/rspec/core/output_wrapper.rb +29 -0
  65. data/lib/rspec/core/pending.rb +165 -0
  66. data/lib/rspec/core/profiler.rb +34 -0
  67. data/lib/rspec/core/project_initializer.rb +48 -0
  68. data/lib/rspec/core/project_initializer/.rspec +1 -0
  69. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +100 -0
  70. data/lib/rspec/core/rake_task.rb +168 -0
  71. data/lib/rspec/core/reporter.rb +257 -0
  72. data/lib/rspec/core/ruby_project.rb +53 -0
  73. data/lib/rspec/core/runner.rb +199 -0
  74. data/lib/rspec/core/sandbox.rb +37 -0
  75. data/lib/rspec/core/set.rb +54 -0
  76. data/lib/rspec/core/shared_context.rb +55 -0
  77. data/lib/rspec/core/shared_example_group.rb +269 -0
  78. data/lib/rspec/core/shell_escape.rb +49 -0
  79. data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
  80. data/lib/rspec/core/version.rb +9 -0
  81. data/lib/rspec/core/warnings.rb +40 -0
  82. data/lib/rspec/core/world.rb +275 -0
  83. metadata +292 -0
  84. metadata.gz.sig +0 -0
@@ -0,0 +1,521 @@
1
+ RSpec::Support.require_rspec_core "formatters/console_codes"
2
+ RSpec::Support.require_rspec_core "formatters/exception_presenter"
3
+ RSpec::Support.require_rspec_core "formatters/helpers"
4
+ RSpec::Support.require_rspec_core "shell_escape"
5
+
6
+ module RSpec::Core
7
+ # Notifications are value objects passed to formatters to provide them
8
+ # with information about a particular event of interest.
9
+ module Notifications
10
+ # @private
11
+ module NullColorizer
12
+ module_function
13
+
14
+ def wrap(line, _code_or_symbol)
15
+ line
16
+ end
17
+ end
18
+
19
+ # The `StartNotification` represents a notification sent by the reporter
20
+ # when the suite is started. It contains the expected amount of examples
21
+ # to be executed, and the load time of RSpec.
22
+ #
23
+ # @attr count [Fixnum] the number counted
24
+ # @attr load_time [Float] the number of seconds taken to boot RSpec
25
+ # and load the spec files
26
+ StartNotification = Struct.new(:count, :load_time)
27
+
28
+ # The `ExampleNotification` represents notifications sent by the reporter
29
+ # which contain information about the current (or soon to be) example.
30
+ # It is used by formatters to access information about that example.
31
+ #
32
+ # @example
33
+ # def example_started(notification)
34
+ # puts "Hey I started #{notification.example.description}"
35
+ # end
36
+ #
37
+ # @attr example [RSpec::Core::Example] the current example
38
+ ExampleNotification = Struct.new(:example)
39
+ class ExampleNotification
40
+ # @private
41
+ def self.for(example)
42
+ execution_result = example.execution_result
43
+
44
+ return SkippedExampleNotification.new(example) if execution_result.example_skipped?
45
+ return new(example) unless execution_result.status == :pending || execution_result.status == :failed
46
+
47
+ klass = if execution_result.pending_fixed?
48
+ PendingExampleFixedNotification
49
+ elsif execution_result.status == :pending
50
+ PendingExampleFailedAsExpectedNotification
51
+ else
52
+ FailedExampleNotification
53
+ end
54
+
55
+ klass.new(example)
56
+ end
57
+
58
+ private_class_method :new
59
+ end
60
+
61
+ # The `ExamplesNotification` represents notifications sent by the reporter
62
+ # which contain information about the suites examples.
63
+ #
64
+ # @example
65
+ # def stop(notification)
66
+ # puts "Hey I ran #{notification.examples.size}"
67
+ # end
68
+ #
69
+ class ExamplesNotification
70
+ def initialize(reporter)
71
+ @reporter = reporter
72
+ end
73
+
74
+ # @return [Array<RSpec::Core::Example>] list of examples
75
+ def examples
76
+ @reporter.examples
77
+ end
78
+
79
+ # @return [Array<RSpec::Core::Example>] list of failed examples
80
+ def failed_examples
81
+ @reporter.failed_examples
82
+ end
83
+
84
+ # @return [Array<RSpec::Core::Example>] list of pending examples
85
+ def pending_examples
86
+ @reporter.pending_examples
87
+ end
88
+
89
+ # @return [Array<RSpec::Core::Notifications::ExampleNotification>]
90
+ # returns examples as notifications
91
+ def notifications
92
+ @notifications ||= format_examples(examples)
93
+ end
94
+
95
+ # @return [Array<RSpec::Core::Notifications::FailedExampleNotification>]
96
+ # returns failed examples as notifications
97
+ def failure_notifications
98
+ @failed_notifications ||= format_examples(failed_examples)
99
+ end
100
+
101
+ # @return [Array<RSpec::Core::Notifications::SkippedExampleNotification,
102
+ # RSpec::Core::Notifications::PendingExampleFailedAsExpectedNotification>]
103
+ # returns pending examples as notifications
104
+ def pending_notifications
105
+ @pending_notifications ||= format_examples(pending_examples)
106
+ end
107
+
108
+ # @return [String] The list of failed examples, fully formatted in the way
109
+ # that RSpec's built-in formatters emit.
110
+ def fully_formatted_failed_examples(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
111
+ formatted = "\nFailures:\n"
112
+
113
+ failure_notifications.each_with_index do |failure, index|
114
+ formatted += failure.fully_formatted(index.next, colorizer)
115
+ end
116
+
117
+ formatted
118
+ end
119
+
120
+ # @return [String] The list of pending examples, fully formatted in the
121
+ # way that RSpec's built-in formatters emit.
122
+ def fully_formatted_pending_examples(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
123
+ formatted = "\nPending: (Failures listed here are expected and do not affect your suite's status)\n".dup
124
+
125
+ pending_notifications.each_with_index do |notification, index|
126
+ formatted << notification.fully_formatted(index.next, colorizer)
127
+ end
128
+
129
+ formatted
130
+ end
131
+
132
+ private
133
+
134
+ def format_examples(examples)
135
+ examples.map do |example|
136
+ ExampleNotification.for(example)
137
+ end
138
+ end
139
+ end
140
+
141
+ # The `FailedExampleNotification` extends `ExampleNotification` with
142
+ # things useful for examples that have failure info -- typically a
143
+ # failed or pending spec.
144
+ #
145
+ # @example
146
+ # def example_failed(notification)
147
+ # puts "Hey I failed :("
148
+ # puts "Here's my stack trace"
149
+ # puts notification.exception.backtrace.join("\n")
150
+ # end
151
+ #
152
+ # @attr [RSpec::Core::Example] example the current example
153
+ # @see ExampleNotification
154
+ class FailedExampleNotification < ExampleNotification
155
+ public_class_method :new
156
+
157
+ # @return [Exception] The example failure
158
+ def exception
159
+ @exception_presenter.exception
160
+ end
161
+
162
+ # @return [String] The example description
163
+ def description
164
+ @exception_presenter.description
165
+ end
166
+
167
+ # Returns the message generated for this failure line by line.
168
+ #
169
+ # @return [Array<String>] The example failure message
170
+ def message_lines
171
+ @exception_presenter.message_lines
172
+ end
173
+
174
+ # Returns the message generated for this failure colorized line by line.
175
+ #
176
+ # @param colorizer [#wrap] An object to colorize the message_lines by
177
+ # @return [Array<String>] The example failure message colorized
178
+ def colorized_message_lines(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
179
+ @exception_presenter.colorized_message_lines(colorizer)
180
+ end
181
+
182
+ # Returns the failures formatted backtrace.
183
+ #
184
+ # @return [Array<String>] the examples backtrace lines
185
+ def formatted_backtrace
186
+ @exception_presenter.formatted_backtrace
187
+ end
188
+
189
+ # Returns the failures colorized formatted backtrace.
190
+ #
191
+ # @param colorizer [#wrap] An object to colorize the message_lines by
192
+ # @return [Array<String>] the examples colorized backtrace lines
193
+ def colorized_formatted_backtrace(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
194
+ @exception_presenter.colorized_formatted_backtrace(colorizer)
195
+ end
196
+
197
+ # @return [String] The failure information fully formatted in the way that
198
+ # RSpec's built-in formatters emit.
199
+ def fully_formatted(failure_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
200
+ @exception_presenter.fully_formatted(failure_number, colorizer)
201
+ end
202
+
203
+ # @return [Array<string>] The failure information fully formatted in the way that
204
+ # RSpec's built-in formatters emit, split by line.
205
+ def fully_formatted_lines(failure_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
206
+ @exception_presenter.fully_formatted_lines(failure_number, colorizer)
207
+ end
208
+
209
+ private
210
+
211
+ def initialize(example, exception_presenter=Formatters::ExceptionPresenter::Factory.new(example).build)
212
+ @exception_presenter = exception_presenter
213
+ super(example)
214
+ end
215
+ end
216
+
217
+ # @deprecated Use {FailedExampleNotification} instead.
218
+ class PendingExampleFixedNotification < FailedExampleNotification; end
219
+
220
+ # @deprecated Use {FailedExampleNotification} instead.
221
+ class PendingExampleFailedAsExpectedNotification < FailedExampleNotification; end
222
+
223
+ # The `SkippedExampleNotification` extends `ExampleNotification` with
224
+ # things useful for specs that are skipped.
225
+ #
226
+ # @attr [RSpec::Core::Example] example the current example
227
+ # @see ExampleNotification
228
+ class SkippedExampleNotification < ExampleNotification
229
+ public_class_method :new
230
+
231
+ # @return [String] The pending detail fully formatted in the way that
232
+ # RSpec's built-in formatters emit.
233
+ def fully_formatted(pending_number, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
234
+ formatted_caller = RSpec.configuration.backtrace_formatter.backtrace_line(example.location)
235
+
236
+ [
237
+ colorizer.wrap("\n #{pending_number}) #{example.full_description}", :pending),
238
+ "\n ",
239
+ Formatters::ExceptionPresenter::PENDING_DETAIL_FORMATTER.call(example, colorizer),
240
+ "\n",
241
+ colorizer.wrap(" # #{formatted_caller}\n", :detail)
242
+ ].join("")
243
+ end
244
+ end
245
+
246
+ # The `GroupNotification` represents notifications sent by the reporter
247
+ # which contain information about the currently running (or soon to be)
248
+ # example group. It is used by formatters to access information about that
249
+ # group.
250
+ #
251
+ # @example
252
+ # def example_group_started(notification)
253
+ # puts "Hey I started #{notification.group.description}"
254
+ # end
255
+ # @attr group [RSpec::Core::ExampleGroup] the current group
256
+ GroupNotification = Struct.new(:group)
257
+
258
+ # The `MessageNotification` encapsulates generic messages that the reporter
259
+ # sends to formatters.
260
+ #
261
+ # @attr message [String] the message
262
+ MessageNotification = Struct.new(:message)
263
+
264
+ # The `SeedNotification` holds the seed used to randomize examples and
265
+ # whether that seed has been used or not.
266
+ #
267
+ # @attr seed [Fixnum] the seed used to randomize ordering
268
+ # @attr used [Boolean] whether the seed has been used or not
269
+ SeedNotification = Struct.new(:seed, :used)
270
+ class SeedNotification
271
+ # @api
272
+ # @return [Boolean] has the seed been used?
273
+ def seed_used?
274
+ !!used
275
+ end
276
+ private :used
277
+
278
+ # @return [String] The seed information fully formatted in the way that
279
+ # RSpec's built-in formatters emit.
280
+ def fully_formatted
281
+ "\nRandomized with seed #{seed}\n"
282
+ end
283
+ end
284
+
285
+ # The `SummaryNotification` holds information about the results of running
286
+ # a test suite. It is used by formatters to provide information at the end
287
+ # of the test run.
288
+ #
289
+ # @attr duration [Float] the time taken (in seconds) to run the suite
290
+ # @attr examples [Array<RSpec::Core::Example>] the examples run
291
+ # @attr failed_examples [Array<RSpec::Core::Example>] the failed examples
292
+ # @attr pending_examples [Array<RSpec::Core::Example>] the pending examples
293
+ # @attr load_time [Float] the number of seconds taken to boot RSpec
294
+ # and load the spec files
295
+ # @attr errors_outside_of_examples_count [Integer] the number of errors that
296
+ # have occurred processing
297
+ # the spec suite
298
+ SummaryNotification = Struct.new(:duration, :examples, :failed_examples,
299
+ :pending_examples, :load_time,
300
+ :errors_outside_of_examples_count)
301
+ class SummaryNotification
302
+ # @api
303
+ # @return [Fixnum] the number of examples run
304
+ def example_count
305
+ @example_count ||= examples.size
306
+ end
307
+
308
+ # @api
309
+ # @return [Fixnum] the number of failed examples
310
+ def failure_count
311
+ @failure_count ||= failed_examples.size
312
+ end
313
+
314
+ # @api
315
+ # @return [Fixnum] the number of pending examples
316
+ def pending_count
317
+ @pending_count ||= pending_examples.size
318
+ end
319
+
320
+ # @api
321
+ # @return [String] A line summarising the result totals of the spec run.
322
+ def totals_line
323
+ summary = Formatters::Helpers.pluralize(example_count, "example") +
324
+ ", " + Formatters::Helpers.pluralize(failure_count, "failure")
325
+ summary += ", #{pending_count} pending" if pending_count > 0
326
+ if errors_outside_of_examples_count > 0
327
+ summary += (
328
+ ", " +
329
+ Formatters::Helpers.pluralize(errors_outside_of_examples_count, "error") +
330
+ " occurred outside of examples"
331
+ )
332
+ end
333
+ summary
334
+ end
335
+
336
+ # @api public
337
+ #
338
+ # Wraps the results line with colors based on the configured
339
+ # colors for failure, pending, and success. Defaults to red,
340
+ # yellow, green accordingly.
341
+ #
342
+ # @param colorizer [#wrap] An object which supports wrapping text with
343
+ # specific colors.
344
+ # @return [String] A colorized results line.
345
+ def colorized_totals_line(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
346
+ if failure_count > 0 || errors_outside_of_examples_count > 0
347
+ colorizer.wrap(totals_line, RSpec.configuration.failure_color)
348
+ elsif pending_count > 0
349
+ colorizer.wrap(totals_line, RSpec.configuration.pending_color)
350
+ else
351
+ colorizer.wrap(totals_line, RSpec.configuration.success_color)
352
+ end
353
+ end
354
+
355
+ # @api public
356
+ #
357
+ # Formats failures into a rerunable command format.
358
+ #
359
+ # @param colorizer [#wrap] An object which supports wrapping text with
360
+ # specific colors.
361
+ # @return [String] A colorized summary line.
362
+ def colorized_rerun_commands(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
363
+ "\nFailed examples:\n\n" +
364
+ failed_examples.map do |example|
365
+ colorizer.wrap("rspec #{rerun_argument_for(example)}", RSpec.configuration.failure_color) + " " +
366
+ colorizer.wrap("# #{example.full_description}", RSpec.configuration.detail_color)
367
+ end.join("\n")
368
+ end
369
+
370
+ # @return [String] a formatted version of the time it took to run the
371
+ # suite
372
+ def formatted_duration
373
+ Formatters::Helpers.format_duration(duration)
374
+ end
375
+
376
+ # @return [String] a formatted version of the time it took to boot RSpec
377
+ # and load the spec files
378
+ def formatted_load_time
379
+ Formatters::Helpers.format_duration(load_time)
380
+ end
381
+
382
+ # @return [String] The summary information fully formatted in the way that
383
+ # RSpec's built-in formatters emit.
384
+ def fully_formatted(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
385
+ formatted = "\nFinished in #{formatted_duration} " \
386
+ "(files took #{formatted_load_time} to load)\n" \
387
+ "#{colorized_totals_line(colorizer)}\n"
388
+
389
+ unless failed_examples.empty?
390
+ formatted += (colorized_rerun_commands(colorizer) + "\n")
391
+ end
392
+
393
+ formatted
394
+ end
395
+
396
+ private
397
+
398
+ include RSpec::Core::ShellEscape
399
+
400
+ def rerun_argument_for(example)
401
+ location = example.location_rerun_argument
402
+ return location unless duplicate_rerun_locations.include?(location)
403
+ conditionally_quote(example.id)
404
+ end
405
+
406
+ def duplicate_rerun_locations
407
+ @duplicate_rerun_locations ||= begin
408
+ locations = RSpec.world.all_examples.map(&:location_rerun_argument)
409
+
410
+ Set.new.tap do |s|
411
+ locations.group_by { |l| l }.each do |l, ls|
412
+ s << l if ls.count > 1
413
+ end
414
+ end
415
+ end
416
+ end
417
+ end
418
+
419
+ # The `ProfileNotification` holds information about the results of running a
420
+ # test suite when profiling is enabled. It is used by formatters to provide
421
+ # information at the end of the test run for profiling information.
422
+ #
423
+ # @attr duration [Float] the time taken (in seconds) to run the suite
424
+ # @attr examples [Array<RSpec::Core::Example>] the examples run
425
+ # @attr number_of_examples [Fixnum] the number of examples to profile
426
+ # @attr example_groups [Array<RSpec::Core::Profiler>] example groups run
427
+ class ProfileNotification
428
+ def initialize(duration, examples, number_of_examples, example_groups)
429
+ @duration = duration
430
+ @examples = examples
431
+ @number_of_examples = number_of_examples
432
+ @example_groups = example_groups
433
+ end
434
+ attr_reader :duration, :examples, :number_of_examples
435
+
436
+ # @return [Array<RSpec::Core::Example>] the slowest examples
437
+ def slowest_examples
438
+ @slowest_examples ||=
439
+ examples.sort_by do |example|
440
+ -example.execution_result.run_time
441
+ end.first(number_of_examples)
442
+ end
443
+
444
+ # @return [Float] the time taken (in seconds) to run the slowest examples
445
+ def slow_duration
446
+ @slow_duration ||=
447
+ slowest_examples.inject(0.0) do |i, e|
448
+ i + e.execution_result.run_time
449
+ end
450
+ end
451
+
452
+ # @return [String] the percentage of total time taken
453
+ def percentage
454
+ @percentage ||=
455
+ begin
456
+ time_taken = slow_duration / duration
457
+ '%.1f' % ((time_taken.nan? ? 0.0 : time_taken) * 100)
458
+ end
459
+ end
460
+
461
+ # @return [Array<RSpec::Core::Example>] the slowest example groups
462
+ def slowest_groups
463
+ @slowest_groups ||= calculate_slowest_groups
464
+ end
465
+
466
+ private
467
+
468
+ def calculate_slowest_groups
469
+ # stop if we've only one example group
470
+ return {} if @example_groups.keys.length <= 1
471
+
472
+ @example_groups.each_value do |hash|
473
+ hash[:average] = hash[:total_time].to_f / hash[:count]
474
+ end
475
+
476
+ groups = @example_groups.sort_by { |_, hash| -hash[:average] }.first(number_of_examples)
477
+ groups.map { |group, data| [group.location, data] }
478
+ end
479
+ end
480
+
481
+ # The `DeprecationNotification` is issued by the reporter when a deprecated
482
+ # part of RSpec is encountered. It represents information about the
483
+ # deprecated call site.
484
+ #
485
+ # @attr message [String] A custom message about the deprecation
486
+ # @attr deprecated [String] A custom message about the deprecation (alias of
487
+ # message)
488
+ # @attr replacement [String] An optional replacement for the deprecation
489
+ # @attr call_site [String] An optional call site from which the deprecation
490
+ # was issued
491
+ DeprecationNotification = Struct.new(:deprecated, :message, :replacement, :call_site)
492
+ class DeprecationNotification
493
+ private_class_method :new
494
+
495
+ # @api
496
+ # Convenience way to initialize the notification
497
+ def self.from_hash(data)
498
+ new data[:deprecated], data[:message], data[:replacement], data[:call_site]
499
+ end
500
+ end
501
+
502
+ # `NullNotification` represents a placeholder value for notifications that
503
+ # currently require no information, but we may wish to extend in future.
504
+ class NullNotification
505
+ end
506
+
507
+ # `CustomNotification` is used when sending custom events to formatters /
508
+ # other registered listeners, it creates attributes based on supplied hash
509
+ # of options.
510
+ class CustomNotification < Struct
511
+ # @param options [Hash] A hash of method / value pairs to create on this notification
512
+ # @return [CustomNotification]
513
+ #
514
+ # Build a custom notification based on the supplied option key / values.
515
+ def self.for(options={})
516
+ return NullNotification if options.keys.empty?
517
+ new(*options.keys).new(*options.values)
518
+ end
519
+ end
520
+ end
521
+ end