activesupport 7.1.3.2 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -1126
- 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
|