activesupport 6.0.4.4 → 7.0.4.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.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +257 -532
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +5 -5
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +16 -10
- data/lib/active_support/cache/mem_cache_store.rb +163 -42
- data/lib/active_support/cache/memory_store.rb +57 -29
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +79 -98
- data/lib/active_support/cache/strategy/local_cache.rb +49 -57
- data/lib/active_support/cache.rb +378 -179
- data/lib/active_support/callbacks.rb +230 -122
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +49 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +9 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +9 -22
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +17 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +164 -23
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +2 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +2 -2
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +40 -36
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -73
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +42 -26
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +39 -5
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +92 -41
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +25 -7
- data/lib/active_support/core_ext/time/conversions.rb +15 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -23
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +39 -16
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -769
- data/lib/active_support/deprecation/behaviors.rb +23 -7
- 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 +6 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +7 -2
- data/lib/active_support/descendants_tracker.rb +174 -64
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -10
- data/lib/active_support/duration.rb +134 -55
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +32 -3
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +72 -138
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +43 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +51 -25
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +24 -9
- data/lib/active_support/inflector/methods.rb +29 -49
- data/lib/active_support/inflector/transliterate.rb +5 -5
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +8 -4
- data/lib/active_support/key_generator.rb +23 -6
- data/lib/active_support/lazy_load_hooks.rb +28 -4
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +23 -5
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -21
- data/lib/active_support/message_encryptor.rb +16 -13
- data/lib/active_support/message_verifier.rb +50 -18
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +13 -52
- data/lib/active_support/multibyte/unicode.rb +1 -87
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +110 -69
- data/lib/active_support/notifications/instrumenter.rb +37 -29
- data/lib/active_support/notifications.rb +55 -28
- data/lib/active_support/number_helper/number_converter.rb +2 -4
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +29 -16
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +9 -3
- data/lib/active_support/parameter_filter.rb +21 -11
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +16 -16
- data/lib/active_support/ruby_features.rb +7 -0
- 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 +2 -2
- data/lib/active_support/subscriber.rb +19 -25
- data/lib/active_support/tagged_logging.rb +31 -6
- data/lib/active_support/test_case.rb +13 -21
- data/lib/active_support/testing/assertions.rb +50 -13
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +53 -5
- data/lib/active_support/time_with_zone.rb +126 -62
- data/lib/active_support/values/time_zone.rb +54 -23
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +29 -1
- metadata +46 -45
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -31,6 +31,10 @@ module ActiveSupport
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
def new_event(name, payload = {}) # :nodoc:
|
35
|
+
Event.new(name, nil, nil, @id, payload)
|
36
|
+
end
|
37
|
+
|
34
38
|
# Send a start notification with +name+ and +payload+.
|
35
39
|
def start(name, payload)
|
36
40
|
@notifier.start name, @id, payload
|
@@ -52,28 +56,35 @@ module ActiveSupport
|
|
52
56
|
end
|
53
57
|
|
54
58
|
class Event
|
55
|
-
attr_reader :name, :time, :end, :transaction_id, :
|
56
|
-
|
57
|
-
def self.clock_gettime_supported? # :nodoc:
|
58
|
-
defined?(Process::CLOCK_THREAD_CPUTIME_ID) &&
|
59
|
-
!Gem.win_platform? &&
|
60
|
-
!RUBY_PLATFORM.match?(/solaris/i)
|
61
|
-
end
|
62
|
-
private_class_method :clock_gettime_supported?
|
59
|
+
attr_reader :name, :time, :end, :transaction_id, :children
|
60
|
+
attr_accessor :payload
|
63
61
|
|
64
62
|
def initialize(name, start, ending, transaction_id, payload)
|
65
63
|
@name = name
|
66
64
|
@payload = payload.dup
|
67
|
-
@time = start
|
65
|
+
@time = start ? start.to_f * 1_000.0 : start
|
68
66
|
@transaction_id = transaction_id
|
69
|
-
@end = ending
|
67
|
+
@end = ending ? ending.to_f * 1_000.0 : ending
|
70
68
|
@children = []
|
71
|
-
@cpu_time_start = 0
|
72
|
-
@cpu_time_finish = 0
|
69
|
+
@cpu_time_start = 0.0
|
70
|
+
@cpu_time_finish = 0.0
|
73
71
|
@allocation_count_start = 0
|
74
72
|
@allocation_count_finish = 0
|
75
73
|
end
|
76
74
|
|
75
|
+
def record
|
76
|
+
start!
|
77
|
+
begin
|
78
|
+
yield payload if block_given?
|
79
|
+
rescue Exception => e
|
80
|
+
payload[:exception] = [e.class.name, e.message]
|
81
|
+
payload[:exception_object] = e
|
82
|
+
raise e
|
83
|
+
ensure
|
84
|
+
finish!
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
77
88
|
# Record information at the time this event starts
|
78
89
|
def start!
|
79
90
|
@time = now
|
@@ -88,15 +99,10 @@ module ActiveSupport
|
|
88
99
|
@allocation_count_finish = now_allocations
|
89
100
|
end
|
90
101
|
|
91
|
-
def end=(ending)
|
92
|
-
ActiveSupport::Deprecation.deprecation_warning(:end=, :finish!)
|
93
|
-
@end = ending
|
94
|
-
end
|
95
|
-
|
96
102
|
# Returns the CPU time (in milliseconds) passed since the call to
|
97
103
|
# +start!+ and the call to +finish!+
|
98
104
|
def cpu_time
|
99
|
-
|
105
|
+
@cpu_time_finish - @cpu_time_start
|
100
106
|
end
|
101
107
|
|
102
108
|
# Returns the idle time time (in milliseconds) passed since the call to
|
@@ -124,7 +130,7 @@ module ActiveSupport
|
|
124
130
|
#
|
125
131
|
# @event.duration # => 1000.138
|
126
132
|
def duration
|
127
|
-
|
133
|
+
self.end - time
|
128
134
|
end
|
129
135
|
|
130
136
|
def <<(event)
|
@@ -137,26 +143,28 @@ module ActiveSupport
|
|
137
143
|
|
138
144
|
private
|
139
145
|
def now
|
140
|
-
|
146
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
141
147
|
end
|
142
148
|
|
143
|
-
|
149
|
+
begin
|
150
|
+
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
|
151
|
+
|
144
152
|
def now_cpu
|
145
|
-
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
|
153
|
+
Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
|
146
154
|
end
|
147
|
-
|
148
|
-
def now_cpu
|
149
|
-
0
|
155
|
+
rescue
|
156
|
+
def now_cpu # rubocop:disable Lint/DuplicateMethods
|
157
|
+
0.0
|
150
158
|
end
|
151
159
|
end
|
152
160
|
|
153
|
-
if
|
161
|
+
if GC.stat.key?(:total_allocated_objects)
|
154
162
|
def now_allocations
|
155
|
-
|
163
|
+
GC.stat(:total_allocated_objects)
|
156
164
|
end
|
157
|
-
else
|
165
|
+
else # Likely on JRuby, TruffleRuby
|
158
166
|
def now_allocations
|
159
|
-
|
167
|
+
0
|
160
168
|
end
|
161
169
|
end
|
162
170
|
end
|
@@ -2,10 +2,9 @@
|
|
2
2
|
|
3
3
|
require "active_support/notifications/instrumenter"
|
4
4
|
require "active_support/notifications/fanout"
|
5
|
-
require "active_support/per_thread_registry"
|
6
5
|
|
7
6
|
module ActiveSupport
|
8
|
-
# = Notifications
|
7
|
+
# = \Notifications
|
9
8
|
#
|
10
9
|
# <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
|
11
10
|
# Ruby.
|
@@ -38,6 +37,19 @@ module ActiveSupport
|
|
38
37
|
# payload # => Hash, the payload
|
39
38
|
# end
|
40
39
|
#
|
40
|
+
# Here, the +start+ and +finish+ values represent wall-clock time. If you are
|
41
|
+
# concerned about accuracy, you can register a monotonic subscriber.
|
42
|
+
#
|
43
|
+
# ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
|
44
|
+
# name # => String, name of the event (such as 'render' from above)
|
45
|
+
# start # => Monotonic time, when the instrumented block started execution
|
46
|
+
# finish # => Monotonic time, when the instrumented block ended execution
|
47
|
+
# id # => String, unique ID for the instrumenter that fired the event
|
48
|
+
# payload # => Hash, the payload
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# The +start+ and +finish+ values above represent monotonic time.
|
52
|
+
#
|
41
53
|
# For instance, let's store all "render" events in an array:
|
42
54
|
#
|
43
55
|
# events = []
|
@@ -72,7 +84,7 @@ module ActiveSupport
|
|
72
84
|
# event.payload[:exception] # => ["ArgumentError", "Invalid value"]
|
73
85
|
# event.payload[:exception_object] # => #<ArgumentError: Invalid value>
|
74
86
|
#
|
75
|
-
# As the earlier example depicts, the class
|
87
|
+
# As the earlier example depicts, the class ActiveSupport::Notifications::Event
|
76
88
|
# is able to take the arguments as they come and provide an object-oriented
|
77
89
|
# interface to that data.
|
78
90
|
#
|
@@ -135,6 +147,16 @@ module ActiveSupport
|
|
135
147
|
# during the execution of the block. The callback is unsubscribed automatically
|
136
148
|
# after that.
|
137
149
|
#
|
150
|
+
# To record +started+ and +finished+ values with monotonic time,
|
151
|
+
# specify the optional <tt>:monotonic</tt> option to the
|
152
|
+
# <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
|
153
|
+
# to +false+ by default.
|
154
|
+
#
|
155
|
+
# callback = lambda {|name, started, finished, unique_id, payload| ... }
|
156
|
+
# ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
|
157
|
+
# ...
|
158
|
+
# end
|
159
|
+
#
|
138
160
|
# === Manual Unsubscription
|
139
161
|
#
|
140
162
|
# The +subscribe+ method returns a subscriber object:
|
@@ -155,7 +177,7 @@ module ActiveSupport
|
|
155
177
|
#
|
156
178
|
# Subscribers using a regexp or other pattern-matching object will remain subscribed
|
157
179
|
# to all events that match their original pattern, unless those events match a string
|
158
|
-
# passed to
|
180
|
+
# passed to +unsubscribe+:
|
159
181
|
#
|
160
182
|
# subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
|
161
183
|
# ActiveSupport::Notifications.unsubscribe('render_template.action_view')
|
@@ -175,6 +197,10 @@ module ActiveSupport
|
|
175
197
|
notifier.publish(name, *args)
|
176
198
|
end
|
177
199
|
|
200
|
+
def publish_event(event) # :nodoc:
|
201
|
+
notifier.publish_event(event)
|
202
|
+
end
|
203
|
+
|
178
204
|
def instrument(name, payload = {})
|
179
205
|
if notifier.listening?(name)
|
180
206
|
instrumenter.instrument(name, payload) { yield payload if block_given? }
|
@@ -208,12 +234,28 @@ module ActiveSupport
|
|
208
234
|
# ActiveSupport::Notifications.subscribe(/render/) do |event|
|
209
235
|
# @event = event
|
210
236
|
# end
|
211
|
-
|
212
|
-
|
237
|
+
#
|
238
|
+
# Raises an error if invalid event name type is passed:
|
239
|
+
#
|
240
|
+
# ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
|
241
|
+
# #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
|
242
|
+
#
|
243
|
+
def subscribe(pattern = nil, callback = nil, &block)
|
244
|
+
notifier.subscribe(pattern, callback, monotonic: false, &block)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Performs the same functionality as #subscribe, but the +start+ and
|
248
|
+
# +finish+ block arguments are in monotonic time instead of wall-clock
|
249
|
+
# time. Monotonic time will not jump forward or backward (due to NTP or
|
250
|
+
# Daylights Savings). Use +monotonic_subscribe+ when accuracy of time
|
251
|
+
# duration is important. For example, computing elapsed time between
|
252
|
+
# two events.
|
253
|
+
def monotonic_subscribe(pattern = nil, callback = nil, &block)
|
254
|
+
notifier.subscribe(pattern, callback, monotonic: true, &block)
|
213
255
|
end
|
214
256
|
|
215
|
-
def subscribed(callback,
|
216
|
-
subscriber = subscribe(
|
257
|
+
def subscribed(callback, pattern = nil, monotonic: false, &block)
|
258
|
+
subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
|
217
259
|
yield
|
218
260
|
ensure
|
219
261
|
unsubscribe(subscriber)
|
@@ -224,28 +266,13 @@ module ActiveSupport
|
|
224
266
|
end
|
225
267
|
|
226
268
|
def instrumenter
|
227
|
-
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
# This class is a registry which holds all of the +Instrumenter+ objects
|
232
|
-
# in a particular thread local. To access the +Instrumenter+ object for a
|
233
|
-
# particular +notifier+, you can call the following method:
|
234
|
-
#
|
235
|
-
# InstrumentationRegistry.instrumenter_for(notifier)
|
236
|
-
#
|
237
|
-
# The instrumenters for multiple notifiers are held in a single instance of
|
238
|
-
# this class.
|
239
|
-
class InstrumentationRegistry # :nodoc:
|
240
|
-
extend ActiveSupport::PerThreadRegistry
|
241
|
-
|
242
|
-
def initialize
|
243
|
-
@registry = {}
|
269
|
+
registry[notifier] ||= Instrumenter.new(notifier)
|
244
270
|
end
|
245
271
|
|
246
|
-
|
247
|
-
|
248
|
-
|
272
|
+
private
|
273
|
+
def registry
|
274
|
+
ActiveSupport::IsolatedExecutionState[:active_support_notifications_registry] ||= {}
|
275
|
+
end
|
249
276
|
end
|
250
277
|
|
251
278
|
self.notifier = Fanout.new
|
@@ -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
|
|
@@ -174,9 +174,7 @@ module ActiveSupport
|
|
174
174
|
end
|
175
175
|
|
176
176
|
def valid_float?
|
177
|
-
Float(number)
|
178
|
-
rescue ArgumentError, TypeError
|
179
|
-
false
|
177
|
+
Float(number, exception: false)
|
180
178
|
end
|
181
179
|
end
|
182
180
|
end
|
@@ -8,16 +8,21 @@ module ActiveSupport
|
|
8
8
|
self.namespace = :currency
|
9
9
|
|
10
10
|
def convert
|
11
|
-
number = self.number.to_s.strip
|
12
11
|
format = options[:format]
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
number_f = valid_float?
|
14
|
+
if number_f
|
15
|
+
if number_f.negative?
|
16
|
+
number_f = number_f.abs
|
17
|
+
format = options[:negative_format] if (number_f * 10**options[:precision]) >= 0.5
|
18
|
+
end
|
19
|
+
number_s = NumberToRoundedConverter.convert(number_f, options)
|
20
|
+
else
|
21
|
+
number_s = number.to_s.strip
|
22
|
+
format = options[:negative_format] if number_s.sub!(/^-/, "")
|
17
23
|
end
|
18
24
|
|
19
|
-
|
20
|
-
format.gsub("%n", rounded_number).gsub("%u", options[:unit])
|
25
|
+
format.gsub("%n", number_s).gsub("%u", options[:unit])
|
21
26
|
end
|
22
27
|
|
23
28
|
private
|
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module NumberHelper
|
7
|
-
class NumberToDelimitedConverter < NumberConverter
|
7
|
+
class NumberToDelimitedConverter < NumberConverter # :nodoc:
|
8
8
|
self.validate_float = true
|
9
9
|
|
10
10
|
DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
|
@@ -16,7 +16,7 @@ module ActiveSupport
|
|
16
16
|
@number = RoundingHelper.new(options).round(number)
|
17
17
|
@number = Float(number)
|
18
18
|
|
19
|
-
#
|
19
|
+
# For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
|
20
20
|
unless options.key?(:strip_insignificant_zeros)
|
21
21
|
options[:strip_insignificant_zeros] = true
|
22
22
|
end
|
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module NumberHelper
|
7
|
-
class NumberToHumanSizeConverter < NumberConverter
|
7
|
+
class NumberToHumanSizeConverter < NumberConverter # :nodoc:
|
8
8
|
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
|
9
9
|
|
10
10
|
self.namespace = :human
|
@@ -13,7 +13,7 @@ module ActiveSupport
|
|
13
13
|
def convert
|
14
14
|
@number = Float(number)
|
15
15
|
|
16
|
-
#
|
16
|
+
# For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
|
17
17
|
unless options.key?(:strip_insignificant_zeros)
|
18
18
|
options[:strip_insignificant_zeros] = true
|
19
19
|
end
|
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
|
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
6
|
module NumberHelper
|
7
|
-
class NumberToPhoneConverter < NumberConverter
|
7
|
+
class NumberToPhoneConverter < NumberConverter # :nodoc:
|
8
8
|
def convert
|
9
9
|
str = country_code(opts[:country_code]).dup
|
10
10
|
str << convert_to_phone_number(number.to_s.strip)
|
@@ -20,14 +20,18 @@ module ActiveSupport
|
|
20
20
|
end
|
21
21
|
|
22
22
|
formatted_string =
|
23
|
-
if
|
23
|
+
if rounded_number.finite?
|
24
24
|
s = rounded_number.to_s("F")
|
25
|
-
s << "0" * precision
|
26
25
|
a, b = s.split(".", 2)
|
27
|
-
|
28
|
-
|
26
|
+
if precision != 0
|
27
|
+
b << "0" * precision
|
28
|
+
a << "."
|
29
|
+
a << b[0, precision]
|
30
|
+
end
|
31
|
+
a
|
29
32
|
else
|
30
|
-
|
33
|
+
# Infinity/NaN
|
34
|
+
"%f" % rounded_number
|
31
35
|
end
|
32
36
|
else
|
33
37
|
formatted_string = rounded_number
|
@@ -10,56 +10,36 @@ module ActiveSupport
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def round(number)
|
13
|
+
precision = absolute_precision(number)
|
13
14
|
return number unless precision
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
else
|
18
|
-
round_without_significant(number)
|
19
|
-
end
|
15
|
+
|
16
|
+
rounded_number = convert_to_decimal(number).round(precision, options.fetch(:round_mode, :default).to_sym)
|
17
|
+
rounded_number.zero? ? rounded_number.abs : rounded_number # prevent showing negative zeros
|
20
18
|
end
|
21
19
|
|
22
20
|
def digit_count(number)
|
23
21
|
return 1 if number.zero?
|
24
|
-
(Math.log10(
|
22
|
+
(Math.log10(number.abs) + 1).floor
|
25
23
|
end
|
26
24
|
|
27
25
|
private
|
28
|
-
def round_without_significant(number)
|
29
|
-
number = number.round(precision, BigDecimal.mode(BigDecimal::ROUND_MODE))
|
30
|
-
number = number.to_i if precision == 0 && number.finite?
|
31
|
-
number = number.abs if number.zero? # prevent showing negative zeros
|
32
|
-
number
|
33
|
-
end
|
34
|
-
|
35
|
-
def round_significant(number)
|
36
|
-
return 0 if number.zero?
|
37
|
-
digits = digit_count(number)
|
38
|
-
multiplier = 10**(digits - precision)
|
39
|
-
(number / BigDecimal(multiplier.to_f.to_s)).round * multiplier
|
40
|
-
end
|
41
|
-
|
42
26
|
def convert_to_decimal(number)
|
43
27
|
case number
|
44
28
|
when Float, String
|
45
29
|
BigDecimal(number.to_s)
|
46
30
|
when Rational
|
47
|
-
BigDecimal(number, digit_count(number.to_i) + precision)
|
31
|
+
BigDecimal(number, digit_count(number.to_i) + options[:precision])
|
48
32
|
else
|
49
33
|
number.to_d
|
50
34
|
end
|
51
35
|
end
|
52
36
|
|
53
|
-
def
|
54
|
-
options[:precision]
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
def absolute_number(number)
|
62
|
-
number.respond_to?(:abs) ? number.abs : number.to_d.abs
|
37
|
+
def absolute_precision(number)
|
38
|
+
if options[:significant] && options[:precision] > 0
|
39
|
+
options[:precision] - digit_count(convert_to_decimal(number))
|
40
|
+
else
|
41
|
+
options[:precision]
|
42
|
+
end
|
63
43
|
end
|
64
44
|
end
|
65
45
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/dependencies/autoload"
|
4
|
-
|
5
3
|
module ActiveSupport
|
6
4
|
module NumberHelper
|
7
5
|
extend ActiveSupport::Autoload
|
@@ -73,6 +71,8 @@ module ActiveSupport
|
|
73
71
|
# (defaults to current locale).
|
74
72
|
# * <tt>:precision</tt> - Sets the level of precision (defaults
|
75
73
|
# to 2).
|
74
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
75
|
+
# (defaults to :default. See BigDecimal::mode)
|
76
76
|
# * <tt>:unit</tt> - Sets the denomination of the currency
|
77
77
|
# (defaults to "$").
|
78
78
|
# * <tt>:separator</tt> - Sets the separator between the units
|
@@ -99,8 +99,6 @@ module ActiveSupport
|
|
99
99
|
# number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
|
100
100
|
# number_to_currency('123a456') # => "$123a456"
|
101
101
|
#
|
102
|
-
# number_to_currency("123a456", raise: true) # => InvalidNumberError
|
103
|
-
#
|
104
102
|
# number_to_currency(-0.456789, precision: 0)
|
105
103
|
# # => "$0"
|
106
104
|
# number_to_currency(-1234567890.50, negative_format: '(%u%n)')
|
@@ -111,6 +109,8 @@ module ActiveSupport
|
|
111
109
|
# # => "1234567890,50 £"
|
112
110
|
# number_to_currency(1234567890.50, strip_insignificant_zeros: true)
|
113
111
|
# # => "$1,234,567,890.5"
|
112
|
+
# number_to_currency(1234567890.50, precision: 0, round_mode: :up)
|
113
|
+
# # => "$1,234,567,891"
|
114
114
|
def number_to_currency(number, options = {})
|
115
115
|
NumberToCurrencyConverter.convert(number, options)
|
116
116
|
end
|
@@ -124,6 +124,8 @@ module ActiveSupport
|
|
124
124
|
# (defaults to current locale).
|
125
125
|
# * <tt>:precision</tt> - Sets the precision of the number
|
126
126
|
# (defaults to 3). Keeps the number's precision if +nil+.
|
127
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
128
|
+
# (defaults to :default. See BigDecimal::mode)
|
127
129
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
128
130
|
# of significant_digits. If +false+, the number of fractional
|
129
131
|
# digits (defaults to +false+).
|
@@ -139,15 +141,16 @@ module ActiveSupport
|
|
139
141
|
#
|
140
142
|
# ==== Examples
|
141
143
|
#
|
142
|
-
# number_to_percentage(100)
|
143
|
-
# number_to_percentage('98')
|
144
|
-
# number_to_percentage(100, precision: 0)
|
145
|
-
# number_to_percentage(1000, delimiter: '.', separator: ',')
|
146
|
-
# number_to_percentage(302.24398923423, precision: 5)
|
147
|
-
# number_to_percentage(1000, locale: :fr)
|
148
|
-
# number_to_percentage(1000, precision: nil)
|
149
|
-
# number_to_percentage('98a')
|
150
|
-
# number_to_percentage(100, format: '%n %')
|
144
|
+
# number_to_percentage(100) # => "100.000%"
|
145
|
+
# number_to_percentage('98') # => "98.000%"
|
146
|
+
# number_to_percentage(100, precision: 0) # => "100%"
|
147
|
+
# number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
|
148
|
+
# number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
|
149
|
+
# number_to_percentage(1000, locale: :fr) # => "1000,000%"
|
150
|
+
# number_to_percentage(1000, precision: nil) # => "1000%"
|
151
|
+
# number_to_percentage('98a') # => "98a%"
|
152
|
+
# number_to_percentage(100, format: '%n %') # => "100.000 %"
|
153
|
+
# number_to_percentage(302.24398923423, precision: 5, round_mode: :down) # => "302.24398%"
|
151
154
|
def number_to_percentage(number, options = {})
|
152
155
|
NumberToPercentageConverter.convert(number, options)
|
153
156
|
end
|
@@ -198,6 +201,8 @@ module ActiveSupport
|
|
198
201
|
# (defaults to current locale).
|
199
202
|
# * <tt>:precision</tt> - Sets the precision of the number
|
200
203
|
# (defaults to 3). Keeps the number's precision if +nil+.
|
204
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
205
|
+
# (defaults to :default. See BigDecimal::mode)
|
201
206
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
202
207
|
# of significant_digits. If +false+, the number of fractional
|
203
208
|
# digits (defaults to +false+).
|
@@ -219,6 +224,7 @@ module ActiveSupport
|
|
219
224
|
# number_to_rounded(111.2345, precision: 1, significant: true) # => "100"
|
220
225
|
# number_to_rounded(13, precision: 5, significant: true) # => "13.000"
|
221
226
|
# number_to_rounded(13, precision: nil) # => "13"
|
227
|
+
# number_to_rounded(389.32314, precision: 0, round_mode: :up) # => "390"
|
222
228
|
# number_to_rounded(111.234, locale: :fr) # => "111,234"
|
223
229
|
#
|
224
230
|
# number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true)
|
@@ -232,7 +238,7 @@ module ActiveSupport
|
|
232
238
|
end
|
233
239
|
|
234
240
|
# Formats the bytes in +number+ into a more understandable
|
235
|
-
# representation (e.g., giving it 1500 yields 1.
|
241
|
+
# representation (e.g., giving it 1500 yields 1.46 KB). This
|
236
242
|
# method is useful for reporting file sizes to users. You can
|
237
243
|
# customize the format in the +options+ hash.
|
238
244
|
#
|
@@ -245,6 +251,8 @@ module ActiveSupport
|
|
245
251
|
# (defaults to current locale).
|
246
252
|
# * <tt>:precision</tt> - Sets the precision of the number
|
247
253
|
# (defaults to 3).
|
254
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
255
|
+
# (defaults to :default. See BigDecimal::mode)
|
248
256
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
249
257
|
# of significant_digits. If +false+, the number of fractional
|
250
258
|
# digits (defaults to +true+)
|
@@ -268,6 +276,7 @@ module ActiveSupport
|
|
268
276
|
# number_to_human_size(1234567890123456789) # => "1.07 EB"
|
269
277
|
# number_to_human_size(1234567, precision: 2) # => "1.2 MB"
|
270
278
|
# number_to_human_size(483989, precision: 2) # => "470 KB"
|
279
|
+
# number_to_human_size(483989, precision: 2, round_mode: :up) # => "480 KB"
|
271
280
|
# number_to_human_size(1234567, precision: 2, separator: ',') # => "1,2 MB"
|
272
281
|
# number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
|
273
282
|
# number_to_human_size(524288000, precision: 5) # => "500 MB"
|
@@ -276,7 +285,7 @@ module ActiveSupport
|
|
276
285
|
end
|
277
286
|
|
278
287
|
# Pretty prints (formats and approximates) a number in a way it
|
279
|
-
# is more readable by humans (
|
288
|
+
# is more readable by humans (e.g.: 1200000000 becomes "1.2
|
280
289
|
# Billion"). This is useful for numbers that can get very large
|
281
290
|
# (and too hard to read).
|
282
291
|
#
|
@@ -284,7 +293,7 @@ module ActiveSupport
|
|
284
293
|
# size.
|
285
294
|
#
|
286
295
|
# You can also define your own unit-quantifier names if you want
|
287
|
-
# to use other decimal units (
|
296
|
+
# to use other decimal units (e.g.: 1500 becomes "1.5
|
288
297
|
# kilometers", 0.150 becomes "150 milliliters", etc). You may
|
289
298
|
# define a wide range of unit quantifiers, even fractional ones
|
290
299
|
# (centi, deci, mili, etc).
|
@@ -295,6 +304,8 @@ module ActiveSupport
|
|
295
304
|
# (defaults to current locale).
|
296
305
|
# * <tt>:precision</tt> - Sets the precision of the number
|
297
306
|
# (defaults to 3).
|
307
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
308
|
+
# (defaults to :default. See BigDecimal::mode)
|
298
309
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
299
310
|
# of significant_digits. If +false+, the number of fractional
|
300
311
|
# digits (defaults to +true+)
|
@@ -332,6 +343,8 @@ module ActiveSupport
|
|
332
343
|
# number_to_human(1234567890123456789) # => "1230 Quadrillion"
|
333
344
|
# number_to_human(489939, precision: 2) # => "490 Thousand"
|
334
345
|
# number_to_human(489939, precision: 4) # => "489.9 Thousand"
|
346
|
+
# number_to_human(489939, precision: 2
|
347
|
+
# , round_mode: :down) # => "480 Thousand"
|
335
348
|
# number_to_human(1234567, precision: 4,
|
336
349
|
# significant: false) # => "1.2346 Million"
|
337
350
|
# number_to_human(1234567, precision: 1,
|
@@ -3,9 +3,9 @@
|
|
3
3
|
require "active_support/core_ext/hash/deep_merge"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
class OptionMerger
|
6
|
+
class OptionMerger # :nodoc:
|
7
7
|
instance_methods.each do |method|
|
8
|
-
undef_method(method)
|
8
|
+
undef_method(method) unless method.start_with?("__", "instance_eval", "class", "object_id")
|
9
9
|
end
|
10
10
|
|
11
11
|
def initialize(context, options)
|
@@ -15,8 +15,8 @@ module ActiveSupport
|
|
15
15
|
private
|
16
16
|
def method_missing(method, *arguments, &block)
|
17
17
|
options = nil
|
18
|
-
if arguments.first.is_a?(Proc)
|
19
|
-
proc = arguments.
|
18
|
+
if arguments.size == 1 && arguments.first.is_a?(Proc)
|
19
|
+
proc = arguments.shift
|
20
20
|
arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
|
21
21
|
elsif arguments.last.respond_to?(:to_hash)
|
22
22
|
options = @options.deep_merge(arguments.pop)
|
@@ -24,22 +24,15 @@ module ActiveSupport
|
|
24
24
|
options = @options
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if RUBY_VERSION >= "2.7"
|
31
|
-
def invoke_method(method, arguments, options, &block)
|
32
|
-
if options
|
33
|
-
@context.__send__(method, *arguments, **options, &block)
|
34
|
-
else
|
35
|
-
@context.__send__(method, *arguments, &block)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
else
|
39
|
-
def invoke_method(method, arguments, options, &block)
|
40
|
-
arguments << options.dup if options
|
27
|
+
if options
|
28
|
+
@context.__send__(method, *arguments, **options, &block)
|
29
|
+
else
|
41
30
|
@context.__send__(method, *arguments, &block)
|
42
31
|
end
|
43
32
|
end
|
33
|
+
|
34
|
+
def respond_to_missing?(*arguments)
|
35
|
+
@context.respond_to?(*arguments)
|
36
|
+
end
|
44
37
|
end
|
45
38
|
end
|
@@ -21,7 +21,7 @@ module ActiveSupport
|
|
21
21
|
#
|
22
22
|
# <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
|
23
23
|
# with other implementations.
|
24
|
-
class OrderedHash < ::Hash
|
24
|
+
class OrderedHash < ::Hash # :nodoc:
|
25
25
|
def to_yaml_type
|
26
26
|
"!tag:yaml.org,2002:omap"
|
27
27
|
end
|