activesupport 7.2.2.1 → 8.0.5
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 +277 -151
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +61 -74
- data/lib/active_support/cache/file_store.rb +14 -4
- data/lib/active_support/cache/mem_cache_store.rb +17 -16
- data/lib/active_support/cache/memory_store.rb +9 -5
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +7 -4
- data/lib/active_support/cache/strategy/local_cache.rb +56 -20
- data/lib/active_support/cache.rb +19 -14
- data/lib/active_support/callbacks.rb +8 -5
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- 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 -3
- data/lib/active_support/core_ext/benchmark.rb +7 -9
- data/lib/active_support/core_ext/class/attribute.rb +26 -20
- data/lib/active_support/core_ext/date/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +2 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/module/attr_internal.rb +3 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/object/json.rb +16 -10
- data/lib/active_support/core_ext/object/to_query.rb +2 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +1 -0
- data/lib/active_support/core_ext/securerandom.rb +24 -8
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +3 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +14 -2
- data/lib/active_support/core_ext/time/compatibility.rb +9 -1
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/current_attributes.rb +14 -7
- data/lib/active_support/delegation.rb +25 -44
- data/lib/active_support/dependencies.rb +0 -1
- data/lib/active_support/deprecation/reporting.rb +0 -19
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration.rb +14 -10
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/error_reporter.rb +36 -3
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +1 -1
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +34 -31
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +2 -1
- data/lib/active_support/inflector/methods.rb +3 -3
- data/lib/active_support/isolated_execution_state.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -2
- data/lib/active_support/json/encoding.rb +25 -7
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- data/lib/active_support/message_encryptors.rb +2 -2
- data/lib/active_support/message_pack/extensions.rb +1 -1
- data/lib/active_support/message_verifier.rb +9 -0
- data/lib/active_support/message_verifiers.rb +5 -3
- data/lib/active_support/messages/rotator.rb +5 -0
- data/lib/active_support/multibyte/chars.rb +4 -1
- data/lib/active_support/notifications/fanout.rb +0 -1
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/railtie.rb +6 -0
- data/lib/active_support/tagged_logging.rb +5 -0
- data/lib/active_support/test_case.rb +6 -0
- data/lib/active_support/testing/assertions.rb +84 -21
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/parallelization/server.rb +15 -2
- data/lib/active_support/testing/parallelization/worker.rb +7 -3
- data/lib/active_support/testing/parallelization.rb +12 -1
- data/lib/active_support/testing/time_helpers.rb +2 -1
- data/lib/active_support/time_with_zone.rb +22 -13
- data/lib/active_support/values/time_zone.rb +11 -9
- data/lib/active_support/xml_mini.rb +2 -0
- data/lib/active_support.rb +10 -3
- metadata +24 -12
- data/lib/active_support/proxy_object.rb +0 -20
- data/lib/active_support/testing/strict_warnings.rb +0 -43
|
@@ -13,12 +13,30 @@ module ActiveSupport
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
module JSON
|
|
16
|
-
# Dumps objects in JSON (JavaScript Object Notation).
|
|
17
|
-
# See http://www.json.org for more info.
|
|
18
|
-
#
|
|
19
|
-
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
20
|
-
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
21
16
|
class << self
|
|
17
|
+
# Dumps objects in JSON (JavaScript Object Notation).
|
|
18
|
+
# See http://www.json.org for more info.
|
|
19
|
+
#
|
|
20
|
+
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
21
|
+
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
22
|
+
#
|
|
23
|
+
# Generates JSON that is safe to include in JavaScript as it escapes
|
|
24
|
+
# U+2028 (Line Separator) and U+2029 (Paragraph Separator):
|
|
25
|
+
#
|
|
26
|
+
# ActiveSupport::JSON.encode({ key: "\u2028" })
|
|
27
|
+
# # => "{\"key\":\"\\u2028\"}"
|
|
28
|
+
#
|
|
29
|
+
# By default, it also generates JSON that is safe to include in HTML, as
|
|
30
|
+
# it escapes <tt><</tt>, <tt>></tt>, and <tt>&</tt>:
|
|
31
|
+
#
|
|
32
|
+
# ActiveSupport::JSON.encode({ key: "<>&" })
|
|
33
|
+
# # => "{\"key\":\"\\u003c\\u003e\\u0026\"}"
|
|
34
|
+
#
|
|
35
|
+
# This can be changed with the +escape_html_entities+ option, or the
|
|
36
|
+
# global escape_html_entities_in_json configuration option.
|
|
37
|
+
#
|
|
38
|
+
# ActiveSupport::JSON.encode({ key: "<>&" }, escape_html_entities: false)
|
|
39
|
+
# # => "{\"key\":\"<>&\"}"
|
|
22
40
|
def encode(value, options = nil)
|
|
23
41
|
Encoding.json_encoder.new(options).encode(value)
|
|
24
42
|
end
|
|
@@ -36,14 +54,14 @@ module ActiveSupport
|
|
|
36
54
|
# Encode the given object into a JSON string
|
|
37
55
|
def encode(value)
|
|
38
56
|
unless options.empty?
|
|
39
|
-
value = value.as_json(options.dup)
|
|
57
|
+
value = value.as_json(options.dup.freeze)
|
|
40
58
|
end
|
|
41
59
|
json = stringify(jsonify(value))
|
|
42
60
|
|
|
43
61
|
# Rails does more escaping than the JSON gem natively does (we
|
|
44
62
|
# escape \u2028 and \u2029 and optionally >, <, & to work around
|
|
45
63
|
# certain browser problems).
|
|
46
|
-
if Encoding.escape_html_entities_in_json
|
|
64
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
|
47
65
|
json.gsub!(">", '\u003e')
|
|
48
66
|
json.gsub!("<", '\u003c')
|
|
49
67
|
json.gsub!("&", '\u0026')
|
|
@@ -53,7 +53,7 @@ module ActiveSupport
|
|
|
53
53
|
# loaded. If the component has already loaded, the block is executed
|
|
54
54
|
# immediately.
|
|
55
55
|
#
|
|
56
|
-
# Options
|
|
56
|
+
# ==== Options
|
|
57
57
|
#
|
|
58
58
|
# * <tt>:yield</tt> - Yields the object that run_load_hooks to +block+.
|
|
59
59
|
# * <tt>:run_once</tt> - Given +block+ will run only once.
|
|
@@ -7,6 +7,11 @@ module ActiveSupport
|
|
|
7
7
|
module LoggerThreadSafeLevel # :nodoc:
|
|
8
8
|
extend ActiveSupport::Concern
|
|
9
9
|
|
|
10
|
+
def initialize(...)
|
|
11
|
+
super
|
|
12
|
+
@local_level_key = :"logger_thread_safe_level_#{object_id}"
|
|
13
|
+
end
|
|
14
|
+
|
|
10
15
|
def local_level
|
|
11
16
|
IsolatedExecutionState[local_level_key]
|
|
12
17
|
end
|
|
@@ -40,8 +45,6 @@ module ActiveSupport
|
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
private
|
|
43
|
-
|
|
44
|
-
@local_level_key ||= :"logger_thread_safe_level_#{object_id}"
|
|
45
|
-
end
|
|
48
|
+
attr_reader :local_level_key
|
|
46
49
|
end
|
|
47
50
|
end
|
|
@@ -28,8 +28,8 @@ module ActiveSupport
|
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
29
|
|
|
30
30
|
##
|
|
31
|
-
# :method:
|
|
32
|
-
# :call-seq:
|
|
31
|
+
# :singleton-method: new
|
|
32
|
+
# :call-seq: new(&secret_generator)
|
|
33
33
|
#
|
|
34
34
|
# Initializes a new instance. +secret_generator+ must accept a salt and a
|
|
35
35
|
# +secret_length+ kwarg, and return a suitable secret (string) or secrets
|
|
@@ -154,6 +154,8 @@ module ActiveSupport
|
|
|
154
154
|
# not URL-safe. In other words, they can contain "+" and "/". If you want to
|
|
155
155
|
# generate URL-safe strings (in compliance with "Base 64 Encoding with URL
|
|
156
156
|
# and Filename Safe Alphabet" in RFC 4648), you can pass +true+.
|
|
157
|
+
# Note that MessageVerifier will always accept both URL-safe and URL-unsafe
|
|
158
|
+
# encoded messages, to allow a smooth transition between the two settings.
|
|
157
159
|
#
|
|
158
160
|
# [+:force_legacy_metadata_serializer+]
|
|
159
161
|
# Whether to use the legacy metadata serializer, which serializes the
|
|
@@ -318,6 +320,13 @@ module ActiveSupport
|
|
|
318
320
|
end
|
|
319
321
|
|
|
320
322
|
private
|
|
323
|
+
def decode(encoded, url_safe: @url_safe)
|
|
324
|
+
catch :invalid_message_format do
|
|
325
|
+
return super
|
|
326
|
+
end
|
|
327
|
+
super(encoded, url_safe: !url_safe)
|
|
328
|
+
end
|
|
329
|
+
|
|
321
330
|
def sign_encoded(encoded)
|
|
322
331
|
digest = generate_digest(encoded)
|
|
323
332
|
encoded << SEPARATOR << digest
|
|
@@ -28,8 +28,8 @@ module ActiveSupport
|
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
29
|
|
|
30
30
|
##
|
|
31
|
-
# :method:
|
|
32
|
-
# :call-seq:
|
|
31
|
+
# :singleton-method: new
|
|
32
|
+
# :call-seq: new(&secret_generator)
|
|
33
33
|
#
|
|
34
34
|
# Initializes a new instance. +secret_generator+ must accept a salt, and
|
|
35
35
|
# return a suitable secret (string). +secret_generator+ may also accept
|
|
@@ -59,7 +59,9 @@ module ActiveSupport
|
|
|
59
59
|
|
|
60
60
|
##
|
|
61
61
|
# :method: rotate
|
|
62
|
-
# :call-seq:
|
|
62
|
+
# :call-seq:
|
|
63
|
+
# rotate(**options)
|
|
64
|
+
# rotate(&block)
|
|
63
65
|
#
|
|
64
66
|
# Adds +options+ to the list of option sets. Messages will be signed using
|
|
65
67
|
# the first set in the list. When verifying, however, each set will be
|
|
@@ -55,7 +55,10 @@ module ActiveSupport # :nodoc:
|
|
|
55
55
|
# Creates a new Chars instance by wrapping _string_.
|
|
56
56
|
def initialize(string)
|
|
57
57
|
@wrapped_string = string
|
|
58
|
-
|
|
58
|
+
if string.encoding != Encoding::UTF_8
|
|
59
|
+
@wrapped_string = @wrapped_string.dup
|
|
60
|
+
@wrapped_string.force_encoding(Encoding::UTF_8)
|
|
61
|
+
end
|
|
59
62
|
end
|
|
60
63
|
|
|
61
64
|
# Forward all undefined methods to the wrapped string.
|
|
@@ -164,7 +164,7 @@ module ActiveSupport
|
|
|
164
164
|
@cpu_time_finish - @cpu_time_start
|
|
165
165
|
end
|
|
166
166
|
|
|
167
|
-
# Returns the idle time
|
|
167
|
+
# Returns the idle time (in milliseconds) passed between the call to
|
|
168
168
|
# #start! and the call to #finish!.
|
|
169
169
|
def idle_time
|
|
170
170
|
diff = duration - cpu_time
|
|
@@ -16,9 +16,24 @@ module ActiveSupport
|
|
|
16
16
|
private
|
|
17
17
|
def parts
|
|
18
18
|
left, right = number.to_s.split(".")
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
if delimiter_pattern
|
|
20
|
+
left.gsub!(delimiter_pattern) do |digit_to_delimit|
|
|
21
|
+
"#{digit_to_delimit}#{options[:delimiter]}"
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
left_parts = []
|
|
25
|
+
offset = left.size % 3
|
|
26
|
+
if offset > 0
|
|
27
|
+
left_parts << left[0, offset]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
(left.size / 3).times do |i|
|
|
31
|
+
left_parts << left[offset + (i * 3), 3]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
left = left_parts.join(options[:delimiter])
|
|
21
35
|
end
|
|
36
|
+
|
|
22
37
|
[left, right].compact
|
|
23
38
|
end
|
|
24
39
|
|
|
@@ -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
|
|
|
@@ -96,6 +96,12 @@ module ActiveSupport
|
|
|
96
96
|
config.eager_load_namespaces << TZInfo
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
initializer "active_support.to_time_preserves_timezone" do |app|
|
|
100
|
+
config.after_initialize do
|
|
101
|
+
ActiveSupport.to_time_preserves_timezone = app.config.active_support.to_time_preserves_timezone
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
99
105
|
# Sets the default week start
|
|
100
106
|
# If assigned value is not a valid day symbol (e.g. :sunday, :monday, ...), an exception will be raised.
|
|
101
107
|
initializer "active_support.initialize_beginning_of_week" do |app|
|
|
@@ -113,6 +113,11 @@ module ActiveSupport
|
|
|
113
113
|
end
|
|
114
114
|
end
|
|
115
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
|
+
|
|
116
121
|
def self.new(logger)
|
|
117
122
|
logger = logger.clone
|
|
118
123
|
|
|
@@ -45,6 +45,12 @@ module ActiveSupport
|
|
|
45
45
|
ActiveSupport.test_order ||= :random
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
if Minitest.respond_to? :run_order # MT6 API change
|
|
49
|
+
def run_order # :nodoc:
|
|
50
|
+
test_order
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
48
54
|
# Parallelizes the test suite.
|
|
49
55
|
#
|
|
50
56
|
# Takes a +workers+ argument that controls how many times the process
|
|
@@ -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,14 @@ 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 = "#{error}\n#{diff before_value + diff, actual}" if Minitest::VERSION > "6"
|
|
125
|
+
error = "#{message}.\n#{error}" if message
|
|
126
|
+
error
|
|
127
|
+
end
|
|
128
|
+
assert_equal(before_value + diff, actual, rich_message)
|
|
124
129
|
end
|
|
125
130
|
|
|
126
131
|
retval
|
|
@@ -195,22 +200,32 @@ module ActiveSupport
|
|
|
195
200
|
retval = _assert_nothing_raised_or_warn("assert_changes", &block)
|
|
196
201
|
|
|
197
202
|
unless from == UNTRACKED
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
rich_message = -> do
|
|
204
|
+
error = "Expected change from #{from.inspect}, got #{before.inspect}"
|
|
205
|
+
error = "#{message}.\n#{error}" if message
|
|
206
|
+
error
|
|
207
|
+
end
|
|
208
|
+
assert from === before, rich_message
|
|
201
209
|
end
|
|
202
210
|
|
|
203
211
|
after = exp.call
|
|
204
212
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
213
|
+
rich_message = -> do
|
|
214
|
+
code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
|
|
215
|
+
error = "`#{code_string}` didn't change"
|
|
216
|
+
error = "#{error}. It was already #{to.inspect}." if before == to
|
|
217
|
+
error = "#{message}.\n#{error}" if message
|
|
218
|
+
error
|
|
219
|
+
end
|
|
220
|
+
refute_equal before, after, rich_message
|
|
209
221
|
|
|
210
222
|
unless to == UNTRACKED
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
223
|
+
rich_message = -> do
|
|
224
|
+
error = "Expected change to #{to.inspect}, got #{after.inspect}\n"
|
|
225
|
+
error = "#{message}.\n#{error}" if message
|
|
226
|
+
error
|
|
227
|
+
end
|
|
228
|
+
assert to === after, rich_message
|
|
214
229
|
end
|
|
215
230
|
|
|
216
231
|
retval
|
|
@@ -242,20 +257,28 @@ module ActiveSupport
|
|
|
242
257
|
retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
|
|
243
258
|
|
|
244
259
|
unless from == UNTRACKED
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
260
|
+
rich_message = -> do
|
|
261
|
+
error = "Expected initial value of #{from.inspect}, got #{before.inspect}"
|
|
262
|
+
error = "#{message}.\n#{error}" if message
|
|
263
|
+
error
|
|
264
|
+
end
|
|
265
|
+
assert from === before, rich_message
|
|
248
266
|
end
|
|
249
267
|
|
|
250
268
|
after = exp.call
|
|
251
269
|
|
|
252
|
-
|
|
253
|
-
|
|
270
|
+
rich_message = -> do
|
|
271
|
+
code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
|
|
272
|
+
error = "`#{code_string}` changed."
|
|
273
|
+
error = "#{message}.\n#{error}" if message
|
|
274
|
+
error = "#{error}\n#{diff before, after}" if Minitest::VERSION > "6"
|
|
275
|
+
error
|
|
276
|
+
end
|
|
254
277
|
|
|
255
278
|
if before.nil?
|
|
256
|
-
assert_nil after,
|
|
279
|
+
assert_nil after, rich_message
|
|
257
280
|
else
|
|
258
|
-
assert_equal before, after,
|
|
281
|
+
assert_equal before, after, rich_message
|
|
259
282
|
end
|
|
260
283
|
|
|
261
284
|
retval
|
|
@@ -276,6 +299,46 @@ module ActiveSupport
|
|
|
276
299
|
|
|
277
300
|
raise
|
|
278
301
|
end
|
|
302
|
+
|
|
303
|
+
def _callable_to_source_string(callable)
|
|
304
|
+
if defined?(RubyVM::InstructionSequence) && callable.is_a?(Proc)
|
|
305
|
+
iseq = RubyVM::InstructionSequence.of(callable)
|
|
306
|
+
source =
|
|
307
|
+
if iseq.script_lines
|
|
308
|
+
iseq.script_lines.join("\n")
|
|
309
|
+
elsif File.readable?(iseq.absolute_path)
|
|
310
|
+
File.read(iseq.absolute_path)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
return callable unless source
|
|
314
|
+
|
|
315
|
+
location = iseq.to_a[4][:code_location]
|
|
316
|
+
return callable unless location
|
|
317
|
+
|
|
318
|
+
lines = source.lines[(location[0] - 1)..(location[2] - 1)]
|
|
319
|
+
lines[-1] = lines[-1].byteslice(...location[3])
|
|
320
|
+
lines[0] = lines[0].byteslice(location[1]...)
|
|
321
|
+
source = lines.join.strip
|
|
322
|
+
|
|
323
|
+
# Strip stabby lambda from Ruby 4.1+
|
|
324
|
+
source = source.sub(/^->\s*/, "")
|
|
325
|
+
|
|
326
|
+
# We ignore procs defined with do/end as they are likely multi-line anyway.
|
|
327
|
+
if source.start_with?("{")
|
|
328
|
+
source.delete_suffix!("}")
|
|
329
|
+
source.delete_prefix!("{")
|
|
330
|
+
source.strip!
|
|
331
|
+
# It won't read nice if the callable contains multiple
|
|
332
|
+
# lines, and it should be a rare occurrence anyway.
|
|
333
|
+
# Same if it takes arguments.
|
|
334
|
+
if !source.include?("\n") && !source.start_with?("|")
|
|
335
|
+
return source
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
callable
|
|
341
|
+
end
|
|
279
342
|
end
|
|
280
343
|
end
|
|
281
344
|
end
|
|
@@ -2,4 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
require "minitest"
|
|
4
4
|
|
|
5
|
+
# This respond_to check handles tests running sub-processes in an
|
|
6
|
+
# unbundled environment, which triggers MT5 usage. This conditional may
|
|
7
|
+
# be removable after the version bump, though it currently safeguards
|
|
8
|
+
# against issues in environments with multiple versions installed.
|
|
9
|
+
Minitest.load :rails if Minitest.respond_to? :load
|
|
5
10
|
Minitest.autorun
|
|
@@ -14,6 +14,7 @@ module ActiveSupport
|
|
|
14
14
|
def initialize
|
|
15
15
|
@queue = Queue.new
|
|
16
16
|
@active_workers = Concurrent::Map.new
|
|
17
|
+
@worker_pids = Concurrent::Map.new
|
|
17
18
|
@in_flight = Concurrent::Map.new
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -40,12 +41,24 @@ module ActiveSupport
|
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
def start_worker(worker_id)
|
|
44
|
+
def start_worker(worker_id, worker_pid)
|
|
44
45
|
@active_workers[worker_id] = true
|
|
46
|
+
@worker_pids[worker_id] = worker_pid
|
|
45
47
|
end
|
|
46
48
|
|
|
47
|
-
def stop_worker(worker_id)
|
|
49
|
+
def stop_worker(worker_id, worker_pid)
|
|
48
50
|
@active_workers.delete(worker_id)
|
|
51
|
+
@worker_pids.delete(worker_id)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def remove_dead_workers(dead_pids)
|
|
55
|
+
dead_pids.each do |dead_pid|
|
|
56
|
+
worker_id = @worker_pids.key(dead_pid)
|
|
57
|
+
if worker_id
|
|
58
|
+
@active_workers.delete(worker_id)
|
|
59
|
+
@worker_pids.delete(worker_id)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
49
62
|
end
|
|
50
63
|
|
|
51
64
|
def active_workers?
|
|
@@ -18,7 +18,7 @@ module ActiveSupport
|
|
|
18
18
|
DRb.stop_service
|
|
19
19
|
|
|
20
20
|
@queue = DRbObject.new_with_uri(@url)
|
|
21
|
-
@queue.start_worker(@id)
|
|
21
|
+
@queue.start_worker(@id, Process.pid)
|
|
22
22
|
|
|
23
23
|
begin
|
|
24
24
|
after_fork
|
|
@@ -29,7 +29,7 @@ module ActiveSupport
|
|
|
29
29
|
set_process_title("(stopping)")
|
|
30
30
|
|
|
31
31
|
run_cleanup
|
|
32
|
-
@queue.stop_worker(@id)
|
|
32
|
+
@queue.stop_worker(@id, Process.pid)
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
@@ -47,7 +47,11 @@ module ActiveSupport
|
|
|
47
47
|
set_process_title("#{klass}##{method}")
|
|
48
48
|
|
|
49
49
|
result = klass.with_info_handler reporter do
|
|
50
|
-
Minitest.run_one_method
|
|
50
|
+
if Minitest.respond_to? :run_one_method
|
|
51
|
+
Minitest.run_one_method klass, method
|
|
52
|
+
else
|
|
53
|
+
klass.new(method).run
|
|
54
|
+
end
|
|
51
55
|
end
|
|
52
56
|
|
|
53
57
|
safe_record(reporter, result)
|
|
@@ -47,8 +47,19 @@ module ActiveSupport
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def shutdown
|
|
50
|
+
dead_worker_pids = @worker_pool.filter_map do |pid|
|
|
51
|
+
Process.waitpid(pid, Process::WNOHANG)
|
|
52
|
+
rescue Errno::ECHILD
|
|
53
|
+
pid
|
|
54
|
+
end
|
|
55
|
+
@queue_server.remove_dead_workers(dead_worker_pids)
|
|
56
|
+
|
|
50
57
|
@queue_server.shutdown
|
|
51
|
-
@worker_pool.each
|
|
58
|
+
@worker_pool.each do |pid|
|
|
59
|
+
Process.waitpid(pid)
|
|
60
|
+
rescue Errno::ECHILD
|
|
61
|
+
nil
|
|
62
|
+
end
|
|
52
63
|
end
|
|
53
64
|
end
|
|
54
65
|
end
|
|
@@ -166,9 +166,10 @@ module ActiveSupport
|
|
|
166
166
|
else
|
|
167
167
|
now = date_or_time
|
|
168
168
|
now = now.to_time unless now.is_a?(Time)
|
|
169
|
-
now = now.change(usec: 0) unless with_usec
|
|
170
169
|
end
|
|
171
170
|
|
|
171
|
+
now = now.change(usec: 0) unless with_usec
|
|
172
|
+
|
|
172
173
|
# +now+ must be in local system timezone, because +Time.at(now)+
|
|
173
174
|
# and +now.to_date+ (see stubs below) will use +now+'s timezone too!
|
|
174
175
|
now = now.getlocal
|