rspec-core 3.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.document +5 -0
- data/.yardopts +8 -0
- data/Changelog.md +2243 -0
- data/LICENSE.md +26 -0
- data/README.md +384 -0
- data/exe/rspec +4 -0
- data/lib/rspec/autorun.rb +3 -0
- data/lib/rspec/core.rb +185 -0
- data/lib/rspec/core/backtrace_formatter.rb +65 -0
- data/lib/rspec/core/bisect/coordinator.rb +62 -0
- data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
- data/lib/rspec/core/bisect/fork_runner.rb +134 -0
- data/lib/rspec/core/bisect/server.rb +61 -0
- data/lib/rspec/core/bisect/shell_command.rb +126 -0
- data/lib/rspec/core/bisect/shell_runner.rb +73 -0
- data/lib/rspec/core/bisect/utilities.rb +58 -0
- data/lib/rspec/core/configuration.rb +2308 -0
- data/lib/rspec/core/configuration_options.rb +233 -0
- data/lib/rspec/core/drb.rb +113 -0
- data/lib/rspec/core/dsl.rb +98 -0
- data/lib/rspec/core/example.rb +656 -0
- data/lib/rspec/core/example_group.rb +889 -0
- data/lib/rspec/core/example_status_persister.rb +235 -0
- data/lib/rspec/core/filter_manager.rb +231 -0
- data/lib/rspec/core/flat_map.rb +20 -0
- data/lib/rspec/core/formatters.rb +269 -0
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/base_formatter.rb +70 -0
- data/lib/rspec/core/formatters/base_text_formatter.rb +75 -0
- data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
- data/lib/rspec/core/formatters/console_codes.rb +68 -0
- data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
- data/lib/rspec/core/formatters/documentation_formatter.rb +70 -0
- data/lib/rspec/core/formatters/exception_presenter.rb +508 -0
- data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
- data/lib/rspec/core/formatters/helpers.rb +110 -0
- data/lib/rspec/core/formatters/html_formatter.rb +153 -0
- data/lib/rspec/core/formatters/html_printer.rb +414 -0
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
- data/lib/rspec/core/formatters/json_formatter.rb +102 -0
- data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
- data/lib/rspec/core/formatters/progress_formatter.rb +29 -0
- data/lib/rspec/core/formatters/protocol.rb +182 -0
- data/lib/rspec/core/formatters/snippet_extractor.rb +134 -0
- data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
- data/lib/rspec/core/hooks.rb +624 -0
- data/lib/rspec/core/invocations.rb +87 -0
- data/lib/rspec/core/memoized_helpers.rb +554 -0
- data/lib/rspec/core/metadata.rb +498 -0
- data/lib/rspec/core/metadata_filter.rb +255 -0
- data/lib/rspec/core/minitest_assertions_adapter.rb +31 -0
- data/lib/rspec/core/mocking_adapters/flexmock.rb +31 -0
- data/lib/rspec/core/mocking_adapters/mocha.rb +57 -0
- data/lib/rspec/core/mocking_adapters/null.rb +14 -0
- data/lib/rspec/core/mocking_adapters/rr.rb +31 -0
- data/lib/rspec/core/mocking_adapters/rspec.rb +32 -0
- data/lib/rspec/core/notifications.rb +521 -0
- data/lib/rspec/core/option_parser.rb +309 -0
- data/lib/rspec/core/ordering.rb +158 -0
- data/lib/rspec/core/output_wrapper.rb +29 -0
- data/lib/rspec/core/pending.rb +165 -0
- data/lib/rspec/core/profiler.rb +34 -0
- data/lib/rspec/core/project_initializer.rb +48 -0
- data/lib/rspec/core/project_initializer/.rspec +1 -0
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +100 -0
- data/lib/rspec/core/rake_task.rb +168 -0
- data/lib/rspec/core/reporter.rb +257 -0
- data/lib/rspec/core/ruby_project.rb +53 -0
- data/lib/rspec/core/runner.rb +199 -0
- data/lib/rspec/core/sandbox.rb +37 -0
- data/lib/rspec/core/set.rb +54 -0
- data/lib/rspec/core/shared_context.rb +55 -0
- data/lib/rspec/core/shared_example_group.rb +269 -0
- data/lib/rspec/core/shell_escape.rb +49 -0
- data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
- data/lib/rspec/core/version.rb +9 -0
- data/lib/rspec/core/warnings.rb +40 -0
- data/lib/rspec/core/world.rb +275 -0
- metadata +292 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
RSpec::Support.require_rspec_core "formatters/base_bisect_formatter"
|
3
|
+
|
4
|
+
module RSpec
|
5
|
+
module Core
|
6
|
+
module Formatters
|
7
|
+
# Used by `--bisect`. When it shells out and runs a portion of the suite, it uses
|
8
|
+
# this formatter as a means to have the status reported back to it, via DRb.
|
9
|
+
#
|
10
|
+
# Note that since DRb calls carry considerable overhead compared to normal
|
11
|
+
# method calls, we try to minimize the number of DRb calls for perf reasons,
|
12
|
+
# opting to communicate only at the start and the end of the run, rather than
|
13
|
+
# after each example.
|
14
|
+
# @private
|
15
|
+
class BisectDRbFormatter < BaseBisectFormatter
|
16
|
+
def initialize(_output)
|
17
|
+
drb_uri = "druby://localhost:#{RSpec.configuration.drb_port}"
|
18
|
+
@bisect_server = DRbObject.new_with_uri(drb_uri)
|
19
|
+
RSpec.configuration.files_or_directories_to_run = @bisect_server.files_or_directories_to_run
|
20
|
+
super(Set.new(@bisect_server.expected_failures))
|
21
|
+
end
|
22
|
+
|
23
|
+
def notify_results(results)
|
24
|
+
@bisect_server.latest_run_results = results
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "formatters/base_text_formatter"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
module Formatters
|
6
|
+
# @private
|
7
|
+
# Produces progress output while bisecting.
|
8
|
+
class BisectProgressFormatter < BaseTextFormatter
|
9
|
+
def initialize(output, bisect_runner)
|
10
|
+
super(output)
|
11
|
+
@bisect_runner = bisect_runner
|
12
|
+
end
|
13
|
+
|
14
|
+
def bisect_starting(notification)
|
15
|
+
@round_count = 0
|
16
|
+
output.puts bisect_started_message(notification)
|
17
|
+
output.print "Running suite to find failures..."
|
18
|
+
end
|
19
|
+
|
20
|
+
def bisect_original_run_complete(notification)
|
21
|
+
failures = Helpers.pluralize(notification.failed_example_ids.size, "failing example")
|
22
|
+
non_failures = Helpers.pluralize(notification.non_failing_example_ids.size, "non-failing example")
|
23
|
+
|
24
|
+
output.puts " (#{Helpers.format_duration(notification.duration)})"
|
25
|
+
output.puts "Starting bisect with #{failures} and #{non_failures}."
|
26
|
+
end
|
27
|
+
|
28
|
+
def bisect_dependency_check_started(_notification)
|
29
|
+
output.print "Checking that failure(s) are order-dependent.."
|
30
|
+
end
|
31
|
+
|
32
|
+
def bisect_dependency_check_passed(_notification)
|
33
|
+
output.puts " failure appears to be order-dependent"
|
34
|
+
end
|
35
|
+
|
36
|
+
def bisect_dependency_check_failed(_notification)
|
37
|
+
output.puts " failure(s) do not require any non-failures to run first"
|
38
|
+
|
39
|
+
if @bisect_runner == :fork
|
40
|
+
output.puts
|
41
|
+
output.puts "=" * 80
|
42
|
+
output.puts "NOTE: this bisect run used `config.bisect_runner = :fork`, which generally"
|
43
|
+
output.puts "provides significantly faster bisection runs than the old shell-based runner,"
|
44
|
+
output.puts "but may inaccurately report that no non-failures are required. If this result"
|
45
|
+
output.puts "is unexpected, consider setting `config.bisect_runner = :shell` and trying again."
|
46
|
+
output.puts "=" * 80
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def bisect_round_started(notification, include_trailing_space=true)
|
51
|
+
@round_count += 1
|
52
|
+
range_desc = notification.candidate_range.description
|
53
|
+
|
54
|
+
output.print "\nRound #{@round_count}: bisecting over non-failing #{range_desc}"
|
55
|
+
output.print " " if include_trailing_space
|
56
|
+
end
|
57
|
+
|
58
|
+
def bisect_round_ignoring_ids(notification)
|
59
|
+
range_desc = notification.ignore_range.description
|
60
|
+
|
61
|
+
output.print " ignoring #{range_desc}"
|
62
|
+
output.print " (#{Helpers.format_duration(notification.duration)})"
|
63
|
+
end
|
64
|
+
|
65
|
+
def bisect_round_detected_multiple_culprits(notification)
|
66
|
+
output.print " multiple culprits detected - splitting candidates"
|
67
|
+
output.print " (#{Helpers.format_duration(notification.duration)})"
|
68
|
+
end
|
69
|
+
|
70
|
+
def bisect_individual_run_complete(_)
|
71
|
+
output.print '.'
|
72
|
+
end
|
73
|
+
|
74
|
+
def bisect_complete(notification)
|
75
|
+
output.puts "\nBisect complete! Reduced necessary non-failing examples " \
|
76
|
+
"from #{notification.original_non_failing_count} to " \
|
77
|
+
"#{notification.remaining_count} in " \
|
78
|
+
"#{Helpers.format_duration(notification.duration)}."
|
79
|
+
end
|
80
|
+
|
81
|
+
def bisect_repro_command(notification)
|
82
|
+
output.puts "\nThe minimal reproduction command is:\n #{notification.repro}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def bisect_failed(notification)
|
86
|
+
output.puts "\nBisect failed! #{notification.failure_explanation}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def bisect_aborted(notification)
|
90
|
+
output.puts "\n\nBisect aborted!"
|
91
|
+
output.puts "\nThe most minimal reproduction command discovered so far is:\n #{notification.repro}"
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def bisect_started_message(notification)
|
97
|
+
options = notification.original_cli_args.join(' ')
|
98
|
+
"Bisect started using options: #{options.inspect}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @private
|
103
|
+
# Produces detailed debug output while bisecting. Used when bisect is
|
104
|
+
# performed with `--bisect=verbose`. Designed to provide details for
|
105
|
+
# us when we need to troubleshoot bisect bugs.
|
106
|
+
class BisectDebugFormatter < BisectProgressFormatter
|
107
|
+
def bisect_original_run_complete(notification)
|
108
|
+
output.puts " (#{Helpers.format_duration(notification.duration)})"
|
109
|
+
|
110
|
+
output.puts " - #{describe_ids 'Failing examples', notification.failed_example_ids}"
|
111
|
+
output.puts " - #{describe_ids 'Non-failing examples', notification.non_failing_example_ids}"
|
112
|
+
end
|
113
|
+
|
114
|
+
def bisect_individual_run_start(notification)
|
115
|
+
output.print "\n - Running: #{notification.command}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def bisect_individual_run_complete(notification)
|
119
|
+
output.print " (#{Helpers.format_duration(notification.duration)})"
|
120
|
+
end
|
121
|
+
|
122
|
+
def bisect_dependency_check_passed(_notification)
|
123
|
+
output.print "\n - Failure appears to be order-dependent"
|
124
|
+
end
|
125
|
+
|
126
|
+
def bisect_dependency_check_failed(_notification)
|
127
|
+
output.print "\n - Failure is not order-dependent"
|
128
|
+
end
|
129
|
+
|
130
|
+
def bisect_round_started(notification)
|
131
|
+
super(notification, false)
|
132
|
+
end
|
133
|
+
|
134
|
+
def bisect_round_ignoring_ids(notification)
|
135
|
+
output.print "\n - #{describe_ids 'Examples we can safely ignore', notification.ids_to_ignore}"
|
136
|
+
output.print "\n - #{describe_ids 'Remaining non-failing examples', notification.remaining_ids}"
|
137
|
+
end
|
138
|
+
|
139
|
+
def bisect_round_detected_multiple_culprits(_notification)
|
140
|
+
output.print "\n - Multiple culprits detected - splitting candidates"
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def describe_ids(description, ids)
|
146
|
+
organized_ids = Formatters::Helpers.organize_ids(ids)
|
147
|
+
formatted_ids = organized_ids.map { |id| " - #{id}" }.join("\n")
|
148
|
+
"#{description} (#{ids.size}):\n#{formatted_ids}"
|
149
|
+
end
|
150
|
+
|
151
|
+
def bisect_started_message(notification)
|
152
|
+
"#{super} and bisect runner: #{notification.bisect_runner.inspect}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
module Formatters
|
4
|
+
# ConsoleCodes provides helpers for formatting console output
|
5
|
+
# with ANSI codes, e.g. color's and bold.
|
6
|
+
module ConsoleCodes
|
7
|
+
# @private
|
8
|
+
VT100_CODES =
|
9
|
+
{
|
10
|
+
:black => 30,
|
11
|
+
:red => 31,
|
12
|
+
:green => 32,
|
13
|
+
:yellow => 33,
|
14
|
+
:blue => 34,
|
15
|
+
:magenta => 35,
|
16
|
+
:cyan => 36,
|
17
|
+
:white => 37,
|
18
|
+
:bold => 1,
|
19
|
+
}
|
20
|
+
# @private
|
21
|
+
VT100_CODE_VALUES = VT100_CODES.invert
|
22
|
+
|
23
|
+
module_function
|
24
|
+
|
25
|
+
# @private
|
26
|
+
def config_colors_to_methods
|
27
|
+
@config_colors_to_methods ||=
|
28
|
+
Configuration.instance_methods.grep(/_color\z/).inject({}) do |hash, method|
|
29
|
+
hash[method.to_s.sub(/_color\z/, '').to_sym] = method
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fetches the correct code for the supplied symbol, or checks
|
35
|
+
# that a code is valid. Defaults to white (37).
|
36
|
+
#
|
37
|
+
# @param code_or_symbol [Symbol, Fixnum] Symbol or code to check
|
38
|
+
# @return [Fixnum] a console code
|
39
|
+
def console_code_for(code_or_symbol)
|
40
|
+
if (config_method = config_colors_to_methods[code_or_symbol])
|
41
|
+
console_code_for RSpec.configuration.__send__(config_method)
|
42
|
+
elsif VT100_CODE_VALUES.key?(code_or_symbol)
|
43
|
+
code_or_symbol
|
44
|
+
else
|
45
|
+
VT100_CODES.fetch(code_or_symbol) do
|
46
|
+
console_code_for(:white)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Wraps a piece of text in ANSI codes with the supplied code. Will
|
52
|
+
# only apply the control code if `RSpec.configuration.color_enabled?`
|
53
|
+
# returns true.
|
54
|
+
#
|
55
|
+
# @param text [String] the text to wrap
|
56
|
+
# @param code_or_symbol [Symbol, Fixnum] the desired control code
|
57
|
+
# @return [String] the wrapped text
|
58
|
+
def wrap(text, code_or_symbol)
|
59
|
+
if RSpec.configuration.color_enabled?
|
60
|
+
"\e[#{console_code_for(code_or_symbol)}m#{text}\e[0m"
|
61
|
+
else
|
62
|
+
text
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "formatters/helpers"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
module Formatters
|
6
|
+
# @private
|
7
|
+
class DeprecationFormatter
|
8
|
+
Formatters.register self, :deprecation, :deprecation_summary
|
9
|
+
|
10
|
+
attr_reader :count, :deprecation_stream, :summary_stream
|
11
|
+
|
12
|
+
def initialize(deprecation_stream, summary_stream)
|
13
|
+
@deprecation_stream = deprecation_stream
|
14
|
+
@summary_stream = summary_stream
|
15
|
+
@seen_deprecations = Set.new
|
16
|
+
@count = 0
|
17
|
+
end
|
18
|
+
alias :output :deprecation_stream
|
19
|
+
|
20
|
+
def printer
|
21
|
+
@printer ||= case deprecation_stream
|
22
|
+
when File
|
23
|
+
ImmediatePrinter.new(FileStream.new(deprecation_stream),
|
24
|
+
summary_stream, self)
|
25
|
+
when RaiseErrorStream
|
26
|
+
ImmediatePrinter.new(deprecation_stream, summary_stream, self)
|
27
|
+
else
|
28
|
+
DelayedPrinter.new(deprecation_stream, summary_stream, self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def deprecation(notification)
|
33
|
+
return if @seen_deprecations.include? notification
|
34
|
+
|
35
|
+
@count += 1
|
36
|
+
printer.print_deprecation_message notification
|
37
|
+
@seen_deprecations << notification
|
38
|
+
end
|
39
|
+
|
40
|
+
def deprecation_summary(_notification)
|
41
|
+
printer.deprecation_summary
|
42
|
+
end
|
43
|
+
|
44
|
+
def deprecation_message_for(data)
|
45
|
+
if data.message
|
46
|
+
SpecifiedDeprecationMessage.new(data)
|
47
|
+
else
|
48
|
+
GeneratedDeprecationMessage.new(data)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
RAISE_ERROR_CONFIG_NOTICE = <<-EOS.gsub(/^\s+\|/, '')
|
53
|
+
|
|
54
|
+
|If you need more of the backtrace for any of these deprecations to
|
55
|
+
|identify where to make the necessary changes, you can configure
|
56
|
+
|`config.raise_errors_for_deprecations!`, and it will turn the
|
57
|
+
|deprecation warnings into errors, giving you the full backtrace.
|
58
|
+
EOS
|
59
|
+
|
60
|
+
DEPRECATION_STREAM_NOTICE = "Pass `--deprecation-out` or set " \
|
61
|
+
"`config.deprecation_stream` to a file for full output."
|
62
|
+
TOO_MANY_WARNINGS_NOTICE = "Too many similar deprecation messages " \
|
63
|
+
"reported, disregarding further reports. #{DEPRECATION_STREAM_NOTICE}"
|
64
|
+
|
65
|
+
# @private
|
66
|
+
SpecifiedDeprecationMessage = Struct.new(:type) do
|
67
|
+
def initialize(data)
|
68
|
+
@message = data.message
|
69
|
+
super deprecation_type_for(data)
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
output_formatted @message
|
74
|
+
end
|
75
|
+
|
76
|
+
def too_many_warnings_message
|
77
|
+
TOO_MANY_WARNINGS_NOTICE
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def output_formatted(str)
|
83
|
+
return str unless str.lines.count > 1
|
84
|
+
separator = '-' * 80
|
85
|
+
"#{separator}\n#{str.chomp}\n#{separator}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def deprecation_type_for(data)
|
89
|
+
data.message.gsub(/(\w+\/)+\w+\.rb:\d+/, '')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @private
|
94
|
+
GeneratedDeprecationMessage = Struct.new(:type) do
|
95
|
+
def initialize(data)
|
96
|
+
@data = data
|
97
|
+
super data.deprecated
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_s
|
101
|
+
msg = String.new("#{@data.deprecated} is deprecated.")
|
102
|
+
msg << " Use #{@data.replacement} instead." if @data.replacement
|
103
|
+
msg << " Called from #{@data.call_site}." if @data.call_site
|
104
|
+
msg
|
105
|
+
end
|
106
|
+
|
107
|
+
def too_many_warnings_message
|
108
|
+
"Too many uses of deprecated '#{type}'. #{DEPRECATION_STREAM_NOTICE}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# @private
|
113
|
+
class ImmediatePrinter
|
114
|
+
attr_reader :deprecation_stream, :summary_stream, :deprecation_formatter
|
115
|
+
|
116
|
+
def initialize(deprecation_stream, summary_stream, deprecation_formatter)
|
117
|
+
@deprecation_stream = deprecation_stream
|
118
|
+
|
119
|
+
@summary_stream = summary_stream
|
120
|
+
@deprecation_formatter = deprecation_formatter
|
121
|
+
end
|
122
|
+
|
123
|
+
def print_deprecation_message(data)
|
124
|
+
deprecation_message = deprecation_formatter.deprecation_message_for(data)
|
125
|
+
deprecation_stream.puts deprecation_message.to_s
|
126
|
+
end
|
127
|
+
|
128
|
+
def deprecation_summary
|
129
|
+
return if deprecation_formatter.count.zero?
|
130
|
+
deprecation_stream.summarize(summary_stream, deprecation_formatter.count)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @private
|
135
|
+
class DelayedPrinter
|
136
|
+
TOO_MANY_USES_LIMIT = 4
|
137
|
+
|
138
|
+
attr_reader :deprecation_stream, :summary_stream, :deprecation_formatter
|
139
|
+
|
140
|
+
def initialize(deprecation_stream, summary_stream, deprecation_formatter)
|
141
|
+
@deprecation_stream = deprecation_stream
|
142
|
+
@summary_stream = summary_stream
|
143
|
+
@deprecation_formatter = deprecation_formatter
|
144
|
+
@seen_deprecations = Hash.new { 0 }
|
145
|
+
@deprecation_messages = Hash.new { |h, k| h[k] = [] }
|
146
|
+
end
|
147
|
+
|
148
|
+
def print_deprecation_message(data)
|
149
|
+
deprecation_message = deprecation_formatter.deprecation_message_for(data)
|
150
|
+
@seen_deprecations[deprecation_message] += 1
|
151
|
+
|
152
|
+
stash_deprecation_message(deprecation_message)
|
153
|
+
end
|
154
|
+
|
155
|
+
def stash_deprecation_message(deprecation_message)
|
156
|
+
if @seen_deprecations[deprecation_message] < TOO_MANY_USES_LIMIT
|
157
|
+
@deprecation_messages[deprecation_message] << deprecation_message.to_s
|
158
|
+
elsif @seen_deprecations[deprecation_message] == TOO_MANY_USES_LIMIT
|
159
|
+
@deprecation_messages[deprecation_message] << deprecation_message.too_many_warnings_message
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def deprecation_summary
|
164
|
+
return unless @deprecation_messages.any?
|
165
|
+
|
166
|
+
print_deferred_deprecation_warnings
|
167
|
+
deprecation_stream.puts RAISE_ERROR_CONFIG_NOTICE
|
168
|
+
|
169
|
+
summary_stream.puts "\n#{Helpers.pluralize(deprecation_formatter.count, 'deprecation warning')} total"
|
170
|
+
end
|
171
|
+
|
172
|
+
def print_deferred_deprecation_warnings
|
173
|
+
deprecation_stream.puts "\nDeprecation Warnings:\n\n"
|
174
|
+
@deprecation_messages.keys.sort_by(&:type).each do |deprecation|
|
175
|
+
messages = @deprecation_messages[deprecation]
|
176
|
+
messages.each { |msg| deprecation_stream.puts msg }
|
177
|
+
deprecation_stream.puts
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# @private
|
183
|
+
# Not really a stream, but is usable in place of one.
|
184
|
+
class RaiseErrorStream
|
185
|
+
def puts(message)
|
186
|
+
raise DeprecationError, message
|
187
|
+
end
|
188
|
+
|
189
|
+
def summarize(summary_stream, deprecation_count)
|
190
|
+
summary_stream.puts "\n#{Helpers.pluralize(deprecation_count, 'deprecation')} found."
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# @private
|
195
|
+
# Wraps a File object and provides file-specific operations.
|
196
|
+
class FileStream
|
197
|
+
def initialize(file)
|
198
|
+
@file = file
|
199
|
+
|
200
|
+
# In one of my test suites, I got lots of duplicate output in the
|
201
|
+
# deprecation file (e.g. 200 of the same deprecation, even though
|
202
|
+
# the `puts` below was only called 6 times). Setting `sync = true`
|
203
|
+
# fixes this (but we really have no idea why!).
|
204
|
+
@file.sync = true
|
205
|
+
end
|
206
|
+
|
207
|
+
def puts(*args)
|
208
|
+
@file.puts(*args)
|
209
|
+
end
|
210
|
+
|
211
|
+
def summarize(summary_stream, deprecation_count)
|
212
|
+
path = @file.respond_to?(:path) ? @file.path : @file.inspect
|
213
|
+
summary_stream.puts "\n#{Helpers.pluralize(deprecation_count, 'deprecation')} logged to #{path}"
|
214
|
+
puts RAISE_ERROR_CONFIG_NOTICE
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Deprecation Error.
|
221
|
+
DeprecationError = Class.new(StandardError)
|
222
|
+
end
|
223
|
+
end
|