activesupport 7.0.4 → 7.1.5.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 +1076 -230
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +3 -1
- data/lib/active_support/array_inquirer.rb +2 -0
- data/lib/active_support/backtrace_cleaner.rb +30 -5
- data/lib/active_support/benchmarkable.rb +1 -0
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +37 -10
- data/lib/active_support/cache/mem_cache_store.rb +100 -76
- data/lib/active_support/cache/memory_store.rb +78 -24
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +153 -141
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +333 -253
- data/lib/active_support/callbacks.rb +44 -21
- data/lib/active_support/code_generator.rb +15 -10
- data/lib/active_support/concern.rb +4 -2
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/configurable.rb +10 -0
- data/lib/active_support/core_ext/array/conversions.rb +2 -1
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +13 -10
- data/lib/active_support/core_ext/date/calculations.rb +15 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date.rb +0 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +1 -10
- data/lib/active_support/core_ext/enumerable.rb +8 -75
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +3 -3
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +81 -37
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
- data/lib/active_support/core_ext/object/duplicable.rb +25 -16
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +16 -6
- data/lib/active_support/core_ext/object/to_query.rb +0 -2
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +9 -9
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +2 -0
- data/lib/active_support/core_ext/pathname.rb +1 -0
- data/lib/active_support/core_ext/range/conversions.rb +28 -7
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +24 -12
- data/lib/active_support/core_ext/string/filters.rb +20 -14
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +16 -9
- data/lib/active_support/core_ext/string/output_safety.rb +42 -174
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +22 -2
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +7 -8
- data/lib/active_support/core_ext/time.rb +0 -1
- data/lib/active_support/current_attributes.rb +15 -6
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +6 -8
- data/lib/active_support/deprecation/instance_delegator.rb +31 -4
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
- data/lib/active_support/deprecation/reporting.rb +43 -26
- data/lib/active_support/deprecation.rb +32 -5
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +104 -132
- data/lib/active_support/duration/iso8601_serializer.rb +0 -2
- data/lib/active_support/duration.rb +2 -1
- data/lib/active_support/encrypted_configuration.rb +63 -11
- data/lib/active_support/encrypted_file.rb +16 -12
- data/lib/active_support/environment_inquirer.rb +22 -2
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +121 -35
- data/lib/active_support/evented_file_update_checker.rb +17 -2
- data/lib/active_support/execution_wrapper.rb +4 -4
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +10 -2
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +35 -17
- data/lib/active_support/html_safe_translation.rb +16 -6
- data/lib/active_support/i18n.rb +1 -1
- data/lib/active_support/i18n_railtie.rb +20 -13
- data/lib/active_support/inflector/inflections.rb +2 -0
- data/lib/active_support/inflector/methods.rb +28 -18
- data/lib/active_support/inflector/transliterate.rb +3 -1
- data/lib/active_support/isolated_execution_state.rb +26 -22
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +25 -43
- data/lib/active_support/key_generator.rb +9 -1
- data/lib/active_support/lazy_load_hooks.rb +7 -5
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber.rb +85 -33
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_thread_safe_level.rb +10 -24
- data/lib/active_support/message_encryptor.rb +197 -53
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +212 -93
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +111 -45
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +2 -0
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +245 -81
- data/lib/active_support/notifications/instrumenter.rb +87 -22
- data/lib/active_support/notifications.rb +3 -3
- data/lib/active_support/number_helper/number_converter.rb +14 -5
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
- data/lib/active_support/number_helper.rb +379 -317
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +14 -0
- data/lib/active_support/parameter_filter.rb +103 -84
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/railtie.rb +33 -21
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +2 -0
- data/lib/active_support/secure_compare_rotator.rb +16 -9
- data/lib/active_support/string_inquirer.rb +3 -1
- data/lib/active_support/subscriber.rb +9 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -24
- data/lib/active_support/test_case.rb +153 -6
- data/lib/active_support/testing/assertions.rb +26 -10
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +25 -25
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +29 -28
- data/lib/active_support/testing/method_call_assertions.rb +21 -8
- data/lib/active_support/testing/parallelize_executor.rb +8 -3
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/time_helpers.rb +37 -15
- data/lib/active_support/time_with_zone.rb +8 -37
- data/lib/active_support/values/time_zone.rb +18 -7
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -10
- data/lib/active_support/xml_mini/nokogiri.rb +1 -1
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +2 -2
- data/lib/active_support.rb +14 -3
- metadata +148 -19
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/uri.rb +0 -5
- data/lib/active_support/per_thread_registry.rb +0 -65
@@ -17,6 +17,33 @@ module ActiveSupport
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
module FanoutIteration # :nodoc:
|
21
|
+
private
|
22
|
+
def iterate_guarding_exceptions(collection)
|
23
|
+
exceptions = nil
|
24
|
+
|
25
|
+
collection.each do |s|
|
26
|
+
yield s
|
27
|
+
rescue Exception => e
|
28
|
+
exceptions ||= []
|
29
|
+
exceptions << e
|
30
|
+
end
|
31
|
+
|
32
|
+
if exceptions
|
33
|
+
exceptions = exceptions.flat_map do |exception|
|
34
|
+
exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception]
|
35
|
+
end
|
36
|
+
if exceptions.size == 1
|
37
|
+
raise exceptions.first
|
38
|
+
else
|
39
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
collection
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
20
47
|
# This is a default queue implementation that ships with Notifications.
|
21
48
|
# It just pushes events to all registered log subscribers.
|
22
49
|
#
|
@@ -25,22 +52,29 @@ module ActiveSupport
|
|
25
52
|
include Mutex_m
|
26
53
|
|
27
54
|
def initialize
|
28
|
-
@string_subscribers =
|
55
|
+
@string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
|
29
56
|
@other_subscribers = []
|
30
|
-
@
|
57
|
+
@all_listeners_for = Concurrent::Map.new
|
58
|
+
@groups_for = Concurrent::Map.new
|
59
|
+
@silenceable_groups_for = Concurrent::Map.new
|
31
60
|
super
|
32
61
|
end
|
33
62
|
|
63
|
+
def inspect # :nodoc:
|
64
|
+
total_patterns = @string_subscribers.size + @other_subscribers.size
|
65
|
+
"#<#{self.class} (#{total_patterns} patterns)>"
|
66
|
+
end
|
67
|
+
|
34
68
|
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
35
69
|
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
36
70
|
synchronize do
|
37
71
|
case pattern
|
38
72
|
when String
|
39
73
|
@string_subscribers[pattern] << subscriber
|
40
|
-
|
74
|
+
clear_cache(pattern)
|
41
75
|
when NilClass, Regexp
|
42
76
|
@other_subscribers << subscriber
|
43
|
-
|
77
|
+
clear_cache
|
44
78
|
else
|
45
79
|
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
46
80
|
end
|
@@ -53,69 +87,232 @@ module ActiveSupport
|
|
53
87
|
case subscriber_or_name
|
54
88
|
when String
|
55
89
|
@string_subscribers[subscriber_or_name].clear
|
56
|
-
|
90
|
+
clear_cache(subscriber_or_name)
|
57
91
|
@other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
|
58
92
|
else
|
59
93
|
pattern = subscriber_or_name.try(:pattern)
|
60
94
|
if String === pattern
|
61
95
|
@string_subscribers[pattern].delete(subscriber_or_name)
|
62
|
-
|
96
|
+
clear_cache(pattern)
|
63
97
|
else
|
64
98
|
@other_subscribers.delete(subscriber_or_name)
|
65
|
-
|
99
|
+
clear_cache
|
66
100
|
end
|
67
101
|
end
|
68
102
|
end
|
69
103
|
end
|
70
104
|
|
71
|
-
def
|
72
|
-
|
105
|
+
def clear_cache(key = nil) # :nodoc:
|
106
|
+
if key
|
107
|
+
@all_listeners_for.delete(key)
|
108
|
+
@groups_for.delete(key)
|
109
|
+
@silenceable_groups_for.delete(key)
|
110
|
+
else
|
111
|
+
@all_listeners_for.clear
|
112
|
+
@groups_for.clear
|
113
|
+
@silenceable_groups_for.clear
|
114
|
+
end
|
73
115
|
end
|
74
116
|
|
75
|
-
|
76
|
-
|
117
|
+
class BaseGroup # :nodoc:
|
118
|
+
include FanoutIteration
|
119
|
+
|
120
|
+
def initialize(listeners, name, id, payload)
|
121
|
+
@listeners = listeners
|
122
|
+
end
|
123
|
+
|
124
|
+
def each(&block)
|
125
|
+
iterate_guarding_exceptions(@listeners, &block)
|
126
|
+
end
|
77
127
|
end
|
78
128
|
|
79
|
-
|
80
|
-
|
129
|
+
class BaseTimeGroup < BaseGroup # :nodoc:
|
130
|
+
def start(name, id, payload)
|
131
|
+
@start_time = now
|
132
|
+
end
|
133
|
+
|
134
|
+
def finish(name, id, payload)
|
135
|
+
stop_time = now
|
136
|
+
each do |listener|
|
137
|
+
listener.call(name, @start_time, stop_time, id, payload)
|
138
|
+
end
|
139
|
+
end
|
81
140
|
end
|
82
141
|
|
83
|
-
|
84
|
-
|
142
|
+
class MonotonicTimedGroup < BaseTimeGroup # :nodoc:
|
143
|
+
private
|
144
|
+
def now
|
145
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
146
|
+
end
|
85
147
|
end
|
86
148
|
|
87
|
-
|
88
|
-
|
149
|
+
class TimedGroup < BaseTimeGroup # :nodoc:
|
150
|
+
private
|
151
|
+
def now
|
152
|
+
Time.now
|
153
|
+
end
|
154
|
+
end
|
89
155
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
156
|
+
class EventedGroup < BaseGroup # :nodoc:
|
157
|
+
def start(name, id, payload)
|
158
|
+
each do |s|
|
159
|
+
s.start(name, id, payload)
|
160
|
+
end
|
95
161
|
end
|
96
162
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
else
|
101
|
-
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
163
|
+
def finish(name, id, payload)
|
164
|
+
each do |s|
|
165
|
+
s.finish(name, id, payload)
|
102
166
|
end
|
103
167
|
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class EventObjectGroup < BaseGroup # :nodoc:
|
171
|
+
def start(name, id, payload)
|
172
|
+
@event = build_event(name, id, payload)
|
173
|
+
@event.start!
|
174
|
+
end
|
104
175
|
|
105
|
-
|
176
|
+
def finish(name, id, payload)
|
177
|
+
@event.payload = payload
|
178
|
+
@event.finish!
|
179
|
+
|
180
|
+
each do |s|
|
181
|
+
s.call(@event)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
def build_event(name, id, payload)
|
187
|
+
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
188
|
+
end
|
106
189
|
end
|
107
190
|
|
108
|
-
def
|
191
|
+
def groups_for(name) # :nodoc:
|
192
|
+
groups = @groups_for.compute_if_absent(name) do
|
193
|
+
all_listeners_for(name).reject(&:silenceable).group_by(&:group_class).transform_values do |s|
|
194
|
+
s.map(&:delegate)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
silenceable_groups = @silenceable_groups_for.compute_if_absent(name) do
|
199
|
+
all_listeners_for(name).select(&:silenceable).group_by(&:group_class).transform_values do |s|
|
200
|
+
s.map(&:delegate)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
unless silenceable_groups.empty?
|
205
|
+
groups = groups.dup
|
206
|
+
silenceable_groups.each do |group_class, subscriptions|
|
207
|
+
active_subscriptions = subscriptions.reject { |s| s.silenced?(name) }
|
208
|
+
unless active_subscriptions.empty?
|
209
|
+
groups[group_class] = (groups[group_class] || []) + active_subscriptions
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
groups
|
215
|
+
end
|
216
|
+
|
217
|
+
# A +Handle+ is used to record the start and finish time of event.
|
218
|
+
#
|
219
|
+
# Both #start and #finish must each be called exactly once.
|
220
|
+
#
|
221
|
+
# Where possible, it's best to use the block form: ActiveSupport::Notifications.instrument.
|
222
|
+
# +Handle+ is a low-level API intended for cases where the block form can't be used.
|
223
|
+
#
|
224
|
+
# handle = ActiveSupport::Notifications.instrumenter.build_handle("my.event", {})
|
225
|
+
# begin
|
226
|
+
# handle.start
|
227
|
+
# # work to be instrumented
|
228
|
+
# ensure
|
229
|
+
# handle.finish
|
230
|
+
# end
|
231
|
+
class Handle
|
232
|
+
include FanoutIteration
|
233
|
+
|
234
|
+
def initialize(notifier, name, id, payload) # :nodoc:
|
235
|
+
@name = name
|
236
|
+
@id = id
|
237
|
+
@payload = payload
|
238
|
+
@groups = notifier.groups_for(name).map do |group_klass, grouped_listeners|
|
239
|
+
group_klass.new(grouped_listeners, name, id, payload)
|
240
|
+
end
|
241
|
+
@state = :initialized
|
242
|
+
end
|
243
|
+
|
244
|
+
def start
|
245
|
+
ensure_state! :initialized
|
246
|
+
@state = :started
|
247
|
+
|
248
|
+
iterate_guarding_exceptions(@groups) do |group|
|
249
|
+
group.start(@name, @id, @payload)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def finish
|
254
|
+
finish_with_values(@name, @id, @payload)
|
255
|
+
end
|
256
|
+
|
257
|
+
def finish_with_values(name, id, payload) # :nodoc:
|
258
|
+
ensure_state! :started
|
259
|
+
@state = :finished
|
260
|
+
|
261
|
+
iterate_guarding_exceptions(@groups) do |group|
|
262
|
+
group.finish(name, id, payload)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
private
|
267
|
+
def ensure_state!(expected)
|
268
|
+
if @state != expected
|
269
|
+
raise ArgumentError, "expected state to be #{expected.inspect} but was #{@state.inspect}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
include FanoutIteration
|
275
|
+
|
276
|
+
def build_handle(name, id, payload)
|
277
|
+
Handle.new(self, name, id, payload)
|
278
|
+
end
|
279
|
+
|
280
|
+
def start(name, id, payload)
|
281
|
+
handle_stack = (IsolatedExecutionState[:_fanout_handle_stack] ||= [])
|
282
|
+
handle = build_handle(name, id, payload)
|
283
|
+
handle_stack << handle
|
284
|
+
handle.start
|
285
|
+
end
|
286
|
+
|
287
|
+
def finish(name, id, payload, listeners = nil)
|
288
|
+
handle_stack = IsolatedExecutionState[:_fanout_handle_stack]
|
289
|
+
handle = handle_stack.pop
|
290
|
+
handle.finish_with_values(name, id, payload)
|
291
|
+
end
|
292
|
+
|
293
|
+
def publish(name, *args)
|
294
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
|
295
|
+
end
|
296
|
+
|
297
|
+
def publish_event(event)
|
298
|
+
iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
|
299
|
+
end
|
300
|
+
|
301
|
+
def all_listeners_for(name)
|
109
302
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
110
|
-
@
|
303
|
+
@all_listeners_for[name] || synchronize do
|
111
304
|
# use synchronisation when accessing @subscribers
|
112
|
-
@
|
305
|
+
@all_listeners_for[name] ||=
|
113
306
|
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
114
307
|
end
|
115
308
|
end
|
116
309
|
|
310
|
+
def listeners_for(name)
|
311
|
+
all_listeners_for(name).reject { |s| s.silenced?(name) }
|
312
|
+
end
|
313
|
+
|
117
314
|
def listening?(name)
|
118
|
-
|
315
|
+
all_listeners_for(name).any? { |s| !s.silenced?(name) }
|
119
316
|
end
|
120
317
|
|
121
318
|
# This is a sync queue, so there is no waiting.
|
@@ -180,15 +377,20 @@ module ActiveSupport
|
|
180
377
|
end
|
181
378
|
|
182
379
|
class Evented # :nodoc:
|
183
|
-
attr_reader :pattern
|
380
|
+
attr_reader :pattern, :delegate, :silenceable
|
184
381
|
|
185
382
|
def initialize(pattern, delegate)
|
186
383
|
@pattern = Matcher.wrap(pattern)
|
187
384
|
@delegate = delegate
|
385
|
+
@silenceable = delegate.respond_to?(:silenced?)
|
188
386
|
@can_publish = delegate.respond_to?(:publish)
|
189
387
|
@can_publish_event = delegate.respond_to?(:publish_event)
|
190
388
|
end
|
191
389
|
|
390
|
+
def group_class
|
391
|
+
EventedGroup
|
392
|
+
end
|
393
|
+
|
192
394
|
def publish(name, *args)
|
193
395
|
if @can_publish
|
194
396
|
@delegate.publish name, *args
|
@@ -203,12 +405,8 @@ module ActiveSupport
|
|
203
405
|
end
|
204
406
|
end
|
205
407
|
|
206
|
-
def
|
207
|
-
@delegate.
|
208
|
-
end
|
209
|
-
|
210
|
-
def finish(name, id, payload)
|
211
|
-
@delegate.finish name, id, payload
|
408
|
+
def silenced?(name)
|
409
|
+
@silenceable && @delegate.silenced?(name)
|
212
410
|
end
|
213
411
|
|
214
412
|
def subscribed_to?(name)
|
@@ -221,63 +419,29 @@ module ActiveSupport
|
|
221
419
|
end
|
222
420
|
|
223
421
|
class Timed < Evented # :nodoc:
|
224
|
-
def
|
225
|
-
|
226
|
-
end
|
227
|
-
|
228
|
-
def start(name, id, payload)
|
229
|
-
timestack = IsolatedExecutionState[:_timestack] ||= []
|
230
|
-
timestack.push Time.now
|
422
|
+
def group_class
|
423
|
+
TimedGroup
|
231
424
|
end
|
232
425
|
|
233
|
-
def finish(name, id, payload)
|
234
|
-
timestack = IsolatedExecutionState[:_timestack]
|
235
|
-
started = timestack.pop
|
236
|
-
@delegate.call(name, started, Time.now, id, payload)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
class MonotonicTimed < Evented # :nodoc:
|
241
426
|
def publish(name, *args)
|
242
427
|
@delegate.call name, *args
|
243
428
|
end
|
429
|
+
end
|
244
430
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
end
|
249
|
-
|
250
|
-
def finish(name, id, payload)
|
251
|
-
timestack = IsolatedExecutionState[:_timestack_monotonic]
|
252
|
-
started = timestack.pop
|
253
|
-
@delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
|
431
|
+
class MonotonicTimed < Timed # :nodoc:
|
432
|
+
def group_class
|
433
|
+
MonotonicTimedGroup
|
254
434
|
end
|
255
435
|
end
|
256
436
|
|
257
437
|
class EventObject < Evented
|
258
|
-
def
|
259
|
-
|
260
|
-
event = build_event name, id, payload
|
261
|
-
event.start!
|
262
|
-
stack.push event
|
263
|
-
end
|
264
|
-
|
265
|
-
def finish(name, id, payload)
|
266
|
-
stack = IsolatedExecutionState[:_event_stack]
|
267
|
-
event = stack.pop
|
268
|
-
event.payload = payload
|
269
|
-
event.finish!
|
270
|
-
@delegate.call event
|
438
|
+
def group_class
|
439
|
+
EventObjectGroup
|
271
440
|
end
|
272
441
|
|
273
442
|
def publish_event(event)
|
274
443
|
@delegate.call event
|
275
444
|
end
|
276
|
-
|
277
|
-
private
|
278
|
-
def build_event(name, id, payload)
|
279
|
-
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
280
|
-
end
|
281
445
|
end
|
282
446
|
end
|
283
447
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/module/delegation"
|
3
4
|
require "securerandom"
|
4
5
|
|
5
6
|
module ActiveSupport
|
@@ -9,17 +10,50 @@ module ActiveSupport
|
|
9
10
|
attr_reader :id
|
10
11
|
|
11
12
|
def initialize(notifier)
|
13
|
+
unless notifier.respond_to?(:build_handle)
|
14
|
+
notifier = LegacyHandle::Wrapper.new(notifier)
|
15
|
+
end
|
16
|
+
|
12
17
|
@id = unique_id
|
13
18
|
@notifier = notifier
|
14
19
|
end
|
15
20
|
|
21
|
+
class LegacyHandle # :nodoc:
|
22
|
+
class Wrapper # :nodoc:
|
23
|
+
def initialize(notifier)
|
24
|
+
@notifier = notifier
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_handle(name, id, payload)
|
28
|
+
LegacyHandle.new(@notifier, name, id, payload)
|
29
|
+
end
|
30
|
+
|
31
|
+
delegate :start, :finish, to: :@notifier
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(notifier, name, id, payload)
|
35
|
+
@notifier = notifier
|
36
|
+
@name = name
|
37
|
+
@id = id
|
38
|
+
@payload = payload
|
39
|
+
end
|
40
|
+
|
41
|
+
def start
|
42
|
+
@listener_state = @notifier.start @name, @id, @payload
|
43
|
+
end
|
44
|
+
|
45
|
+
def finish
|
46
|
+
@notifier.finish(@name, @id, @payload, @listener_state)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
16
50
|
# Given a block, instrument it by measuring the time taken to execute
|
17
51
|
# and publish it. Without a block, simply send a message via the
|
18
52
|
# notifier. Notice that events get sent even if an error occurs in the
|
19
53
|
# passed-in block.
|
20
54
|
def instrument(name, payload = {})
|
21
|
-
|
22
|
-
|
55
|
+
handle = build_handle(name, payload)
|
56
|
+
handle.start
|
23
57
|
begin
|
24
58
|
yield payload if block_given?
|
25
59
|
rescue Exception => e
|
@@ -27,10 +61,24 @@ module ActiveSupport
|
|
27
61
|
payload[:exception_object] = e
|
28
62
|
raise e
|
29
63
|
ensure
|
30
|
-
|
64
|
+
handle.finish
|
31
65
|
end
|
32
66
|
end
|
33
67
|
|
68
|
+
# Returns a "handle" for an event with the given +name+ and +payload+.
|
69
|
+
#
|
70
|
+
# #start and #finish must each be called exactly once on the returned object.
|
71
|
+
#
|
72
|
+
# Where possible, it's best to use #instrument, which will record the
|
73
|
+
# start and finish of the event and correctly handle any exceptions.
|
74
|
+
# +build_handle+ is a low-level API intended for cases where using
|
75
|
+
# +instrument+ isn't possible.
|
76
|
+
#
|
77
|
+
# See ActiveSupport::Notifications::Fanout::Handle.
|
78
|
+
def build_handle(name, payload)
|
79
|
+
@notifier.build_handle(name, @id, payload)
|
80
|
+
end
|
81
|
+
|
34
82
|
def new_event(name, payload = {}) # :nodoc:
|
35
83
|
Event.new(name, nil, nil, @id, payload)
|
36
84
|
end
|
@@ -56,7 +104,7 @@ module ActiveSupport
|
|
56
104
|
end
|
57
105
|
|
58
106
|
class Event
|
59
|
-
attr_reader :name, :
|
107
|
+
attr_reader :name, :transaction_id
|
60
108
|
attr_accessor :payload
|
61
109
|
|
62
110
|
def initialize(name, start, ending, transaction_id, payload)
|
@@ -65,14 +113,21 @@ module ActiveSupport
|
|
65
113
|
@time = start ? start.to_f * 1_000.0 : start
|
66
114
|
@transaction_id = transaction_id
|
67
115
|
@end = ending ? ending.to_f * 1_000.0 : ending
|
68
|
-
@children = []
|
69
116
|
@cpu_time_start = 0.0
|
70
117
|
@cpu_time_finish = 0.0
|
71
118
|
@allocation_count_start = 0
|
72
119
|
@allocation_count_finish = 0
|
73
120
|
end
|
74
121
|
|
75
|
-
def
|
122
|
+
def time
|
123
|
+
@time / 1000.0 if @time
|
124
|
+
end
|
125
|
+
|
126
|
+
def end
|
127
|
+
@end / 1000.0 if @end
|
128
|
+
end
|
129
|
+
|
130
|
+
def record # :nodoc:
|
76
131
|
start!
|
77
132
|
begin
|
78
133
|
yield payload if block_given?
|
@@ -99,24 +154,42 @@ module ActiveSupport
|
|
99
154
|
@allocation_count_finish = now_allocations
|
100
155
|
end
|
101
156
|
|
102
|
-
# Returns the CPU time (in milliseconds) passed
|
103
|
-
#
|
157
|
+
# Returns the CPU time (in milliseconds) passed between the call to
|
158
|
+
# #start! and the call to #finish!.
|
104
159
|
def cpu_time
|
105
160
|
@cpu_time_finish - @cpu_time_start
|
106
161
|
end
|
107
162
|
|
108
|
-
# Returns the idle time time (in milliseconds) passed
|
109
|
-
#
|
163
|
+
# Returns the idle time time (in milliseconds) passed between the call to
|
164
|
+
# #start! and the call to #finish!.
|
110
165
|
def idle_time
|
111
|
-
duration - cpu_time
|
166
|
+
diff = duration - cpu_time
|
167
|
+
diff > 0.0 ? diff : 0.0
|
112
168
|
end
|
113
169
|
|
114
|
-
# Returns the number of allocations made
|
115
|
-
# the call to
|
170
|
+
# Returns the number of allocations made between the call to #start! and
|
171
|
+
# the call to #finish!.
|
116
172
|
def allocations
|
117
173
|
@allocation_count_finish - @allocation_count_start
|
118
174
|
end
|
119
175
|
|
176
|
+
def children # :nodoc:
|
177
|
+
ActiveSupport.deprecator.warn <<~EOM
|
178
|
+
ActiveSupport::Notifications::Event#children is deprecated and will
|
179
|
+
be removed in Rails 7.2.
|
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)
|
191
|
+
end
|
192
|
+
|
120
193
|
# Returns the difference in milliseconds between when the execution of the
|
121
194
|
# event started and when it ended.
|
122
195
|
#
|
@@ -130,15 +203,7 @@ module ActiveSupport
|
|
130
203
|
#
|
131
204
|
# @event.duration # => 1000.138
|
132
205
|
def duration
|
133
|
-
|
134
|
-
end
|
135
|
-
|
136
|
-
def <<(event)
|
137
|
-
@children << event
|
138
|
-
end
|
139
|
-
|
140
|
-
def parent_of?(event)
|
141
|
-
@children.include? event
|
206
|
+
@end - @time
|
142
207
|
end
|
143
208
|
|
144
209
|
private
|
@@ -6,7 +6,7 @@ require "active_support/notifications/fanout"
|
|
6
6
|
module ActiveSupport
|
7
7
|
# = \Notifications
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# +ActiveSupport::Notifications+ provides an instrumentation API for
|
10
10
|
# Ruby.
|
11
11
|
#
|
12
12
|
# == Instrumenters
|
@@ -237,8 +237,8 @@ module ActiveSupport
|
|
237
237
|
#
|
238
238
|
# Raises an error if invalid event name type is passed:
|
239
239
|
#
|
240
|
-
#
|
241
|
-
#
|
240
|
+
# ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
|
241
|
+
# #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
|
242
242
|
#
|
243
243
|
def subscribe(pattern = nil, callback = nil, &block)
|
244
244
|
notifier.subscribe(pattern, callback, monotonic: false, &block)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bigdecimal"
|
4
|
+
require "bigdecimal/util"
|
3
5
|
require "active_support/core_ext/big_decimal/conversions"
|
4
|
-
require "active_support/core_ext/object/blank"
|
5
6
|
require "active_support/core_ext/hash/keys"
|
6
7
|
require "active_support/i18n"
|
7
8
|
require "active_support/core_ext/class/attribute"
|
@@ -122,13 +123,14 @@ module ActiveSupport
|
|
122
123
|
|
123
124
|
def initialize(number, options)
|
124
125
|
@number = number
|
125
|
-
@opts
|
126
|
+
@opts = options.symbolize_keys
|
127
|
+
@options = nil
|
126
128
|
end
|
127
129
|
|
128
130
|
def execute
|
129
131
|
if !number
|
130
132
|
nil
|
131
|
-
elsif validate_float? && !
|
133
|
+
elsif validate_float? && !valid_bigdecimal
|
132
134
|
number
|
133
135
|
else
|
134
136
|
convert
|
@@ -173,8 +175,15 @@ module ActiveSupport
|
|
173
175
|
key.split(".").reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
|
174
176
|
end
|
175
177
|
|
176
|
-
def
|
177
|
-
|
178
|
+
def valid_bigdecimal
|
179
|
+
case number
|
180
|
+
when Float, Rational
|
181
|
+
number.to_d(0)
|
182
|
+
when String
|
183
|
+
BigDecimal(number, exception: false)
|
184
|
+
else
|
185
|
+
number.to_d rescue nil
|
186
|
+
end
|
178
187
|
end
|
179
188
|
end
|
180
189
|
end
|