activesupport 7.1.3.4 → 8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -1136
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +15 -3
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +19 -18
- data/lib/active_support/cache/file_store.rb +27 -12
- data/lib/active_support/cache/mem_cache_store.rb +16 -74
- data/lib/active_support/cache/memory_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +21 -15
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache.rb +76 -78
- data/lib/active_support/callbacks.rb +79 -116
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +24 -10
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/core_ext/array/conversions.rb +3 -5
- data/lib/active_support/core_ext/benchmark.rb +6 -9
- data/lib/active_support/core_ext/class/attribute.rb +24 -20
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -2
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/enumerable.rb +8 -3
- data/lib/active_support/core_ext/erb/util.rb +7 -2
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -148
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/duplicable.rb +24 -15
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +21 -13
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/range/overlap.rb +1 -1
- data/lib/active_support/core_ext/securerandom.rb +4 -4
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +0 -7
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +32 -30
- data/lib/active_support/core_ext/time/compatibility.rb +24 -0
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +38 -40
- data/lib/active_support/delegation.rb +200 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/dependencies.rb +0 -1
- data/lib/active_support/deprecation/constant_accessor.rb +47 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +3 -17
- data/lib/active_support/deprecation.rb +8 -5
- data/lib/active_support/descendants_tracker.rb +9 -87
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -2
- data/lib/active_support/duration.rb +25 -16
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +65 -3
- data/lib/active_support/evented_file_update_checker.rb +0 -2
- data/lib/active_support/execution_wrapper.rb +0 -1
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +21 -23
- data/lib/active_support/html_safe_translation.rb +7 -4
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/isolated_execution_state.rb +0 -2
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/log_subscriber.rb +1 -12
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +0 -8
- data/lib/active_support/message_pack/extensions.rb +15 -2
- data/lib/active_support/message_verifier.rb +12 -0
- data/lib/active_support/messages/codec.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +2 -2
- data/lib/active_support/notifications/fanout.rb +4 -8
- data/lib/active_support/notifications/instrumenter.rb +32 -21
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/railtie.rb +8 -11
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +1 -0
- data/lib/active_support/syntax_error_proxy.rb +1 -11
- data/lib/active_support/tagged_logging.rb +9 -1
- data/lib/active_support/test_case.rb +3 -1
- data/lib/active_support/testing/assertions.rb +79 -21
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/isolation.rb +19 -9
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/parallelization/server.rb +3 -0
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/strict_warnings.rb +8 -4
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +4 -3
- data/lib/active_support/time_with_zone.rb +30 -17
- data/lib/active_support/values/time_zone.rb +25 -14
- data/lib/active_support/xml_mini.rb +11 -2
- data/lib/active_support.rb +12 -4
- metadata +68 -19
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/proxy_object.rb +0 -17
- data/lib/active_support/ruby_features.rb +0 -7
@@ -1,6 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
+
# = Number Helper
|
5
|
+
#
|
6
|
+
# Provides methods for formatting numbers into currencies, percentages,
|
7
|
+
# phone numbers, and more.
|
8
|
+
#
|
9
|
+
# Example usage in a class:
|
10
|
+
# class Topic
|
11
|
+
# include ActiveSupport::NumberHelper
|
12
|
+
#
|
13
|
+
# def price
|
14
|
+
# number_to_currency(@price)
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Example usage in a module:
|
19
|
+
# require "active_support/number_helper"
|
20
|
+
#
|
21
|
+
# module NumberFormatting
|
22
|
+
# def format_price(price)
|
23
|
+
# ActiveSupport::NumberHelper.number_to_currency(price)
|
24
|
+
# end
|
25
|
+
# end
|
4
26
|
module NumberHelper
|
5
27
|
extend ActiveSupport::Autoload
|
6
28
|
|
@@ -46,18 +46,14 @@ module ActiveSupport
|
|
46
46
|
super(key.to_sym, *identifiers)
|
47
47
|
end
|
48
48
|
|
49
|
-
def method_missing(
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
def method_missing(method, *args)
|
50
|
+
if method.end_with?("=")
|
51
|
+
self[method.name.chomp("=")] = args.first
|
52
|
+
elsif method.end_with?("!")
|
53
|
+
name_string = method.name.chomp("!")
|
54
|
+
self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
|
53
55
|
else
|
54
|
-
|
55
|
-
|
56
|
-
if bangs
|
57
|
-
self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
|
58
|
-
else
|
59
|
-
self[name_string]
|
60
|
-
end
|
56
|
+
self[method.name]
|
61
57
|
end
|
62
58
|
end
|
63
59
|
|
@@ -92,18 +88,60 @@ module ActiveSupport
|
|
92
88
|
# h.boy # => 'John'
|
93
89
|
class InheritableOptions < OrderedOptions
|
94
90
|
def initialize(parent = nil)
|
95
|
-
|
91
|
+
@parent = parent
|
92
|
+
if @parent.kind_of?(OrderedOptions)
|
96
93
|
# use the faster _get when dealing with OrderedOptions
|
97
|
-
super() { |h, k| parent._get(k) }
|
98
|
-
elsif parent
|
99
|
-
super() { |h, k| parent[k] }
|
94
|
+
super() { |h, k| @parent._get(k) }
|
95
|
+
elsif @parent
|
96
|
+
super() { |h, k| @parent[k] }
|
100
97
|
else
|
101
98
|
super()
|
99
|
+
@parent = {}
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
103
|
+
def to_h
|
104
|
+
@parent.merge(self)
|
105
|
+
end
|
106
|
+
|
107
|
+
def ==(other)
|
108
|
+
to_h == other.to_h
|
109
|
+
end
|
110
|
+
|
111
|
+
def inspect
|
112
|
+
"#<#{self.class.name} #{to_h.inspect}>"
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_s
|
116
|
+
to_h.to_s
|
117
|
+
end
|
118
|
+
|
119
|
+
def pretty_print(pp)
|
120
|
+
pp.pp_hash(to_h)
|
121
|
+
end
|
122
|
+
|
123
|
+
alias_method :own_key?, :key?
|
124
|
+
private :own_key?
|
125
|
+
|
126
|
+
def key?(key)
|
127
|
+
super || @parent.key?(key)
|
128
|
+
end
|
129
|
+
|
130
|
+
def overridden?(key)
|
131
|
+
!!(@parent && @parent.key?(key) && own_key?(key.to_sym))
|
132
|
+
end
|
133
|
+
|
105
134
|
def inheritable_copy
|
106
135
|
self.class.new(self)
|
107
136
|
end
|
137
|
+
|
138
|
+
def to_a
|
139
|
+
entries
|
140
|
+
end
|
141
|
+
|
142
|
+
def each(&block)
|
143
|
+
to_h.each(&block)
|
144
|
+
self
|
145
|
+
end
|
108
146
|
end
|
109
147
|
end
|
@@ -89,10 +89,15 @@ module ActiveSupport
|
|
89
89
|
begin
|
90
90
|
TZInfo::DataSource.get
|
91
91
|
rescue TZInfo::DataSourceNotFound => e
|
92
|
-
raise e.exception
|
92
|
+
raise e.exception('tzinfo-data is not present. Please add gem "tzinfo-data" to your Gemfile and run bundle install')
|
93
93
|
end
|
94
94
|
require "active_support/core_ext/time/zones"
|
95
95
|
Time.zone_default = Time.find_zone!(app.config.time_zone)
|
96
|
+
config.eager_load_namespaces << TZInfo
|
97
|
+
end
|
98
|
+
|
99
|
+
initializer "active_support.to_time_preserves_timezone" do |app|
|
100
|
+
ActiveSupport.to_time_preserves_timezone = app.config.active_support.to_time_preserves_timezone
|
96
101
|
end
|
97
102
|
|
98
103
|
# Sets the default week start
|
@@ -117,16 +122,8 @@ module ActiveSupport
|
|
117
122
|
|
118
123
|
initializer "active_support.set_configs" do |app|
|
119
124
|
app.config.active_support.each do |k, v|
|
120
|
-
|
121
|
-
|
122
|
-
elsif k == "remove_deprecated_time_with_zone_name"
|
123
|
-
ActiveSupport.deprecator.warn("config.active_support.remove_deprecated_time_with_zone_name is deprecated and will be removed in Rails 7.2.")
|
124
|
-
elsif k == "use_rfc4122_namespaced_uuids"
|
125
|
-
ActiveSupport.deprecator.warn("config.active_support.use_rfc4122_namespaced_uuids is deprecated and will be removed in Rails 7.2.")
|
126
|
-
else
|
127
|
-
k = "#{k}="
|
128
|
-
ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
|
129
|
-
end
|
125
|
+
k = "#{k}="
|
126
|
+
ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
|
130
127
|
end
|
131
128
|
end
|
132
129
|
|
@@ -67,6 +67,7 @@ module ActiveSupport
|
|
67
67
|
|
68
68
|
# Adds event subscribers for all new methods added to the class.
|
69
69
|
def method_added(event)
|
70
|
+
super
|
70
71
|
# Only public methods are added as subscribers, and only if a notifier
|
71
72
|
# has been set up. This means that subscribers will only be set up for
|
72
73
|
# classes that call #attach_to.
|
@@ -45,7 +45,7 @@ module ActiveSupport
|
|
45
45
|
|
46
46
|
private
|
47
47
|
def parse_message_for_trace
|
48
|
-
if
|
48
|
+
if __getobj__.to_s.start_with?("(eval")
|
49
49
|
# If the exception is coming from a call to eval, we need to keep
|
50
50
|
# the path of the file in which eval was called to ensure we can
|
51
51
|
# return the right source fragment to show the location of the
|
@@ -56,15 +56,5 @@ module ActiveSupport
|
|
56
56
|
__getobj__.to_s.split("\n")
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
60
|
-
if SyntaxError.method_defined?(:path) # Ruby 3.3+
|
61
|
-
def source_location_eval?
|
62
|
-
__getobj__.path.start_with?("(eval")
|
63
|
-
end
|
64
|
-
else # 3.2 and older versions of Ruby
|
65
|
-
def source_location_eval?
|
66
|
-
__getobj__.to_s.start_with?("(eval")
|
67
|
-
end
|
68
|
-
end
|
69
59
|
end
|
70
60
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/module/delegation"
|
4
4
|
require "active_support/core_ext/object/blank"
|
5
|
-
require "logger"
|
6
5
|
require "active_support/logger"
|
7
6
|
|
8
7
|
module ActiveSupport
|
@@ -114,11 +113,20 @@ module ActiveSupport
|
|
114
113
|
end
|
115
114
|
end
|
116
115
|
|
116
|
+
# Returns an `ActiveSupport::Logger` that has already been wrapped with tagged logging concern.
|
117
|
+
def self.logger(*args, **kwargs)
|
118
|
+
new ActiveSupport::Logger.new(*args, **kwargs)
|
119
|
+
end
|
120
|
+
|
117
121
|
def self.new(logger)
|
118
122
|
logger = logger.clone
|
119
123
|
|
120
124
|
if logger.formatter
|
121
125
|
logger.formatter = logger.formatter.clone
|
126
|
+
|
127
|
+
# Workaround for https://bugs.ruby-lang.org/issues/20250
|
128
|
+
# Can be removed when Ruby 3.4 is the least supported version.
|
129
|
+
logger.formatter.object_id if logger.formatter.is_a?(Proc)
|
122
130
|
else
|
123
131
|
# Ensure we set a default formatter so we aren't extending nil!
|
124
132
|
logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "minitest"
|
4
4
|
require "active_support/testing/tagged_logging"
|
5
5
|
require "active_support/testing/setup_and_teardown"
|
6
|
+
require "active_support/testing/tests_without_assertions"
|
6
7
|
require "active_support/testing/assertions"
|
7
8
|
require "active_support/testing/error_reporter_assertions"
|
8
9
|
require "active_support/testing/deprecation"
|
@@ -78,7 +79,7 @@ module ActiveSupport
|
|
78
79
|
# number of tests to run is above the +threshold+ param. The default value is
|
79
80
|
# 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
|
80
81
|
def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
|
81
|
-
workers = Concurrent.
|
82
|
+
workers = Concurrent.processor_count if workers == :number_of_processors
|
82
83
|
workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
|
83
84
|
|
84
85
|
Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
|
@@ -142,6 +143,7 @@ module ActiveSupport
|
|
142
143
|
|
143
144
|
include ActiveSupport::Testing::TaggedLogging
|
144
145
|
prepend ActiveSupport::Testing::SetupAndTeardown
|
146
|
+
prepend ActiveSupport::Testing::TestsWithoutAssertions
|
145
147
|
include ActiveSupport::Testing::Assertions
|
146
148
|
include ActiveSupport::Testing::ErrorReporterAssertions
|
147
149
|
include ActiveSupport::Testing::Deprecation
|
@@ -19,7 +19,7 @@ module ActiveSupport
|
|
19
19
|
#
|
20
20
|
# assert_not foo, 'foo should be false'
|
21
21
|
def assert_not(object, message = nil)
|
22
|
-
message ||= "Expected #{mu_pp(object)} to be nil or false"
|
22
|
+
message ||= -> { "Expected #{mu_pp(object)} to be nil or false" }
|
23
23
|
assert !object, message
|
24
24
|
end
|
25
25
|
|
@@ -118,9 +118,13 @@ module ActiveSupport
|
|
118
118
|
|
119
119
|
expressions.zip(exps, before) do |(code, diff), exp, before_value|
|
120
120
|
actual = exp.call
|
121
|
-
|
122
|
-
|
123
|
-
|
121
|
+
rich_message = -> do
|
122
|
+
code_string = code.respond_to?(:call) ? _callable_to_source_string(code) : code
|
123
|
+
error = "`#{code_string}` didn't change by #{diff}, but by #{actual - before_value}"
|
124
|
+
error = "#{message}.\n#{error}" if message
|
125
|
+
error
|
126
|
+
end
|
127
|
+
assert_equal(before_value + diff, actual, rich_message)
|
124
128
|
end
|
125
129
|
|
126
130
|
retval
|
@@ -195,22 +199,32 @@ module ActiveSupport
|
|
195
199
|
retval = _assert_nothing_raised_or_warn("assert_changes", &block)
|
196
200
|
|
197
201
|
unless from == UNTRACKED
|
198
|
-
|
199
|
-
|
200
|
-
|
202
|
+
rich_message = -> do
|
203
|
+
error = "Expected change from #{from.inspect}, got #{before.inspect}"
|
204
|
+
error = "#{message}.\n#{error}" if message
|
205
|
+
error
|
206
|
+
end
|
207
|
+
assert from === before, rich_message
|
201
208
|
end
|
202
209
|
|
203
210
|
after = exp.call
|
204
211
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
212
|
+
rich_message = -> do
|
213
|
+
code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
|
214
|
+
error = "`#{code_string}` didn't change"
|
215
|
+
error = "#{error}. It was already #{to.inspect}" if before == to
|
216
|
+
error = "#{message}.\n#{error}" if message
|
217
|
+
error
|
218
|
+
end
|
219
|
+
refute_equal before, after, rich_message
|
209
220
|
|
210
221
|
unless to == UNTRACKED
|
211
|
-
|
212
|
-
|
213
|
-
|
222
|
+
rich_message = -> do
|
223
|
+
error = "Expected change to #{to.inspect}, got #{after.inspect}\n"
|
224
|
+
error = "#{message}.\n#{error}" if message
|
225
|
+
error
|
226
|
+
end
|
227
|
+
assert to === after, rich_message
|
214
228
|
end
|
215
229
|
|
216
230
|
retval
|
@@ -242,20 +256,27 @@ module ActiveSupport
|
|
242
256
|
retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
|
243
257
|
|
244
258
|
unless from == UNTRACKED
|
245
|
-
|
246
|
-
|
247
|
-
|
259
|
+
rich_message = -> do
|
260
|
+
error = "Expected initial value of #{from.inspect}, got #{before.inspect}"
|
261
|
+
error = "#{message}.\n#{error}" if message
|
262
|
+
error
|
263
|
+
end
|
264
|
+
assert from === before, rich_message
|
248
265
|
end
|
249
266
|
|
250
267
|
after = exp.call
|
251
268
|
|
252
|
-
|
253
|
-
|
269
|
+
rich_message = -> do
|
270
|
+
code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
|
271
|
+
error = "`#{code_string}` changed"
|
272
|
+
error = "#{message}.\n#{error}" if message
|
273
|
+
error
|
274
|
+
end
|
254
275
|
|
255
276
|
if before.nil?
|
256
|
-
assert_nil after,
|
277
|
+
assert_nil after, rich_message
|
257
278
|
else
|
258
|
-
assert_equal before, after,
|
279
|
+
assert_equal before, after, rich_message
|
259
280
|
end
|
260
281
|
|
261
282
|
retval
|
@@ -276,6 +297,43 @@ module ActiveSupport
|
|
276
297
|
|
277
298
|
raise
|
278
299
|
end
|
300
|
+
|
301
|
+
def _callable_to_source_string(callable)
|
302
|
+
if defined?(RubyVM::InstructionSequence) && callable.is_a?(Proc)
|
303
|
+
iseq = RubyVM::InstructionSequence.of(callable)
|
304
|
+
source =
|
305
|
+
if iseq.script_lines
|
306
|
+
iseq.script_lines.join("\n")
|
307
|
+
elsif File.readable?(iseq.absolute_path)
|
308
|
+
File.read(iseq.absolute_path)
|
309
|
+
end
|
310
|
+
|
311
|
+
return callable unless source
|
312
|
+
|
313
|
+
location = iseq.to_a[4][:code_location]
|
314
|
+
return callable unless location
|
315
|
+
|
316
|
+
lines = source.lines[(location[0] - 1)..(location[2] - 1)]
|
317
|
+
lines[-1] = lines[-1].byteslice(...location[3])
|
318
|
+
lines[0] = lines[0].byteslice(location[1]...)
|
319
|
+
source = lines.join.strip
|
320
|
+
|
321
|
+
# We ignore procs defined with do/end as they are likely multi-line anyway.
|
322
|
+
if source.start_with?("{")
|
323
|
+
source.delete_suffix!("}")
|
324
|
+
source.delete_prefix!("{")
|
325
|
+
source.strip!
|
326
|
+
# It won't read nice if the callable contains multiple
|
327
|
+
# lines, and it should be a rare occurrence anyway.
|
328
|
+
# Same if it takes arguments.
|
329
|
+
if !source.include?("\n") && !source.start_with?("|")
|
330
|
+
return source
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
callable
|
336
|
+
end
|
279
337
|
end
|
280
338
|
end
|
281
339
|
end
|
@@ -15,17 +15,39 @@ module ActiveSupport
|
|
15
15
|
# Using this method rather than forcing <tt>World::List::Import::LARGE_IMPORT_THRESHOLD = 5000</tt> prevents
|
16
16
|
# warnings from being thrown, and ensures that the old value is returned after the test has completed.
|
17
17
|
#
|
18
|
+
# If the constant doesn't already exists, but you need it set for the duration of the block
|
19
|
+
# you can do so by passing `exists: false`.
|
20
|
+
#
|
21
|
+
# stub_const(object, :SOME_CONST, 1, exists: false) do
|
22
|
+
# assert_equal 1, SOME_CONST
|
23
|
+
# end
|
24
|
+
#
|
18
25
|
# Note: Stubbing a const will stub it across all threads. So if you have concurrent threads
|
19
26
|
# (like separate test suites running in parallel) that all depend on the same constant, it's possible
|
20
27
|
# divergent stubbing will trample on each other.
|
21
|
-
def stub_const(mod, constant, new_value)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
def stub_const(mod, constant, new_value, exists: true)
|
29
|
+
if exists
|
30
|
+
begin
|
31
|
+
old_value = mod.const_get(constant, false)
|
32
|
+
mod.send(:remove_const, constant)
|
33
|
+
mod.const_set(constant, new_value)
|
34
|
+
yield
|
35
|
+
ensure
|
36
|
+
mod.send(:remove_const, constant)
|
37
|
+
mod.const_set(constant, old_value)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
if mod.const_defined?(constant)
|
41
|
+
raise NameError, "already defined constant #{constant} in #{mod.name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
begin
|
45
|
+
mod.const_set(constant, new_value)
|
46
|
+
yield
|
47
|
+
ensure
|
48
|
+
mod.send(:remove_const, constant)
|
49
|
+
end
|
50
|
+
end
|
29
51
|
end
|
30
52
|
end
|
31
53
|
end
|
@@ -29,10 +29,11 @@ module ActiveSupport
|
|
29
29
|
# end
|
30
30
|
def assert_deprecated(match = nil, deprecator = nil, &block)
|
31
31
|
match, deprecator = nil, match if match.is_a?(ActiveSupport::Deprecation)
|
32
|
+
|
32
33
|
unless deprecator
|
33
|
-
|
34
|
-
deprecator = ActiveSupport::Deprecation._instance
|
34
|
+
raise ArgumentError, "No deprecator given"
|
35
35
|
end
|
36
|
+
|
36
37
|
result, warnings = collect_deprecations(deprecator, &block)
|
37
38
|
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
|
38
39
|
if match
|
@@ -51,11 +52,7 @@ module ActiveSupport
|
|
51
52
|
# assert_not_deprecated(ActiveSupport::Deprecation.new) do
|
52
53
|
# CustomDeprecator.warn "message" # passes assertion, different deprecator
|
53
54
|
# end
|
54
|
-
def assert_not_deprecated(deprecator
|
55
|
-
unless deprecator
|
56
|
-
ActiveSupport.deprecator.warn("assert_not_deprecated without a deprecator is deprecated")
|
57
|
-
deprecator = ActiveSupport::Deprecation._instance
|
58
|
-
end
|
55
|
+
def assert_not_deprecated(deprecator, &block)
|
59
56
|
result, deprecations = collect_deprecations(deprecator, &block)
|
60
57
|
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
|
61
58
|
result
|
@@ -69,11 +66,7 @@ module ActiveSupport
|
|
69
66
|
# ActiveSupport::Deprecation.new.warn "other message"
|
70
67
|
# :result
|
71
68
|
# end # => [:result, ["message"]]
|
72
|
-
def collect_deprecations(deprecator
|
73
|
-
unless deprecator
|
74
|
-
ActiveSupport.deprecator.warn("collect_deprecations without a deprecator is deprecated")
|
75
|
-
deprecator = ActiveSupport::Deprecation._instance
|
76
|
-
end
|
69
|
+
def collect_deprecations(deprecator)
|
77
70
|
old_behavior = deprecator.behavior
|
78
71
|
deprecations = []
|
79
72
|
deprecator.behavior = Proc.new do |message, callstack|
|
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/testing/parallelize_executor"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module Testing
|
5
7
|
module Isolation
|
6
|
-
|
8
|
+
SubprocessCrashed = Class.new(StandardError)
|
7
9
|
|
8
10
|
def self.included(klass) # :nodoc:
|
9
11
|
klass.class_eval do
|
10
|
-
parallelize_me!
|
12
|
+
parallelize_me! unless Minitest.parallel_executor.is_a?(ActiveSupport::Testing::ParallelizeExecutor)
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
@@ -16,10 +18,17 @@ module ActiveSupport
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def run
|
19
|
-
serialized = run_in_isolation do
|
21
|
+
status, serialized = run_in_isolation do
|
20
22
|
super
|
21
23
|
end
|
22
24
|
|
25
|
+
unless status&.success?
|
26
|
+
error = SubprocessCrashed.new("Subprocess exited with an error: #{status.inspect}\noutput: #{serialized.inspect}")
|
27
|
+
error.set_backtrace(caller)
|
28
|
+
self.failures << Minitest::UnexpectedError.new(error)
|
29
|
+
return defined?(Minitest::Result) ? Minitest::Result.from(self) : dup
|
30
|
+
end
|
31
|
+
|
23
32
|
Marshal.load(serialized)
|
24
33
|
end
|
25
34
|
|
@@ -50,13 +59,13 @@ module ActiveSupport
|
|
50
59
|
end
|
51
60
|
|
52
61
|
write.puts [result].pack("m")
|
53
|
-
exit!
|
62
|
+
exit!(0)
|
54
63
|
end
|
55
64
|
|
56
65
|
write.close
|
57
66
|
result = read.read
|
58
|
-
Process.wait2(pid)
|
59
|
-
result.unpack1("m")
|
67
|
+
_, status = Process.wait2(pid)
|
68
|
+
return status, result.unpack1("m")
|
60
69
|
end
|
61
70
|
end
|
62
71
|
end
|
@@ -75,7 +84,7 @@ module ActiveSupport
|
|
75
84
|
File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
|
76
85
|
file.puts [Marshal.dump(test_result)].pack("m")
|
77
86
|
end
|
78
|
-
exit!
|
87
|
+
exit!(0)
|
79
88
|
else
|
80
89
|
Tempfile.open("isolation") do |tmpfile|
|
81
90
|
env = {
|
@@ -93,13 +102,14 @@ module ActiveSupport
|
|
93
102
|
|
94
103
|
child = IO.popen([env, Gem.ruby, *load_path_args, $0, *ORIG_ARGV, test_opts])
|
95
104
|
|
105
|
+
status = nil
|
96
106
|
begin
|
97
|
-
Process.
|
107
|
+
_, status = Process.wait2(child.pid)
|
98
108
|
rescue Errno::ECHILD # The child process may exit before we wait
|
99
109
|
nil
|
100
110
|
end
|
101
111
|
|
102
|
-
return tmpfile.read.unpack1("m")
|
112
|
+
return status, tmpfile.read.unpack1("m")
|
103
113
|
end
|
104
114
|
end
|
105
115
|
end
|
@@ -30,22 +30,8 @@ module ActiveSupport
|
|
30
30
|
assert_called(object, method_name, message, times: 0, &block)
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
# the Minitest 5.16 / Ruby 3.0 kwargs transition. It can go away
|
36
|
-
# when we drop support for Ruby 2.7.
|
37
|
-
if Minitest::Mock.instance_method(:expect).parameters.map(&:first).include?(:keyrest)
|
38
|
-
def expect_called_with(mock, args, returns: false, **kwargs)
|
39
|
-
mock.expect(:call, returns, args, **kwargs)
|
40
|
-
end
|
41
|
-
else
|
42
|
-
def expect_called_with(mock, args, returns: false, **kwargs)
|
43
|
-
if !kwargs.empty?
|
44
|
-
mock.expect(:call, returns, [*args, kwargs])
|
45
|
-
else
|
46
|
-
mock.expect(:call, returns, args)
|
47
|
-
end
|
48
|
-
end
|
33
|
+
def expect_called_with(mock, args, returns: false, **kwargs)
|
34
|
+
mock.expect(:call, returns, args, **kwargs)
|
49
35
|
end
|
50
36
|
|
51
37
|
def assert_called_on_instance_of(klass, method_name, message = nil, times: 1, returns: nil)
|
@@ -6,6 +6,8 @@ require "drb/unix" unless Gem.win_platform?
|
|
6
6
|
module ActiveSupport
|
7
7
|
module Testing
|
8
8
|
class Parallelization # :nodoc:
|
9
|
+
PrerecordResultClass = Struct.new(:name)
|
10
|
+
|
9
11
|
class Server
|
10
12
|
include DRb::DRbUndumped
|
11
13
|
|
@@ -21,6 +23,7 @@ module ActiveSupport
|
|
21
23
|
@in_flight.delete([result.klass, result.name])
|
22
24
|
|
23
25
|
reporter.synchronize do
|
26
|
+
reporter.prerecord(PrerecordResultClass.new(result.klass), result.name)
|
24
27
|
reporter.record(result)
|
25
28
|
end
|
26
29
|
end
|