activesupport 7.1.6 → 8.1.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 +256 -1133
- data/README.rdoc +1 -1
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +81 -3
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +65 -78
- data/lib/active_support/cache/file_store.rb +29 -14
- data/lib/active_support/cache/mem_cache_store.rb +42 -102
- data/lib/active_support/cache/memory_store.rb +11 -6
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +58 -46
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache/strategy/local_cache.rb +72 -27
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +146 -86
- data/lib/active_support/callbacks.rb +102 -126
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -5
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +4 -14
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +26 -19
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/class.rb +2 -2
- 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.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -9
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +10 -5
- data/lib/active_support/core_ext/file.rb +1 -1
- 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/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -163
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +24 -11
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +4 -4
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +4 -4
- 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 +4 -4
- data/lib/active_support/core_ext/string/multibyte.rb +13 -4
- data/lib/active_support/core_ext/string/output_safety.rb +19 -19
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +25 -30
- data/lib/active_support/core_ext/time/compatibility.rb +2 -3
- 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/time.rb +5 -5
- data/lib/active_support/core_ext.rb +1 -2
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +58 -50
- data/lib/active_support/delegation.rb +200 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -2
- 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 +5 -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/editor.rb +70 -0
- 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 +121 -6
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -3
- data/lib/active_support/execution_context.rb +64 -7
- data/lib/active_support/execution_wrapper.rb +1 -2
- data/lib/active_support/file_update_checker.rb +9 -7
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +66 -45
- data/lib/active_support/html_safe_translation.rb +3 -0
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +31 -15
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +12 -17
- data/lib/active_support/json/decoding.rb +6 -4
- data/lib/active_support/json/encoding.rb +157 -21
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +2 -18
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +4 -9
- data/lib/active_support/message_encryptors.rb +54 -2
- data/lib/active_support/message_pack/extensions.rb +20 -2
- data/lib/active_support/message_verifier.rb +21 -0
- data/lib/active_support/message_verifiers.rb +57 -3
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +10 -0
- data/lib/active_support/multibyte/chars.rb +14 -4
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +68 -50
- data/lib/active_support/notifications/instrumenter.rb +22 -19
- 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 +36 -20
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +1 -5
- data/lib/active_support/syntax_error_proxy.rb +3 -0
- data/lib/active_support/tagged_logging.rb +5 -1
- data/lib/active_support/test_case.rb +63 -6
- data/lib/active_support/testing/assertions.rb +113 -27
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- 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/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +18 -2
- data/lib/active_support/testing/parallelization/worker.rb +4 -2
- data/lib/active_support/testing/parallelization.rb +25 -1
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +11 -6
- data/lib/active_support/time_with_zone.rb +39 -26
- data/lib/active_support/values/time_zone.rb +26 -17
- data/lib/active_support/xml_mini.rb +14 -4
- data/lib/active_support.rb +22 -9
- metadata +31 -17
- data/lib/active_support/core_ext/range/each.rb +0 -24
- 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
- data/lib/active_support/testing/strict_warnings.rb +0 -39
|
@@ -26,10 +26,13 @@ module ActiveSupport
|
|
|
26
26
|
# as the first rotation and <tt>transitional = true</tt>. Then, after all
|
|
27
27
|
# servers have been updated, perform a second rolling deploy with
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
|
+
#
|
|
30
|
+
#--
|
|
31
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#transitional
|
|
29
32
|
|
|
30
33
|
##
|
|
31
|
-
# :method:
|
|
32
|
-
# :call-seq:
|
|
34
|
+
# :singleton-method: new
|
|
35
|
+
# :call-seq: new(&secret_generator)
|
|
33
36
|
#
|
|
34
37
|
# Initializes a new instance. +secret_generator+ must accept a salt, and
|
|
35
38
|
# return a suitable secret (string). +secret_generator+ may also accept
|
|
@@ -42,6 +45,9 @@ module ActiveSupport
|
|
|
42
45
|
# end
|
|
43
46
|
#
|
|
44
47
|
# verifiers.rotate(base: "...")
|
|
48
|
+
#
|
|
49
|
+
#--
|
|
50
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#initialize
|
|
45
51
|
|
|
46
52
|
##
|
|
47
53
|
# :method: []
|
|
@@ -50,16 +56,24 @@ module ActiveSupport
|
|
|
50
56
|
# Returns a MessageVerifier configured with a secret derived from the
|
|
51
57
|
# given +salt+, and options from #rotate. MessageVerifier instances will
|
|
52
58
|
# be memoized, so the same +salt+ will return the same instance.
|
|
59
|
+
#
|
|
60
|
+
#--
|
|
61
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#[]
|
|
53
62
|
|
|
54
63
|
##
|
|
55
64
|
# :method: []=
|
|
56
65
|
# :call-seq: []=(salt, verifier)
|
|
57
66
|
#
|
|
58
67
|
# Overrides a MessageVerifier instance associated with a given +salt+.
|
|
68
|
+
#
|
|
69
|
+
#--
|
|
70
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#[]=
|
|
59
71
|
|
|
60
72
|
##
|
|
61
73
|
# :method: rotate
|
|
62
|
-
# :call-seq:
|
|
74
|
+
# :call-seq:
|
|
75
|
+
# rotate(**options)
|
|
76
|
+
# rotate(&block)
|
|
63
77
|
#
|
|
64
78
|
# Adds +options+ to the list of option sets. Messages will be signed using
|
|
65
79
|
# the first set in the list. When verifying, however, each set will be
|
|
@@ -102,18 +116,55 @@ module ActiveSupport
|
|
|
102
116
|
#
|
|
103
117
|
# # Uses `serializer: Marshal, url_safe: false`.
|
|
104
118
|
# verifiers[:baz]
|
|
119
|
+
#
|
|
120
|
+
#--
|
|
121
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#rotate
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# :method: prepend
|
|
125
|
+
# :call-seq:
|
|
126
|
+
# prepend(**options)
|
|
127
|
+
# prepend(&block)
|
|
128
|
+
#
|
|
129
|
+
# Just like #rotate, but prepends the given options or block to the list of
|
|
130
|
+
# option sets.
|
|
131
|
+
#
|
|
132
|
+
# This can be useful when you have an already-configured +MessageVerifiers+
|
|
133
|
+
# instance, but you want to override the way messages are signed.
|
|
134
|
+
#
|
|
135
|
+
# module ThirdParty
|
|
136
|
+
# VERIFIERS = ActiveSupport::MessageVerifiers.new { ... }.
|
|
137
|
+
# rotate(serializer: Marshal, url_safe: true).
|
|
138
|
+
# rotate(serializer: Marshal, url_safe: false)
|
|
139
|
+
# end
|
|
140
|
+
#
|
|
141
|
+
# ThirdParty.VERIFIERS.prepend(serializer: JSON, url_safe: true)
|
|
142
|
+
#
|
|
143
|
+
# # Uses `serializer: JSON, url_safe: true`.
|
|
144
|
+
# # Falls back to `serializer: Marshal, url_safe: true` or
|
|
145
|
+
# # `serializer: Marshal, url_safe: false`.
|
|
146
|
+
# ThirdParty.VERIFIERS[:foo]
|
|
147
|
+
#
|
|
148
|
+
#--
|
|
149
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#prepend
|
|
105
150
|
|
|
106
151
|
##
|
|
107
152
|
# :method: rotate_defaults
|
|
108
153
|
# :call-seq: rotate_defaults
|
|
109
154
|
#
|
|
110
155
|
# Invokes #rotate with the default options.
|
|
156
|
+
#
|
|
157
|
+
#--
|
|
158
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#rotate_defaults
|
|
111
159
|
|
|
112
160
|
##
|
|
113
161
|
# :method: clear_rotations
|
|
114
162
|
# :call-seq: clear_rotations
|
|
115
163
|
#
|
|
116
164
|
# Clears the list of option sets.
|
|
165
|
+
#
|
|
166
|
+
#--
|
|
167
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#clear_rotations
|
|
117
168
|
|
|
118
169
|
##
|
|
119
170
|
# :method: on_rotation
|
|
@@ -125,6 +176,9 @@ module ActiveSupport
|
|
|
125
176
|
# For example, this callback could log each time it is called, and thus
|
|
126
177
|
# indicate whether old option sets are still in use or can be removed from
|
|
127
178
|
# rotation.
|
|
179
|
+
#
|
|
180
|
+
#--
|
|
181
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#on_rotation
|
|
128
182
|
|
|
129
183
|
##
|
|
130
184
|
private
|
|
@@ -32,6 +32,15 @@ module ActiveSupport
|
|
|
32
32
|
self
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def prepend(**options, &block)
|
|
36
|
+
raise ArgumentError, "Options cannot be specified when using a block" if block && !options.empty?
|
|
37
|
+
changing_configuration!
|
|
38
|
+
|
|
39
|
+
@rotate_options.unshift(block || options)
|
|
40
|
+
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
35
44
|
def rotate_defaults
|
|
36
45
|
rotate()
|
|
37
46
|
end
|
|
@@ -15,6 +15,11 @@ module ActiveSupport
|
|
|
15
15
|
fall_back_to build_rotation(*args, **options)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def on_rotation(&on_rotation)
|
|
19
|
+
@on_rotation = on_rotation
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
18
23
|
def fall_back_to(fallback)
|
|
19
24
|
@rotations << fallback
|
|
20
25
|
self
|
|
@@ -40,6 +45,11 @@ module ActiveSupport
|
|
|
40
45
|
end
|
|
41
46
|
end
|
|
42
47
|
|
|
48
|
+
def initialize_dup(*)
|
|
49
|
+
super
|
|
50
|
+
@rotations = @rotations.dup
|
|
51
|
+
end
|
|
52
|
+
|
|
43
53
|
private
|
|
44
54
|
def build_rotation(*args, **options)
|
|
45
55
|
self.class.new(*args, *@args.drop(args.length), **@options, **options)
|
|
@@ -53,14 +53,24 @@ module ActiveSupport # :nodoc:
|
|
|
53
53
|
delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
|
|
54
54
|
|
|
55
55
|
# Creates a new Chars instance by wrapping _string_.
|
|
56
|
-
def initialize(string)
|
|
56
|
+
def initialize(string, deprecation: true)
|
|
57
|
+
if deprecation
|
|
58
|
+
ActiveSupport.deprecator.warn(
|
|
59
|
+
"ActiveSupport::Multibyte::Chars is deprecated and will be removed in Rails 8.2. " \
|
|
60
|
+
"Use normal string methods instead."
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
57
64
|
@wrapped_string = string
|
|
58
|
-
|
|
65
|
+
if string.encoding != Encoding::UTF_8
|
|
66
|
+
@wrapped_string = @wrapped_string.dup
|
|
67
|
+
@wrapped_string.force_encoding(Encoding::UTF_8)
|
|
68
|
+
end
|
|
59
69
|
end
|
|
60
70
|
|
|
61
71
|
# Forward all undefined methods to the wrapped string.
|
|
62
|
-
def method_missing(method,
|
|
63
|
-
result = @wrapped_string.__send__(method,
|
|
72
|
+
def method_missing(method, ...)
|
|
73
|
+
result = @wrapped_string.__send__(method, ...)
|
|
64
74
|
if method.end_with?("!")
|
|
65
75
|
self if result
|
|
66
76
|
else
|
|
@@ -12,6 +12,10 @@ module ActiveSupport # :nodoc:
|
|
|
12
12
|
#
|
|
13
13
|
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
|
|
14
14
|
def self.proxy_class=(klass)
|
|
15
|
+
ActiveSupport.deprecator.warn(
|
|
16
|
+
"ActiveSupport::Multibyte.proxy_class= is deprecated and will be removed in Rails 8.2. " \
|
|
17
|
+
"Use normal string methods instead."
|
|
18
|
+
)
|
|
15
19
|
@proxy_class = klass
|
|
16
20
|
end
|
|
17
21
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "mutex_m"
|
|
4
3
|
require "concurrent/map"
|
|
5
|
-
require "set"
|
|
6
4
|
require "active_support/core_ext/object/try"
|
|
7
5
|
|
|
8
6
|
module ActiveSupport
|
|
@@ -19,24 +17,30 @@ module ActiveSupport
|
|
|
19
17
|
|
|
20
18
|
module FanoutIteration # :nodoc:
|
|
21
19
|
private
|
|
22
|
-
def iterate_guarding_exceptions(collection)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
exceptions
|
|
29
|
-
exceptions << e
|
|
30
|
-
end
|
|
20
|
+
def iterate_guarding_exceptions(collection, &block)
|
|
21
|
+
case collection.size
|
|
22
|
+
when 0
|
|
23
|
+
when 1
|
|
24
|
+
collection.each(&block)
|
|
25
|
+
else
|
|
26
|
+
exceptions = nil
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
collection.each do |s|
|
|
29
|
+
yield s
|
|
30
|
+
rescue Exception => e
|
|
31
|
+
exceptions ||= []
|
|
32
|
+
exceptions << e
|
|
35
33
|
end
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
|
|
35
|
+
if exceptions
|
|
36
|
+
exceptions = exceptions.flat_map do |exception|
|
|
37
|
+
exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception]
|
|
38
|
+
end
|
|
39
|
+
if exceptions.size == 1
|
|
40
|
+
raise exceptions.first
|
|
41
|
+
else
|
|
42
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
|
43
|
+
end
|
|
40
44
|
end
|
|
41
45
|
end
|
|
42
46
|
|
|
@@ -49,15 +53,12 @@ module ActiveSupport
|
|
|
49
53
|
#
|
|
50
54
|
# This class is thread safe. All methods are reentrant.
|
|
51
55
|
class Fanout
|
|
52
|
-
include Mutex_m
|
|
53
|
-
|
|
54
56
|
def initialize
|
|
57
|
+
@mutex = Mutex.new
|
|
55
58
|
@string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
|
|
56
59
|
@other_subscribers = []
|
|
57
60
|
@all_listeners_for = Concurrent::Map.new
|
|
58
61
|
@groups_for = Concurrent::Map.new
|
|
59
|
-
@silenceable_groups_for = Concurrent::Map.new
|
|
60
|
-
super
|
|
61
62
|
end
|
|
62
63
|
|
|
63
64
|
def inspect # :nodoc:
|
|
@@ -67,7 +68,7 @@ module ActiveSupport
|
|
|
67
68
|
|
|
68
69
|
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
|
69
70
|
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
|
70
|
-
synchronize do
|
|
71
|
+
@mutex.synchronize do
|
|
71
72
|
case pattern
|
|
72
73
|
when String
|
|
73
74
|
@string_subscribers[pattern] << subscriber
|
|
@@ -83,7 +84,7 @@ module ActiveSupport
|
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
def unsubscribe(subscriber_or_name)
|
|
86
|
-
synchronize do
|
|
87
|
+
@mutex.synchronize do
|
|
87
88
|
case subscriber_or_name
|
|
88
89
|
when String
|
|
89
90
|
@string_subscribers[subscriber_or_name].clear
|
|
@@ -106,11 +107,9 @@ module ActiveSupport
|
|
|
106
107
|
if key
|
|
107
108
|
@all_listeners_for.delete(key)
|
|
108
109
|
@groups_for.delete(key)
|
|
109
|
-
@silenceable_groups_for.delete(key)
|
|
110
110
|
else
|
|
111
111
|
@all_listeners_for.clear
|
|
112
112
|
@groups_for.clear
|
|
113
|
-
@silenceable_groups_for.clear
|
|
114
113
|
end
|
|
115
114
|
end
|
|
116
115
|
|
|
@@ -188,25 +187,25 @@ module ActiveSupport
|
|
|
188
187
|
end
|
|
189
188
|
end
|
|
190
189
|
|
|
191
|
-
def
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
end
|
|
190
|
+
def group_listeners(listeners) # :nodoc:
|
|
191
|
+
listeners.group_by(&:group_class).transform_values do |s|
|
|
192
|
+
s.map(&:delegate).freeze
|
|
193
|
+
end.freeze
|
|
194
|
+
end
|
|
197
195
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
def groups_for(name) # :nodoc:
|
|
197
|
+
silenceable_groups, groups = @groups_for.compute_if_absent(name) do
|
|
198
|
+
listeners = all_listeners_for(name)
|
|
199
|
+
listeners.partition(&:silenceable).map { |l| group_listeners(l) }
|
|
202
200
|
end
|
|
203
201
|
|
|
204
202
|
unless silenceable_groups.empty?
|
|
205
|
-
groups = groups.dup
|
|
206
203
|
silenceable_groups.each do |group_class, subscriptions|
|
|
207
204
|
active_subscriptions = subscriptions.reject { |s| s.silenced?(name) }
|
|
208
205
|
unless active_subscriptions.empty?
|
|
209
|
-
groups
|
|
206
|
+
groups = groups.dup if groups.frozen?
|
|
207
|
+
base_groups = groups[group_class]
|
|
208
|
+
groups[group_class] = base_groups ? base_groups + active_subscriptions : active_subscriptions
|
|
210
209
|
end
|
|
211
210
|
end
|
|
212
211
|
end
|
|
@@ -231,13 +230,11 @@ module ActiveSupport
|
|
|
231
230
|
class Handle
|
|
232
231
|
include FanoutIteration
|
|
233
232
|
|
|
234
|
-
def initialize(notifier, name, id, payload) # :nodoc:
|
|
233
|
+
def initialize(notifier, name, id, groups, payload) # :nodoc:
|
|
235
234
|
@name = name
|
|
236
235
|
@id = id
|
|
237
236
|
@payload = payload
|
|
238
|
-
@groups =
|
|
239
|
-
group_klass.new(grouped_listeners, name, id, payload)
|
|
240
|
-
end
|
|
237
|
+
@groups = groups
|
|
241
238
|
@state = :initialized
|
|
242
239
|
end
|
|
243
240
|
|
|
@@ -271,10 +268,31 @@ module ActiveSupport
|
|
|
271
268
|
end
|
|
272
269
|
end
|
|
273
270
|
|
|
271
|
+
module NullHandle # :nodoc:
|
|
272
|
+
extend self
|
|
273
|
+
|
|
274
|
+
def start
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def finish
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def finish_with_values(_name, _id, _payload)
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
274
284
|
include FanoutIteration
|
|
275
285
|
|
|
276
286
|
def build_handle(name, id, payload)
|
|
277
|
-
|
|
287
|
+
groups = groups_for(name).map do |group_klass, grouped_listeners|
|
|
288
|
+
group_klass.new(grouped_listeners, name, id, payload)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
if groups.empty?
|
|
292
|
+
NullHandle
|
|
293
|
+
else
|
|
294
|
+
Handle.new(self, name, id, groups, payload)
|
|
295
|
+
end
|
|
278
296
|
end
|
|
279
297
|
|
|
280
298
|
def start(name, id, payload)
|
|
@@ -290,8 +308,8 @@ module ActiveSupport
|
|
|
290
308
|
handle.finish_with_values(name, id, payload)
|
|
291
309
|
end
|
|
292
310
|
|
|
293
|
-
def publish(name,
|
|
294
|
-
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name,
|
|
311
|
+
def publish(name, ...)
|
|
312
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, ...) }
|
|
295
313
|
end
|
|
296
314
|
|
|
297
315
|
def publish_event(event)
|
|
@@ -300,7 +318,7 @@ module ActiveSupport
|
|
|
300
318
|
|
|
301
319
|
def all_listeners_for(name)
|
|
302
320
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
|
303
|
-
@all_listeners_for[name] || synchronize do
|
|
321
|
+
@all_listeners_for[name] || @mutex.synchronize do
|
|
304
322
|
# use synchronisation when accessing @subscribers
|
|
305
323
|
@all_listeners_for[name] ||=
|
|
306
324
|
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
|
@@ -391,9 +409,9 @@ module ActiveSupport
|
|
|
391
409
|
EventedGroup
|
|
392
410
|
end
|
|
393
411
|
|
|
394
|
-
def publish(
|
|
412
|
+
def publish(...)
|
|
395
413
|
if @can_publish
|
|
396
|
-
@delegate.publish
|
|
414
|
+
@delegate.publish(...)
|
|
397
415
|
end
|
|
398
416
|
end
|
|
399
417
|
|
|
@@ -423,8 +441,8 @@ module ActiveSupport
|
|
|
423
441
|
TimedGroup
|
|
424
442
|
end
|
|
425
443
|
|
|
426
|
-
def publish(
|
|
427
|
-
@delegate.call
|
|
444
|
+
def publish(...)
|
|
445
|
+
@delegate.call(...)
|
|
428
446
|
end
|
|
429
447
|
end
|
|
430
448
|
|
|
@@ -117,6 +117,8 @@ module ActiveSupport
|
|
|
117
117
|
@cpu_time_finish = 0.0
|
|
118
118
|
@allocation_count_start = 0
|
|
119
119
|
@allocation_count_finish = 0
|
|
120
|
+
@gc_time_start = 0
|
|
121
|
+
@gc_time_finish = 0
|
|
120
122
|
end
|
|
121
123
|
|
|
122
124
|
def time
|
|
@@ -144,12 +146,14 @@ module ActiveSupport
|
|
|
144
146
|
def start!
|
|
145
147
|
@time = now
|
|
146
148
|
@cpu_time_start = now_cpu
|
|
149
|
+
@gc_time_start = now_gc
|
|
147
150
|
@allocation_count_start = now_allocations
|
|
148
151
|
end
|
|
149
152
|
|
|
150
153
|
# Record information at the time this event finishes
|
|
151
154
|
def finish!
|
|
152
155
|
@cpu_time_finish = now_cpu
|
|
156
|
+
@gc_time_finish = now_gc
|
|
153
157
|
@end = now
|
|
154
158
|
@allocation_count_finish = now_allocations
|
|
155
159
|
end
|
|
@@ -160,7 +164,7 @@ module ActiveSupport
|
|
|
160
164
|
@cpu_time_finish - @cpu_time_start
|
|
161
165
|
end
|
|
162
166
|
|
|
163
|
-
# Returns the idle time
|
|
167
|
+
# Returns the idle time (in milliseconds) passed between the call to
|
|
164
168
|
# #start! and the call to #finish!.
|
|
165
169
|
def idle_time
|
|
166
170
|
diff = duration - cpu_time
|
|
@@ -173,28 +177,17 @@ module ActiveSupport
|
|
|
173
177
|
@allocation_count_finish - @allocation_count_start
|
|
174
178
|
end
|
|
175
179
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
EOM
|
|
181
|
-
[]
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def parent_of?(event) # :nodoc:
|
|
185
|
-
ActiveSupport.deprecator.warn <<~EOM
|
|
186
|
-
ActiveSupport::Notifications::Event#parent_of? is deprecated and will
|
|
187
|
-
be removed in Rails 7.2.
|
|
188
|
-
EOM
|
|
189
|
-
start = (time - event.time) * 1000
|
|
190
|
-
start <= 0 && (start + duration >= event.duration)
|
|
180
|
+
# Returns the time spent in GC (in milliseconds) between the call to #start!
|
|
181
|
+
# and the call to #finish!
|
|
182
|
+
def gc_time
|
|
183
|
+
(@gc_time_finish - @gc_time_start) / 1_000_000.0
|
|
191
184
|
end
|
|
192
185
|
|
|
193
186
|
# Returns the difference in milliseconds between when the execution of the
|
|
194
187
|
# event started and when it ended.
|
|
195
188
|
#
|
|
196
|
-
# ActiveSupport::Notifications.subscribe('wait') do
|
|
197
|
-
# @event =
|
|
189
|
+
# ActiveSupport::Notifications.subscribe('wait') do |event|
|
|
190
|
+
# @event = event
|
|
198
191
|
# end
|
|
199
192
|
#
|
|
200
193
|
# ActiveSupport::Notifications.instrument('wait') do
|
|
@@ -218,11 +211,21 @@ module ActiveSupport
|
|
|
218
211
|
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
|
|
219
212
|
end
|
|
220
213
|
rescue
|
|
221
|
-
def now_cpu
|
|
214
|
+
def now_cpu
|
|
222
215
|
0.0
|
|
223
216
|
end
|
|
224
217
|
end
|
|
225
218
|
|
|
219
|
+
if GC.respond_to?(:total_time)
|
|
220
|
+
def now_gc
|
|
221
|
+
GC.total_time
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
def now_gc
|
|
225
|
+
0
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
226
229
|
if GC.stat.key?(:total_allocated_objects)
|
|
227
230
|
def now_allocations
|
|
228
231
|
GC.stat(:total_allocated_objects)
|
|
@@ -29,6 +29,16 @@ module ActiveSupport
|
|
|
29
29
|
# You can consume those events and the information they provide by registering
|
|
30
30
|
# a subscriber.
|
|
31
31
|
#
|
|
32
|
+
# ActiveSupport::Notifications.subscribe('render') do |event|
|
|
33
|
+
# event.name # => "render"
|
|
34
|
+
# event.duration # => 10 (in milliseconds)
|
|
35
|
+
# event.payload # => { extra: :information }
|
|
36
|
+
# event.allocations # => 1826 (objects)
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
# +Event+ objects record CPU time and allocations. If you don't need this
|
|
40
|
+
# it's also possible to pass a block that accepts five arguments:
|
|
41
|
+
#
|
|
32
42
|
# ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
|
|
33
43
|
# name # => String, name of the event (such as 'render' from above)
|
|
34
44
|
# start # => Time, when the instrumented block started execution
|
|
@@ -42,20 +52,18 @@ module ActiveSupport
|
|
|
42
52
|
#
|
|
43
53
|
# ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
|
|
44
54
|
# name # => String, name of the event (such as 'render' from above)
|
|
45
|
-
# start # =>
|
|
46
|
-
# finish # =>
|
|
55
|
+
# start # => Float, monotonic time when the instrumented block started execution
|
|
56
|
+
# finish # => Float, monotonic time when the instrumented block ended execution
|
|
47
57
|
# id # => String, unique ID for the instrumenter that fired the event
|
|
48
58
|
# payload # => Hash, the payload
|
|
49
59
|
# end
|
|
50
60
|
#
|
|
51
|
-
# The +start+ and +finish+ values above represent monotonic time.
|
|
52
|
-
#
|
|
53
61
|
# For instance, let's store all "render" events in an array:
|
|
54
62
|
#
|
|
55
63
|
# events = []
|
|
56
64
|
#
|
|
57
|
-
# ActiveSupport::Notifications.subscribe('render') do
|
|
58
|
-
# events <<
|
|
65
|
+
# ActiveSupport::Notifications.subscribe('render') do |event|
|
|
66
|
+
# events << event
|
|
59
67
|
# end
|
|
60
68
|
#
|
|
61
69
|
# That code returns right away, you are just subscribing to "render" events.
|
|
@@ -66,14 +74,10 @@ module ActiveSupport
|
|
|
66
74
|
# end
|
|
67
75
|
#
|
|
68
76
|
# event = events.first
|
|
69
|
-
# event.name
|
|
70
|
-
# event.duration
|
|
71
|
-
# event.payload
|
|
72
|
-
#
|
|
73
|
-
# The block in the <tt>subscribe</tt> call gets the name of the event, start
|
|
74
|
-
# timestamp, end timestamp, a string with a unique identifier for that event's instrumenter
|
|
75
|
-
# (something like "535801666f04d0298cd6"), and a hash with the payload, in
|
|
76
|
-
# that order.
|
|
77
|
+
# event.name # => "render"
|
|
78
|
+
# event.duration # => 10 (in milliseconds)
|
|
79
|
+
# event.payload # => { extra: :information }
|
|
80
|
+
# event.allocations # => 1826 (objects)
|
|
77
81
|
#
|
|
78
82
|
# If an exception happens during that particular instrumentation the payload will
|
|
79
83
|
# have a key <tt>:exception</tt> with an array of two elements as value: a string with
|
|
@@ -138,7 +142,7 @@ module ActiveSupport
|
|
|
138
142
|
# You can subscribe to some event temporarily while some block runs. For
|
|
139
143
|
# example, in
|
|
140
144
|
#
|
|
141
|
-
# callback = lambda {
|
|
145
|
+
# callback = lambda {|event| ... }
|
|
142
146
|
# ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
|
|
143
147
|
# ...
|
|
144
148
|
# end
|
|
@@ -161,7 +165,7 @@ module ActiveSupport
|
|
|
161
165
|
#
|
|
162
166
|
# The +subscribe+ method returns a subscriber object:
|
|
163
167
|
#
|
|
164
|
-
# subscriber = ActiveSupport::Notifications.subscribe("render") do
|
|
168
|
+
# subscriber = ActiveSupport::Notifications.subscribe("render") do |event|
|
|
165
169
|
# ...
|
|
166
170
|
# end
|
|
167
171
|
#
|
|
@@ -214,11 +218,15 @@ module ActiveSupport
|
|
|
214
218
|
# You can subscribe to events by passing a String to match exact event
|
|
215
219
|
# names, or by passing a Regexp to match all events that match a pattern.
|
|
216
220
|
#
|
|
217
|
-
#
|
|
218
|
-
#
|
|
221
|
+
# If the block passed to the method only takes one argument,
|
|
222
|
+
# it will yield an +Event+ object to the block:
|
|
223
|
+
#
|
|
224
|
+
# ActiveSupport::Notifications.subscribe(/render/) do |event|
|
|
225
|
+
# @event = event
|
|
219
226
|
# end
|
|
220
227
|
#
|
|
221
|
-
#
|
|
228
|
+
# Otherwise the +block+ will receive five arguments with information
|
|
229
|
+
# about the event:
|
|
222
230
|
#
|
|
223
231
|
# ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
|
|
224
232
|
# name # => String, name of the event (such as 'render' from above)
|
|
@@ -228,16 +236,9 @@ module ActiveSupport
|
|
|
228
236
|
# payload # => Hash, the payload
|
|
229
237
|
# end
|
|
230
238
|
#
|
|
231
|
-
# If the block passed to the method only takes one parameter,
|
|
232
|
-
# it will yield an event object to the block:
|
|
233
|
-
#
|
|
234
|
-
# ActiveSupport::Notifications.subscribe(/render/) do |event|
|
|
235
|
-
# @event = event
|
|
236
|
-
# end
|
|
237
|
-
#
|
|
238
239
|
# Raises an error if invalid event name type is passed:
|
|
239
240
|
#
|
|
240
|
-
# ActiveSupport::Notifications.subscribe(:render) {
|
|
241
|
+
# ActiveSupport::Notifications.subscribe(:render) {|event| ...}
|
|
241
242
|
# #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
|
|
242
243
|
#
|
|
243
244
|
def subscribe(pattern = nil, callback = nil, &block)
|
|
@@ -164,11 +164,11 @@ module ActiveSupport
|
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
def translate_number_value_with_default(key, **i18n_options)
|
|
167
|
-
I18n.translate(key,
|
|
167
|
+
I18n.translate(key, default: default_value(key), scope: :number, **i18n_options)
|
|
168
168
|
end
|
|
169
169
|
|
|
170
170
|
def translate_in_locale(key, **i18n_options)
|
|
171
|
-
translate_number_value_with_default(key,
|
|
171
|
+
translate_number_value_with_default(key, locale: options[:locale], **i18n_options)
|
|
172
172
|
end
|
|
173
173
|
|
|
174
174
|
def default_value(key)
|
|
@@ -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
|
|