activesupport 5.2.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +362 -333
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +29 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +33 -33
- data/lib/active_support/cache/mem_cache_store.rb +31 -29
- data/lib/active_support/cache/memory_store.rb +59 -33
- data/lib/active_support/cache/null_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +84 -45
- data/lib/active_support/cache/strategy/local_cache.rb +41 -26
- data/lib/active_support/cache.rb +174 -113
- data/lib/active_support/callbacks.rb +81 -64
- data/lib/active_support/concern.rb +76 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configurable.rb +10 -14
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/array/conversions.rb +5 -5
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +32 -47
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +171 -70
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/keys.rb +1 -30
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +76 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +1 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +7 -114
- data/lib/active_support/core_ext/object/json.rb +7 -2
- data/lib/active_support/core_ext/object/to_query.rb +5 -2
- data/lib/active_support/core_ext/object/try.rb +17 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +82 -0
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/each.rb +0 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +45 -6
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +69 -12
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +50 -3
- data/lib/active_support/core_ext/time/conversions.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +7 -5
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +15 -2
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +118 -35
- data/lib/active_support/deprecation/behaviors.rb +20 -3
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +21 -13
- data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
- data/lib/active_support/deprecation/reporting.rb +51 -8
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +59 -9
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +18 -14
- data/lib/active_support/duration.rb +90 -38
- data/lib/active_support/encrypted_configuration.rb +1 -5
- data/lib/active_support/encrypted_file.rb +23 -5
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +82 -117
- data/lib/active_support/execution_wrapper.rb +1 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +78 -41
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +16 -5
- data/lib/active_support/inflector/inflections.rb +2 -7
- data/lib/active_support/inflector/methods.rb +50 -57
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +11 -3
- data/lib/active_support/key_generator.rb +1 -33
- data/lib/active_support/lazy_load_hooks.rb +5 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +39 -9
- data/lib/active_support/logger.rb +2 -17
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +52 -7
- data/lib/active_support/message_encryptor.rb +8 -13
- data/lib/active_support/message_verifier.rb +10 -10
- data/lib/active_support/messages/metadata.rb +11 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +10 -68
- data/lib/active_support/multibyte/unicode.rb +15 -327
- data/lib/active_support/notifications/fanout.rb +116 -16
- data/lib/active_support/notifications/instrumenter.rb +71 -9
- data/lib/active_support/notifications.rb +72 -8
- data/lib/active_support/number_helper/number_converter.rb +5 -6
- data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/number_helper.rb +38 -12
- data/lib/active_support/option_merger.rb +22 -3
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +13 -3
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/reloader.rb +4 -5
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -3
- data/lib/active_support/subscriber.rb +72 -24
- data/lib/active_support/tagged_logging.rb +42 -8
- data/lib/active_support/test_case.rb +92 -1
- data/lib/active_support/testing/assertions.rb +30 -9
- data/lib/active_support/testing/deprecation.rb +0 -1
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +28 -1
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/setup_and_teardown.rb +5 -9
- data/lib/active_support/testing/stream.rb +1 -2
- data/lib/active_support/testing/time_helpers.rb +47 -12
- data/lib/active_support/time_with_zone.rb +81 -47
- data/lib/active_support/values/time_zone.rb +34 -18
- data/lib/active_support/xml_mini/jdom.rb +2 -3
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
- data/lib/active_support/xml_mini/rexml.rb +10 -3
- data/lib/active_support/xml_mini.rb +2 -10
- data/lib/active_support.rb +14 -1
- metadata +57 -30
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -25
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require "mutex_m"
|
4
4
|
require "concurrent/map"
|
5
|
+
require "set"
|
6
|
+
require "active_support/core_ext/object/try"
|
5
7
|
|
6
8
|
module ActiveSupport
|
7
9
|
module Notifications
|
@@ -13,16 +15,22 @@ module ActiveSupport
|
|
13
15
|
include Mutex_m
|
14
16
|
|
15
17
|
def initialize
|
16
|
-
@
|
18
|
+
@string_subscribers = Hash.new { |h, k| h[k] = [] }
|
19
|
+
@other_subscribers = []
|
17
20
|
@listeners_for = Concurrent::Map.new
|
18
21
|
super
|
19
22
|
end
|
20
23
|
|
21
|
-
def subscribe(pattern = nil,
|
22
|
-
subscriber = Subscribers.new
|
24
|
+
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
25
|
+
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
23
26
|
synchronize do
|
24
|
-
|
25
|
-
|
27
|
+
if String === pattern
|
28
|
+
@string_subscribers[pattern] << subscriber
|
29
|
+
@listeners_for.delete(pattern)
|
30
|
+
else
|
31
|
+
@other_subscribers << subscriber
|
32
|
+
@listeners_for.clear
|
33
|
+
end
|
26
34
|
end
|
27
35
|
subscriber
|
28
36
|
end
|
@@ -31,12 +39,19 @@ module ActiveSupport
|
|
31
39
|
synchronize do
|
32
40
|
case subscriber_or_name
|
33
41
|
when String
|
34
|
-
@
|
42
|
+
@string_subscribers[subscriber_or_name].clear
|
43
|
+
@listeners_for.delete(subscriber_or_name)
|
44
|
+
@other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
|
35
45
|
else
|
36
|
-
|
46
|
+
pattern = subscriber_or_name.try(:pattern)
|
47
|
+
if String === pattern
|
48
|
+
@string_subscribers[pattern].delete(subscriber_or_name)
|
49
|
+
@listeners_for.delete(pattern)
|
50
|
+
else
|
51
|
+
@other_subscribers.delete(subscriber_or_name)
|
52
|
+
@listeners_for.clear
|
53
|
+
end
|
37
54
|
end
|
38
|
-
|
39
|
-
@listeners_for.clear
|
40
55
|
end
|
41
56
|
end
|
42
57
|
|
@@ -56,7 +71,8 @@ module ActiveSupport
|
|
56
71
|
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
|
57
72
|
@listeners_for[name] || synchronize do
|
58
73
|
# use synchronisation when accessing @subscribers
|
59
|
-
@listeners_for[name] ||=
|
74
|
+
@listeners_for[name] ||=
|
75
|
+
@string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
|
60
76
|
end
|
61
77
|
end
|
62
78
|
|
@@ -69,13 +85,26 @@ module ActiveSupport
|
|
69
85
|
end
|
70
86
|
|
71
87
|
module Subscribers # :nodoc:
|
72
|
-
def self.new(pattern, listener)
|
88
|
+
def self.new(pattern, listener, monotonic)
|
89
|
+
subscriber_class = monotonic ? MonotonicTimed : Timed
|
90
|
+
|
73
91
|
if listener.respond_to?(:start) && listener.respond_to?(:finish)
|
74
|
-
|
92
|
+
subscriber_class = Evented
|
75
93
|
else
|
76
|
-
|
94
|
+
# Doing all this to detect a block like `proc { |x| }` vs
|
95
|
+
# `proc { |*x| }` or `proc { |**x| }`
|
96
|
+
if listener.respond_to?(:parameters)
|
97
|
+
params = listener.parameters
|
98
|
+
if params.length == 1 && params.first.first == :opt
|
99
|
+
subscriber_class = EventObject
|
100
|
+
end
|
101
|
+
end
|
77
102
|
end
|
78
103
|
|
104
|
+
wrap_all pattern, subscriber_class.new(pattern, listener)
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.wrap_all(pattern, subscriber)
|
79
108
|
unless pattern
|
80
109
|
AllMessages.new(subscriber)
|
81
110
|
else
|
@@ -83,9 +112,33 @@ module ActiveSupport
|
|
83
112
|
end
|
84
113
|
end
|
85
114
|
|
115
|
+
class Matcher #:nodoc:
|
116
|
+
attr_reader :pattern, :exclusions
|
117
|
+
|
118
|
+
def self.wrap(pattern)
|
119
|
+
return pattern if String === pattern
|
120
|
+
new(pattern)
|
121
|
+
end
|
122
|
+
|
123
|
+
def initialize(pattern)
|
124
|
+
@pattern = pattern
|
125
|
+
@exclusions = Set.new
|
126
|
+
end
|
127
|
+
|
128
|
+
def unsubscribe!(name)
|
129
|
+
exclusions << -name if pattern === name
|
130
|
+
end
|
131
|
+
|
132
|
+
def ===(name)
|
133
|
+
pattern === name && !exclusions.include?(name)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
86
137
|
class Evented #:nodoc:
|
138
|
+
attr_reader :pattern
|
139
|
+
|
87
140
|
def initialize(pattern, delegate)
|
88
|
-
@pattern = pattern
|
141
|
+
@pattern = Matcher.wrap(pattern)
|
89
142
|
@delegate = delegate
|
90
143
|
@can_publish = delegate.respond_to?(:publish)
|
91
144
|
end
|
@@ -105,11 +158,15 @@ module ActiveSupport
|
|
105
158
|
end
|
106
159
|
|
107
160
|
def subscribed_to?(name)
|
108
|
-
|
161
|
+
pattern === name
|
109
162
|
end
|
110
163
|
|
111
164
|
def matches?(name)
|
112
|
-
|
165
|
+
pattern && pattern === name
|
166
|
+
end
|
167
|
+
|
168
|
+
def unsubscribe!(name)
|
169
|
+
pattern.unsubscribe!(name)
|
113
170
|
end
|
114
171
|
end
|
115
172
|
|
@@ -130,6 +187,45 @@ module ActiveSupport
|
|
130
187
|
end
|
131
188
|
end
|
132
189
|
|
190
|
+
class MonotonicTimed < Evented # :nodoc:
|
191
|
+
def publish(name, *args)
|
192
|
+
@delegate.call name, *args
|
193
|
+
end
|
194
|
+
|
195
|
+
def start(name, id, payload)
|
196
|
+
timestack = Thread.current[:_timestack_monotonic] ||= []
|
197
|
+
timestack.push Concurrent.monotonic_time
|
198
|
+
end
|
199
|
+
|
200
|
+
def finish(name, id, payload)
|
201
|
+
timestack = Thread.current[:_timestack_monotonic]
|
202
|
+
started = timestack.pop
|
203
|
+
@delegate.call(name, started, Concurrent.monotonic_time, id, payload)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class EventObject < Evented
|
208
|
+
def start(name, id, payload)
|
209
|
+
stack = Thread.current[:_event_stack] ||= []
|
210
|
+
event = build_event name, id, payload
|
211
|
+
event.start!
|
212
|
+
stack.push event
|
213
|
+
end
|
214
|
+
|
215
|
+
def finish(name, id, payload)
|
216
|
+
stack = Thread.current[:_event_stack]
|
217
|
+
event = stack.pop
|
218
|
+
event.payload = payload
|
219
|
+
event.finish!
|
220
|
+
@delegate.call event
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
def build_event(name, id, payload)
|
225
|
+
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
133
229
|
class AllMessages # :nodoc:
|
134
230
|
def initialize(delegate)
|
135
231
|
@delegate = delegate
|
@@ -151,6 +247,10 @@ module ActiveSupport
|
|
151
247
|
true
|
152
248
|
end
|
153
249
|
|
250
|
+
def unsubscribe!(*)
|
251
|
+
false
|
252
|
+
end
|
253
|
+
|
154
254
|
alias :matches? :===
|
155
255
|
end
|
156
256
|
end
|
@@ -13,14 +13,15 @@ module ActiveSupport
|
|
13
13
|
@notifier = notifier
|
14
14
|
end
|
15
15
|
|
16
|
-
#
|
17
|
-
# and publish it.
|
18
|
-
#
|
16
|
+
# Given a block, instrument it by measuring the time taken to execute
|
17
|
+
# and publish it. Without a block, simply send a message via the
|
18
|
+
# notifier. Notice that events get sent even if an error occurs in the
|
19
|
+
# passed-in block.
|
19
20
|
def instrument(name, payload = {})
|
20
21
|
# some of the listeners might have state
|
21
22
|
listeners_state = start name, payload
|
22
23
|
begin
|
23
|
-
yield payload
|
24
|
+
yield payload if block_given?
|
24
25
|
rescue Exception => e
|
25
26
|
payload[:exception] = [e.class.name, e.message]
|
26
27
|
payload[:exception_object] = e
|
@@ -45,15 +46,14 @@ module ActiveSupport
|
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
48
|
-
|
49
49
|
def unique_id
|
50
50
|
SecureRandom.hex(10)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
54
|
class Event
|
55
|
-
attr_reader :name, :time, :
|
56
|
-
attr_accessor :
|
55
|
+
attr_reader :name, :time, :end, :transaction_id, :children
|
56
|
+
attr_accessor :payload
|
57
57
|
|
58
58
|
def initialize(name, start, ending, transaction_id, payload)
|
59
59
|
@name = name
|
@@ -62,7 +62,42 @@ module ActiveSupport
|
|
62
62
|
@transaction_id = transaction_id
|
63
63
|
@end = ending
|
64
64
|
@children = []
|
65
|
-
@
|
65
|
+
@cpu_time_start = 0
|
66
|
+
@cpu_time_finish = 0
|
67
|
+
@allocation_count_start = 0
|
68
|
+
@allocation_count_finish = 0
|
69
|
+
end
|
70
|
+
|
71
|
+
# Record information at the time this event starts
|
72
|
+
def start!
|
73
|
+
@time = now
|
74
|
+
@cpu_time_start = now_cpu
|
75
|
+
@allocation_count_start = now_allocations
|
76
|
+
end
|
77
|
+
|
78
|
+
# Record information at the time this event finishes
|
79
|
+
def finish!
|
80
|
+
@cpu_time_finish = now_cpu
|
81
|
+
@end = now
|
82
|
+
@allocation_count_finish = now_allocations
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the CPU time (in milliseconds) passed since the call to
|
86
|
+
# +start!+ and the call to +finish!+
|
87
|
+
def cpu_time
|
88
|
+
(@cpu_time_finish - @cpu_time_start) * 1000
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the idle time time (in milliseconds) passed since the call to
|
92
|
+
# +start!+ and the call to +finish!+
|
93
|
+
def idle_time
|
94
|
+
duration - cpu_time
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns the number of allocations made since the call to +start!+ and
|
98
|
+
# the call to +finish!+
|
99
|
+
def allocations
|
100
|
+
@allocation_count_finish - @allocation_count_start
|
66
101
|
end
|
67
102
|
|
68
103
|
# Returns the difference in milliseconds between when the execution of the
|
@@ -78,7 +113,7 @@ module ActiveSupport
|
|
78
113
|
#
|
79
114
|
# @event.duration # => 1000.138
|
80
115
|
def duration
|
81
|
-
|
116
|
+
1000.0 * (self.end - time)
|
82
117
|
end
|
83
118
|
|
84
119
|
def <<(event)
|
@@ -88,6 +123,33 @@ module ActiveSupport
|
|
88
123
|
def parent_of?(event)
|
89
124
|
@children.include? event
|
90
125
|
end
|
126
|
+
|
127
|
+
private
|
128
|
+
def now
|
129
|
+
Concurrent.monotonic_time
|
130
|
+
end
|
131
|
+
|
132
|
+
begin
|
133
|
+
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
|
134
|
+
|
135
|
+
def now_cpu
|
136
|
+
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
|
137
|
+
end
|
138
|
+
rescue
|
139
|
+
def now_cpu
|
140
|
+
0
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
if defined?(JRUBY_VERSION)
|
145
|
+
def now_allocations
|
146
|
+
0
|
147
|
+
end
|
148
|
+
else
|
149
|
+
def now_allocations
|
150
|
+
GC.stat :total_allocated_objects
|
151
|
+
end
|
152
|
+
end
|
91
153
|
end
|
92
154
|
end
|
93
155
|
end
|
@@ -34,10 +34,23 @@ module ActiveSupport
|
|
34
34
|
# name # => String, name of the event (such as 'render' from above)
|
35
35
|
# start # => Time, when the instrumented block started execution
|
36
36
|
# finish # => Time, when the instrumented block ended execution
|
37
|
-
# id # => String, unique ID for
|
37
|
+
# id # => String, unique ID for the instrumenter that fired the event
|
38
38
|
# payload # => Hash, the payload
|
39
39
|
# end
|
40
40
|
#
|
41
|
+
# Here, the +start+ and +finish+ values represent wall-clock time. If you are
|
42
|
+
# concerned about accuracy, you can register a monotonic subscriber.
|
43
|
+
#
|
44
|
+
# ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
|
45
|
+
# name # => String, name of the event (such as 'render' from above)
|
46
|
+
# start # => Monotonic time, when the instrumented block started execution
|
47
|
+
# finish # => Monotonic time, when the instrumented block ended execution
|
48
|
+
# id # => String, unique ID for the instrumenter that fired the event
|
49
|
+
# payload # => Hash, the payload
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# The +start+ and +finish+ values above represent monotonic time.
|
53
|
+
#
|
41
54
|
# For instance, let's store all "render" events in an array:
|
42
55
|
#
|
43
56
|
# events = []
|
@@ -59,7 +72,7 @@ module ActiveSupport
|
|
59
72
|
# event.payload # => { extra: :information }
|
60
73
|
#
|
61
74
|
# The block in the <tt>subscribe</tt> call gets the name of the event, start
|
62
|
-
# timestamp, end timestamp, a string with a unique identifier for that event
|
75
|
+
# timestamp, end timestamp, a string with a unique identifier for that event's instrumenter
|
63
76
|
# (something like "535801666f04d0298cd6"), and a hash with the payload, in
|
64
77
|
# that order.
|
65
78
|
#
|
@@ -67,9 +80,12 @@ module ActiveSupport
|
|
67
80
|
# have a key <tt>:exception</tt> with an array of two elements as value: a string with
|
68
81
|
# the name of the exception class, and the exception message.
|
69
82
|
# The <tt>:exception_object</tt> key of the payload will have the exception
|
70
|
-
# itself as the value
|
83
|
+
# itself as the value:
|
71
84
|
#
|
72
|
-
#
|
85
|
+
# event.payload[:exception] # => ["ArgumentError", "Invalid value"]
|
86
|
+
# event.payload[:exception_object] # => #<ArgumentError: Invalid value>
|
87
|
+
#
|
88
|
+
# As the earlier example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
|
73
89
|
# is able to take the arguments as they come and provide an object-oriented
|
74
90
|
# interface to that data.
|
75
91
|
#
|
@@ -132,6 +148,16 @@ module ActiveSupport
|
|
132
148
|
# during the execution of the block. The callback is unsubscribed automatically
|
133
149
|
# after that.
|
134
150
|
#
|
151
|
+
# To record +started+ and +finished+ values with monotonic time,
|
152
|
+
# specify the optional <tt>:monotonic</tt> option to the
|
153
|
+
# <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
|
154
|
+
# to +false+ by default.
|
155
|
+
#
|
156
|
+
# callback = lambda {|name, started, finished, unique_id, payload| ... }
|
157
|
+
# ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
|
158
|
+
# ...
|
159
|
+
# end
|
160
|
+
#
|
135
161
|
# === Manual Unsubscription
|
136
162
|
#
|
137
163
|
# The +subscribe+ method returns a subscriber object:
|
@@ -150,6 +176,15 @@ module ActiveSupport
|
|
150
176
|
#
|
151
177
|
# ActiveSupport::Notifications.unsubscribe("render")
|
152
178
|
#
|
179
|
+
# Subscribers using a regexp or other pattern-matching object will remain subscribed
|
180
|
+
# to all events that match their original pattern, unless those events match a string
|
181
|
+
# passed to `unsubscribe`:
|
182
|
+
#
|
183
|
+
# subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
|
184
|
+
# ActiveSupport::Notifications.unsubscribe('render_template.action_view')
|
185
|
+
# subscriber.matches?('render_template.action_view') # => false
|
186
|
+
# subscriber.matches?('render_partial.action_view') # => true
|
187
|
+
#
|
153
188
|
# == Default Queue
|
154
189
|
#
|
155
190
|
# Notifications ships with a queue implementation that consumes and publishes events
|
@@ -171,12 +206,41 @@ module ActiveSupport
|
|
171
206
|
end
|
172
207
|
end
|
173
208
|
|
174
|
-
|
175
|
-
|
209
|
+
# Subscribe to a given event name with the passed +block+.
|
210
|
+
#
|
211
|
+
# You can subscribe to events by passing a String to match exact event
|
212
|
+
# names, or by passing a Regexp to match all events that match a pattern.
|
213
|
+
#
|
214
|
+
# ActiveSupport::Notifications.subscribe(/render/) do |*args|
|
215
|
+
# @event = ActiveSupport::Notifications::Event.new(*args)
|
216
|
+
# end
|
217
|
+
#
|
218
|
+
# The +block+ will receive five parameters with information about the event:
|
219
|
+
#
|
220
|
+
# ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
|
221
|
+
# name # => String, name of the event (such as 'render' from above)
|
222
|
+
# start # => Time, when the instrumented block started execution
|
223
|
+
# finish # => Time, when the instrumented block ended execution
|
224
|
+
# id # => String, unique ID for the instrumenter that fired the event
|
225
|
+
# payload # => Hash, the payload
|
226
|
+
# end
|
227
|
+
#
|
228
|
+
# If the block passed to the method only takes one parameter,
|
229
|
+
# it will yield an event object to the block:
|
230
|
+
#
|
231
|
+
# ActiveSupport::Notifications.subscribe(/render/) do |event|
|
232
|
+
# @event = event
|
233
|
+
# end
|
234
|
+
def subscribe(pattern = nil, callback = nil, &block)
|
235
|
+
notifier.subscribe(pattern, callback, monotonic: false, &block)
|
236
|
+
end
|
237
|
+
|
238
|
+
def monotonic_subscribe(pattern = nil, callback = nil, &block)
|
239
|
+
notifier.subscribe(pattern, callback, monotonic: true, &block)
|
176
240
|
end
|
177
241
|
|
178
|
-
def subscribed(callback,
|
179
|
-
subscriber = subscribe(
|
242
|
+
def subscribed(callback, pattern = nil, monotonic: false, &block)
|
243
|
+
subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
|
180
244
|
yield
|
181
245
|
ensure
|
182
246
|
unsubscribe(subscriber)
|
@@ -30,7 +30,7 @@ module ActiveSupport
|
|
30
30
|
# If set to true, precision will mean the number of significant digits instead
|
31
31
|
# of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
|
32
32
|
significant: false,
|
33
|
-
# If set, the zeros after the decimal separator will always be stripped (
|
33
|
+
# If set, the zeros after the decimal separator will always be stripped (e.g.: 1.200 will be 1.2)
|
34
34
|
strip_insignificant_zeros: false
|
35
35
|
},
|
36
36
|
|
@@ -136,7 +136,6 @@ module ActiveSupport
|
|
136
136
|
end
|
137
137
|
|
138
138
|
private
|
139
|
-
|
140
139
|
def options
|
141
140
|
@options ||= format_options.merge(opts)
|
142
141
|
end
|
@@ -162,12 +161,12 @@ module ActiveSupport
|
|
162
161
|
options
|
163
162
|
end
|
164
163
|
|
165
|
-
def translate_number_value_with_default(key, i18n_options
|
166
|
-
I18n.translate(key, { default: default_value(key), scope: :number }.merge!(i18n_options))
|
164
|
+
def translate_number_value_with_default(key, **i18n_options)
|
165
|
+
I18n.translate(key, **{ default: default_value(key), scope: :number }.merge!(i18n_options))
|
167
166
|
end
|
168
167
|
|
169
|
-
def translate_in_locale(key, i18n_options
|
170
|
-
translate_number_value_with_default(key, { locale: options[:locale] }.merge(i18n_options))
|
168
|
+
def translate_in_locale(key, **i18n_options)
|
169
|
+
translate_number_value_with_default(key, **{ locale: options[:locale] }.merge(i18n_options))
|
171
170
|
end
|
172
171
|
|
173
172
|
def default_value(key)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/
|
3
|
+
require "active_support/number_helper/number_converter"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module NumberHelper
|
@@ -11,21 +11,16 @@ module ActiveSupport
|
|
11
11
|
number = self.number.to_s.strip
|
12
12
|
format = options[:format]
|
13
13
|
|
14
|
-
if number.
|
14
|
+
if number.sub!(/^-/, "") &&
|
15
|
+
(options[:precision] != 0 || number.to_f > 0.5)
|
15
16
|
format = options[:negative_format]
|
16
|
-
number = absolute_value(number)
|
17
17
|
end
|
18
18
|
|
19
19
|
rounded_number = NumberToRoundedConverter.convert(number, options)
|
20
|
-
format.gsub("%n"
|
20
|
+
format.gsub("%n", rounded_number).gsub("%u", options[:unit])
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
24
|
-
|
25
|
-
def absolute_value(number)
|
26
|
-
number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "")
|
27
|
-
end
|
28
|
-
|
29
24
|
def options
|
30
25
|
@options ||= begin
|
31
26
|
defaults = default_format_options.merge(i18n_opts)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/number_helper/number_converter"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module NumberHelper
|
5
7
|
class NumberToDelimitedConverter < NumberConverter #:nodoc:
|
@@ -12,9 +14,8 @@ module ActiveSupport
|
|
12
14
|
end
|
13
15
|
|
14
16
|
private
|
15
|
-
|
16
17
|
def parts
|
17
|
-
left, right = number.to_s.split("."
|
18
|
+
left, right = number.to_s.split(".")
|
18
19
|
left.gsub!(delimiter_pattern) do |digit_to_delimit|
|
19
20
|
"#{digit_to_delimit}#{options[:delimiter]}"
|
20
21
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/number_helper/number_converter"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module NumberHelper
|
5
7
|
class NumberToHumanConverter < NumberConverter # :nodoc:
|
@@ -14,7 +16,7 @@ module ActiveSupport
|
|
14
16
|
@number = RoundingHelper.new(options).round(number)
|
15
17
|
@number = Float(number)
|
16
18
|
|
17
|
-
#
|
19
|
+
# For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
|
18
20
|
unless options.key?(:strip_insignificant_zeros)
|
19
21
|
options[:strip_insignificant_zeros] = true
|
20
22
|
end
|
@@ -25,11 +27,10 @@ module ActiveSupport
|
|
25
27
|
|
26
28
|
rounded_number = NumberToRoundedConverter.convert(number, options)
|
27
29
|
unit = determine_unit(units, exponent)
|
28
|
-
format.gsub("%n"
|
30
|
+
format.gsub("%n", rounded_number).gsub("%u", unit).strip
|
29
31
|
end
|
30
32
|
|
31
33
|
private
|
32
|
-
|
33
34
|
def format
|
34
35
|
options[:format] || translate_in_locale("human.decimal_units.format")
|
35
36
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/number_helper/number_converter"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module NumberHelper
|
5
7
|
class NumberToHumanSizeConverter < NumberConverter #:nodoc:
|
@@ -11,7 +13,7 @@ module ActiveSupport
|
|
11
13
|
def convert
|
12
14
|
@number = Float(number)
|
13
15
|
|
14
|
-
#
|
16
|
+
# For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
|
15
17
|
unless options.key?(:strip_insignificant_zeros)
|
16
18
|
options[:strip_insignificant_zeros] = true
|
17
19
|
end
|
@@ -22,11 +24,10 @@ module ActiveSupport
|
|
22
24
|
human_size = number / (base**exponent)
|
23
25
|
number_to_format = NumberToRoundedConverter.convert(human_size, options)
|
24
26
|
end
|
25
|
-
conversion_format.gsub("%n"
|
27
|
+
conversion_format.gsub("%n", number_to_format).gsub("%u", unit)
|
26
28
|
end
|
27
29
|
|
28
30
|
private
|
29
|
-
|
30
31
|
def conversion_format
|
31
32
|
translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true)
|
32
33
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/number_helper/number_converter"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module NumberHelper
|
5
7
|
class NumberToPercentageConverter < NumberConverter # :nodoc:
|
@@ -7,7 +9,7 @@ module ActiveSupport
|
|
7
9
|
|
8
10
|
def convert
|
9
11
|
rounded_number = NumberToRoundedConverter.convert(number, options)
|
10
|
-
options[:format].gsub("%n"
|
12
|
+
options[:format].gsub("%n", rounded_number)
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/number_helper/number_converter"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module NumberHelper
|
5
7
|
class NumberToPhoneConverter < NumberConverter #:nodoc:
|
@@ -10,7 +12,6 @@ module ActiveSupport
|
|
10
12
|
end
|
11
13
|
|
12
14
|
private
|
13
|
-
|
14
15
|
def convert_to_phone_number(number)
|
15
16
|
if opts[:area_code]
|
16
17
|
convert_with_area_code(number)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/number_helper/number_converter"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
module NumberHelper
|
5
7
|
class NumberToRoundedConverter < NumberConverter # :nodoc:
|
@@ -18,14 +20,14 @@ module ActiveSupport
|
|
18
20
|
end
|
19
21
|
|
20
22
|
formatted_string =
|
21
|
-
if
|
23
|
+
if rounded_number.nan? || rounded_number.infinite? || rounded_number == rounded_number.to_i
|
24
|
+
"%00.#{precision}f" % rounded_number
|
25
|
+
else
|
22
26
|
s = rounded_number.to_s("F")
|
23
|
-
s << "0"
|
24
|
-
a, b = s.split("."
|
25
|
-
a << "."
|
27
|
+
s << "0" * precision
|
28
|
+
a, b = s.split(".", 2)
|
29
|
+
a << "."
|
26
30
|
a << b[0, precision]
|
27
|
-
else
|
28
|
-
"%00.#{precision}f" % rounded_number
|
29
31
|
end
|
30
32
|
else
|
31
33
|
formatted_string = rounded_number
|
@@ -36,7 +38,6 @@ module ActiveSupport
|
|
36
38
|
end
|
37
39
|
|
38
40
|
private
|
39
|
-
|
40
41
|
def strip_insignificant_zeros
|
41
42
|
options[:strip_insignificant_zeros]
|
42
43
|
end
|