activesupport 7.2.3.1 → 8.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +584 -234
- data/lib/active_support/backtrace_cleaner.rb +72 -1
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/cache/file_store.rb +13 -2
- data/lib/active_support/cache/mem_cache_store.rb +17 -14
- data/lib/active_support/cache/memory_store.rb +9 -3
- data/lib/active_support/cache/redis_cache_store.rb +51 -34
- data/lib/active_support/cache/strategy/local_cache.rb +17 -8
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +86 -18
- data/lib/active_support/callbacks.rb +25 -11
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -3
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +0 -16
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +24 -18
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/date/conversions.rb +2 -0
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +8 -3
- data/lib/active_support/core_ext/erb/util.rb +3 -3
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/attr_internal.rb +3 -4
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +24 -11
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +2 -14
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/range/sole.rb +2 -0
- data/lib/active_support/core_ext/range.rb +4 -5
- data/lib/active_support/core_ext/string/filters.rb +2 -0
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +10 -1
- data/lib/active_support/core_ext/string/output_safety.rb +27 -13
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +11 -2
- data/lib/active_support/core_ext/time/compatibility.rb +2 -27
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +13 -10
- data/lib/active_support/delegation.rb +25 -44
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -2
- data/lib/active_support/deprecation/reporting.rb +4 -21
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration.rb +20 -16
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/error_reporter.rb +76 -2
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -2
- data/lib/active_support/execution_context.rb +75 -7
- data/lib/active_support/file_update_checker.rb +7 -5
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +44 -24
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +34 -16
- data/lib/active_support/inflector/methods.rb +6 -22
- data/lib/active_support/inflector/transliterate.rb +18 -10
- data/lib/active_support/isolated_execution_state.rb +17 -17
- data/lib/active_support/json/decoding.rb +9 -3
- data/lib/active_support/json/encoding.rb +149 -19
- data/lib/active_support/log_subscriber.rb +2 -6
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- data/lib/active_support/message_encryptors.rb +52 -0
- data/lib/active_support/message_pack/extensions.rb +23 -1
- data/lib/active_support/message_verifiers.rb +52 -0
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +5 -0
- data/lib/active_support/messages/serializer_with_fallback.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +8 -1
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +64 -43
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/notifications.rb +2 -2
- data/lib/active_support/number_helper/number_converter.rb +4 -1
- data/lib/active_support/number_helper/number_to_currency_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -4
- data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -7
- data/lib/active_support/number_helper/rounding_helper.rb +1 -1
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/ordered_options.rb +2 -2
- data/lib/active_support/railtie.rb +32 -9
- data/lib/active_support/security_utils.rb +4 -5
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +0 -5
- data/lib/active_support/syntax_error_proxy.rb +9 -1
- data/lib/active_support/tagged_logging.rb +5 -0
- data/lib/active_support/test_case.rb +67 -6
- data/lib/active_support/testing/assertions.rb +118 -27
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/error_reporter_assertions.rb +17 -0
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/worker.rb +7 -1
- data/lib/active_support/testing/parallelization.rb +17 -0
- data/lib/active_support/testing/tests_without_assertions.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +9 -4
- data/lib/active_support/time_with_zone.rb +36 -23
- data/lib/active_support/values/time_zone.rb +22 -13
- data/lib/active_support/xml_mini.rb +1 -2
- data/lib/active_support.rb +21 -9
- metadata +33 -17
- data/lib/active_support/core_ext/range/each.rb +0 -24
- data/lib/active_support/proxy_object.rb +0 -20
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module Testing
|
|
5
|
+
module NotificationAssertions
|
|
6
|
+
# Assert a notification was emitted with a given +pattern+ and optional +payload+.
|
|
7
|
+
#
|
|
8
|
+
# You can assert that a notification was emitted by passing a pattern, which accepts
|
|
9
|
+
# either a string or regexp, an optional payload, and a block. While the block
|
|
10
|
+
# is executed, if a matching notification is emitted, the assertion will pass
|
|
11
|
+
# and the notification will be returned.
|
|
12
|
+
#
|
|
13
|
+
# Note that the payload is matched as a subset, meaning that the notification must
|
|
14
|
+
# contain at least the specified keys and values, but may contain additional ones.
|
|
15
|
+
#
|
|
16
|
+
# assert_notification("post.submitted", title: "Cool Post") do
|
|
17
|
+
# post.submit(title: "Cool Post", body: "Cool Body") # => emits matching notification
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# Using the returned notification, you can make more customized assertions.
|
|
21
|
+
#
|
|
22
|
+
# notification = assert_notification("post.submitted", title: "Cool Post") do
|
|
23
|
+
# ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: Body.new("Cool Body"))
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# assert_instance_of(Body, notification.payload[:body])
|
|
27
|
+
#
|
|
28
|
+
def assert_notification(pattern, payload = nil, &block)
|
|
29
|
+
notifications = capture_notifications(pattern, &block)
|
|
30
|
+
assert_not_empty(notifications, "No #{pattern} notifications were found")
|
|
31
|
+
|
|
32
|
+
return notifications.first if payload.nil?
|
|
33
|
+
|
|
34
|
+
notification = notifications.find { |notification| notification.payload.slice(*payload.keys) == payload }
|
|
35
|
+
assert_not_nil(notification, "No #{pattern} notification with payload #{payload} was found")
|
|
36
|
+
|
|
37
|
+
notification
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Assert the number of notifications emitted with a given +pattern+.
|
|
41
|
+
#
|
|
42
|
+
# You can assert the number of notifications emitted by passing a pattern, which accepts
|
|
43
|
+
# either a string or regexp, a count, and a block. While the block is executed,
|
|
44
|
+
# the number of matching notifications emitted will be counted. After the block's
|
|
45
|
+
# execution completes, the assertion will pass if the count matches.
|
|
46
|
+
#
|
|
47
|
+
# assert_notifications_count("post.submitted", 1) do
|
|
48
|
+
# post.submit(title: "Cool Post") # => emits matching notification
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
def assert_notifications_count(pattern, count, &block)
|
|
52
|
+
actual_count = capture_notifications(pattern, &block).count
|
|
53
|
+
assert_equal(count, actual_count, "Expected #{count} instead of #{actual_count} notifications for #{pattern}")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Assert no notifications were emitted for a given +pattern+.
|
|
57
|
+
#
|
|
58
|
+
# You can assert no notifications were emitted by passing a pattern, which accepts
|
|
59
|
+
# either a string or regexp, and a block. While the block is executed, if no
|
|
60
|
+
# matching notifications are emitted, the assertion will pass.
|
|
61
|
+
#
|
|
62
|
+
# assert_no_notifications("post.submitted") do
|
|
63
|
+
# post.destroy # => emits non-matching notification
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
def assert_no_notifications(pattern = nil, &block)
|
|
67
|
+
notifications = capture_notifications(pattern, &block)
|
|
68
|
+
error_message = if pattern
|
|
69
|
+
"Expected no notifications for #{pattern} but found #{notifications.size}"
|
|
70
|
+
else
|
|
71
|
+
"Expected no notifications but found #{notifications.size}"
|
|
72
|
+
end
|
|
73
|
+
assert_empty(notifications, error_message)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Capture emitted notifications, optionally filtered by a +pattern+.
|
|
77
|
+
#
|
|
78
|
+
# You can capture emitted notifications, optionally filtered by a pattern,
|
|
79
|
+
# which accepts either a string or regexp, and a block.
|
|
80
|
+
#
|
|
81
|
+
# notifications = capture_notifications("post.submitted") do
|
|
82
|
+
# post.submit(title: "Cool Post") # => emits matching notification
|
|
83
|
+
# end
|
|
84
|
+
#
|
|
85
|
+
def capture_notifications(pattern = nil, &block)
|
|
86
|
+
notifications = []
|
|
87
|
+
ActiveSupport::Notifications.subscribed(->(n) { notifications << n }, pattern, &block)
|
|
88
|
+
notifications
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -47,7 +47,11 @@ module ActiveSupport
|
|
|
47
47
|
set_process_title("#{klass}##{method}")
|
|
48
48
|
|
|
49
49
|
result = klass.with_info_handler reporter do
|
|
50
|
-
Minitest.run_one_method
|
|
50
|
+
if Minitest.respond_to? :run_one_method
|
|
51
|
+
Minitest.run_one_method klass, method
|
|
52
|
+
else
|
|
53
|
+
klass.new(method).run
|
|
54
|
+
end
|
|
51
55
|
end
|
|
52
56
|
|
|
53
57
|
safe_record(reporter, result)
|
|
@@ -78,6 +82,8 @@ module ActiveSupport
|
|
|
78
82
|
end
|
|
79
83
|
|
|
80
84
|
def after_fork
|
|
85
|
+
ActiveSupport::TestCase.parallel_worker_id = @number
|
|
86
|
+
|
|
81
87
|
Parallelization.after_fork_hooks.each do |cb|
|
|
82
88
|
cb.call(@number)
|
|
83
89
|
end
|
|
@@ -9,6 +9,14 @@ require "active_support/testing/parallelization/worker"
|
|
|
9
9
|
module ActiveSupport
|
|
10
10
|
module Testing
|
|
11
11
|
class Parallelization # :nodoc:
|
|
12
|
+
@@before_fork_hooks = []
|
|
13
|
+
|
|
14
|
+
def self.before_fork_hook(&blk)
|
|
15
|
+
@@before_fork_hooks << blk
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
cattr_reader :before_fork_hooks
|
|
19
|
+
|
|
12
20
|
@@after_fork_hooks = []
|
|
13
21
|
|
|
14
22
|
def self.after_fork_hook(&blk)
|
|
@@ -32,7 +40,12 @@ module ActiveSupport
|
|
|
32
40
|
@url = DRb.start_service("drbunix:", @queue_server).uri
|
|
33
41
|
end
|
|
34
42
|
|
|
43
|
+
def before_fork
|
|
44
|
+
Parallelization.before_fork_hooks.each(&:call)
|
|
45
|
+
end
|
|
46
|
+
|
|
35
47
|
def start
|
|
48
|
+
before_fork
|
|
36
49
|
@worker_pool = @worker_count.times.map do |worker|
|
|
37
50
|
Worker.new(worker, @url).start
|
|
38
51
|
end
|
|
@@ -60,6 +73,10 @@ module ActiveSupport
|
|
|
60
73
|
rescue Errno::ECHILD
|
|
61
74
|
nil
|
|
62
75
|
end
|
|
76
|
+
|
|
77
|
+
DRb.stop_service
|
|
78
|
+
|
|
79
|
+
Parallelization.run_cleanup_hooks.each(&:call)
|
|
63
80
|
end
|
|
64
81
|
end
|
|
65
82
|
end
|
|
@@ -11,7 +11,7 @@ module ActiveSupport
|
|
|
11
11
|
|
|
12
12
|
if assertions.zero? && !skipped? && !error?
|
|
13
13
|
file, line = method(name).source_location
|
|
14
|
-
warn "Test is missing assertions: `#{name}` #{file}:#{line}"
|
|
14
|
+
warn "Test is missing assertions: `#{name}` #{File.expand_path(file)}:#{line}"
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -166,9 +166,10 @@ module ActiveSupport
|
|
|
166
166
|
else
|
|
167
167
|
now = date_or_time
|
|
168
168
|
now = now.to_time unless now.is_a?(Time)
|
|
169
|
-
now = now.change(usec: 0) unless with_usec
|
|
170
169
|
end
|
|
171
170
|
|
|
171
|
+
now = now.change(usec: 0) unless with_usec
|
|
172
|
+
|
|
172
173
|
# +now+ must be in local system timezone, because +Time.at(now)+
|
|
173
174
|
# and +now.to_date+ (see stubs below) will use +now+'s timezone too!
|
|
174
175
|
now = now.getlocal
|
|
@@ -237,12 +238,16 @@ module ActiveSupport
|
|
|
237
238
|
end
|
|
238
239
|
alias_method :unfreeze_time, :travel_back
|
|
239
240
|
|
|
240
|
-
# Calls +travel_to+ with +
|
|
241
|
+
# Calls +travel_to+ with +date_or_time+, which defaults to +Time.now+.
|
|
242
|
+
# Forwards optional <tt>with_usec</tt> argument.
|
|
241
243
|
#
|
|
242
244
|
# Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
|
|
243
245
|
# freeze_time
|
|
244
246
|
# sleep(1)
|
|
245
247
|
# Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
|
|
248
|
+
# freeze_time Time.current + 1.day
|
|
249
|
+
# sleep(1)
|
|
250
|
+
# Time.current # => Mon, 10 Jul 2017 15:34:49 EST -05:00
|
|
246
251
|
#
|
|
247
252
|
# This method also accepts a block, which will return the current time back to its original
|
|
248
253
|
# state at the end of the block:
|
|
@@ -253,8 +258,8 @@ module ActiveSupport
|
|
|
253
258
|
# User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00
|
|
254
259
|
# end
|
|
255
260
|
# Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00
|
|
256
|
-
def freeze_time(with_usec: false, &block)
|
|
257
|
-
travel_to
|
|
261
|
+
def freeze_time(date_or_time = Time.now, with_usec: false, &block)
|
|
262
|
+
travel_to date_or_time, with_usec: with_usec, &block
|
|
258
263
|
end
|
|
259
264
|
|
|
260
265
|
private
|
|
@@ -49,9 +49,15 @@ module ActiveSupport
|
|
|
49
49
|
attr_reader :time_zone
|
|
50
50
|
|
|
51
51
|
def initialize(utc_time, time_zone, local_time = nil, period = nil)
|
|
52
|
-
@utc = utc_time ? transfer_time_values_to_utc_constructor(utc_time) : nil
|
|
53
52
|
@time_zone, @time = time_zone, local_time
|
|
54
|
-
|
|
53
|
+
if utc_time
|
|
54
|
+
@utc = transfer_time_values_to_utc_constructor(utc_time)
|
|
55
|
+
@period = period
|
|
56
|
+
else
|
|
57
|
+
@utc = nil
|
|
58
|
+
@period = get_period_and_ensure_valid_local_time(period)
|
|
59
|
+
end
|
|
60
|
+
@is_utc = zone == "UTC" || zone == "UCT"
|
|
55
61
|
end
|
|
56
62
|
|
|
57
63
|
# Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
|
|
@@ -103,7 +109,7 @@ module ActiveSupport
|
|
|
103
109
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
|
104
110
|
# Time.zone.now.utc? # => false
|
|
105
111
|
def utc?
|
|
106
|
-
|
|
112
|
+
@is_utc
|
|
107
113
|
end
|
|
108
114
|
alias_method :gmt?, :utc?
|
|
109
115
|
|
|
@@ -136,9 +142,9 @@ module ActiveSupport
|
|
|
136
142
|
|
|
137
143
|
# Returns a string of the object's date, time, zone, and offset from UTC.
|
|
138
144
|
#
|
|
139
|
-
# Time.zone.now.inspect # => "
|
|
145
|
+
# Time.zone.now.inspect # => "2024-11-13 07:00:10.528054960 UTC +00:00"
|
|
140
146
|
def inspect
|
|
141
|
-
"#{time.strftime('%
|
|
147
|
+
"#{time.strftime('%F %H:%M:%S.%9N')} #{zone} #{formatted_offset}"
|
|
142
148
|
end
|
|
143
149
|
|
|
144
150
|
# Returns a string of the object's date and time in the ISO 8601 standard
|
|
@@ -146,7 +152,17 @@ module ActiveSupport
|
|
|
146
152
|
#
|
|
147
153
|
# Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
|
|
148
154
|
def xmlschema(fraction_digits = 0)
|
|
149
|
-
|
|
155
|
+
precision = fraction_digits || 0
|
|
156
|
+
|
|
157
|
+
if @is_utc
|
|
158
|
+
utc.iso8601(precision)
|
|
159
|
+
else
|
|
160
|
+
str = time.iso8601(precision)
|
|
161
|
+
offset = formatted_offset(true, "Z")
|
|
162
|
+
|
|
163
|
+
str.sub!(/(Z|[+-]\d{2}:\d{2})\z/, offset)
|
|
164
|
+
str
|
|
165
|
+
end
|
|
150
166
|
end
|
|
151
167
|
alias_method :iso8601, :xmlschema
|
|
152
168
|
alias_method :rfc3339, :xmlschema
|
|
@@ -157,15 +173,15 @@ module ActiveSupport
|
|
|
157
173
|
# to +false+.
|
|
158
174
|
#
|
|
159
175
|
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
|
|
160
|
-
# Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").
|
|
176
|
+
# Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").as_json
|
|
161
177
|
# # => "2005-02-01T05:15:10.000-10:00"
|
|
162
178
|
#
|
|
163
179
|
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
|
|
164
|
-
# Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").
|
|
180
|
+
# Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").as_json
|
|
165
181
|
# # => "2005/02/01 05:15:10 -1000"
|
|
166
182
|
def as_json(options = nil)
|
|
167
183
|
if ActiveSupport::JSON::Encoding.use_standard_json_time_format
|
|
168
|
-
xmlschema(ActiveSupport::JSON::Encoding.time_precision)
|
|
184
|
+
xmlschema(ActiveSupport::JSON::Encoding.time_precision).force_encoding(Encoding::UTF_8)
|
|
169
185
|
else
|
|
170
186
|
%(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
|
|
171
187
|
end
|
|
@@ -215,8 +231,7 @@ module ActiveSupport
|
|
|
215
231
|
elsif formatter = ::Time::DATE_FORMATS[format]
|
|
216
232
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
|
217
233
|
else
|
|
218
|
-
|
|
219
|
-
"#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}"
|
|
234
|
+
to_s
|
|
220
235
|
end
|
|
221
236
|
end
|
|
222
237
|
alias_method :to_formatted_s, :to_fs
|
|
@@ -300,7 +315,8 @@ module ActiveSupport
|
|
|
300
315
|
if duration_of_variable_length?(other)
|
|
301
316
|
method_missing(:+, other)
|
|
302
317
|
else
|
|
303
|
-
result = utc
|
|
318
|
+
result = utc + other
|
|
319
|
+
|
|
304
320
|
result.in_time_zone(time_zone)
|
|
305
321
|
end
|
|
306
322
|
end
|
|
@@ -336,7 +352,7 @@ module ActiveSupport
|
|
|
336
352
|
elsif duration_of_variable_length?(other)
|
|
337
353
|
method_missing(:-, other)
|
|
338
354
|
else
|
|
339
|
-
result = utc
|
|
355
|
+
result = utc - other
|
|
340
356
|
result.in_time_zone(time_zone)
|
|
341
357
|
end
|
|
342
358
|
end
|
|
@@ -479,15 +495,11 @@ module ActiveSupport
|
|
|
479
495
|
@to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
|
|
480
496
|
end
|
|
481
497
|
|
|
482
|
-
# Returns an instance of +Time+, either with the same
|
|
483
|
-
# as +self+ or in the local system timezone
|
|
484
|
-
# of +ActiveSupport.to_time_preserves_timezone+.
|
|
498
|
+
# Returns an instance of +Time+, either with the same timezone as +self+,
|
|
499
|
+
# with the same UTC offset as +self+ or in the local system timezone
|
|
500
|
+
# depending on the setting of +ActiveSupport.to_time_preserves_timezone+.
|
|
485
501
|
def to_time
|
|
486
|
-
|
|
487
|
-
@to_time_with_instance_offset ||= getlocal(utc_offset)
|
|
488
|
-
else
|
|
489
|
-
@to_time_with_system_offset ||= getlocal
|
|
490
|
-
end
|
|
502
|
+
@to_time_with_timezone ||= getlocal(time_zone)
|
|
491
503
|
end
|
|
492
504
|
|
|
493
505
|
# So that +self+ <tt>acts_like?(:time)</tt>.
|
|
@@ -535,7 +547,6 @@ module ActiveSupport
|
|
|
535
547
|
# Ensure proxy class responds to all methods that underlying time instance
|
|
536
548
|
# responds to.
|
|
537
549
|
def respond_to_missing?(sym, include_priv)
|
|
538
|
-
return false if sym.to_sym == :acts_like_date?
|
|
539
550
|
time.respond_to?(sym, include_priv)
|
|
540
551
|
end
|
|
541
552
|
|
|
@@ -551,7 +562,9 @@ module ActiveSupport
|
|
|
551
562
|
SECONDS_PER_DAY = 86400
|
|
552
563
|
|
|
553
564
|
def incorporate_utc_offset(time, offset)
|
|
554
|
-
if
|
|
565
|
+
if offset.zero?
|
|
566
|
+
time
|
|
567
|
+
elsif time.kind_of?(Date)
|
|
555
568
|
time + Rational(offset, SECONDS_PER_DAY)
|
|
556
569
|
else
|
|
557
570
|
time + offset
|
|
@@ -57,13 +57,14 @@ module ActiveSupport
|
|
|
57
57
|
"Caracas" => "America/Caracas",
|
|
58
58
|
"La Paz" => "America/La_Paz",
|
|
59
59
|
"Santiago" => "America/Santiago",
|
|
60
|
+
"Asuncion" => "America/Asuncion",
|
|
60
61
|
"Newfoundland" => "America/St_Johns",
|
|
61
62
|
"Brasilia" => "America/Sao_Paulo",
|
|
62
63
|
"Buenos Aires" => "America/Argentina/Buenos_Aires",
|
|
63
64
|
"Montevideo" => "America/Montevideo",
|
|
64
65
|
"Georgetown" => "America/Guyana",
|
|
65
66
|
"Puerto Rico" => "America/Puerto_Rico",
|
|
66
|
-
"Greenland" => "America/
|
|
67
|
+
"Greenland" => "America/Nuuk",
|
|
67
68
|
"Mid-Atlantic" => "Atlantic/South_Georgia",
|
|
68
69
|
"Azores" => "Atlantic/Azores",
|
|
69
70
|
"Cape Verde Is." => "Atlantic/Cape_Verde",
|
|
@@ -98,7 +99,7 @@ module ActiveSupport
|
|
|
98
99
|
"Bucharest" => "Europe/Bucharest",
|
|
99
100
|
"Cairo" => "Africa/Cairo",
|
|
100
101
|
"Helsinki" => "Europe/Helsinki",
|
|
101
|
-
"Kyiv" => "Europe/
|
|
102
|
+
"Kyiv" => "Europe/Kyiv",
|
|
102
103
|
"Riga" => "Europe/Riga",
|
|
103
104
|
"Sofia" => "Europe/Sofia",
|
|
104
105
|
"Tallinn" => "Europe/Tallinn",
|
|
@@ -139,7 +140,7 @@ module ActiveSupport
|
|
|
139
140
|
"Almaty" => "Asia/Almaty",
|
|
140
141
|
"Astana" => "Asia/Almaty",
|
|
141
142
|
"Novosibirsk" => "Asia/Novosibirsk",
|
|
142
|
-
"Rangoon" => "Asia/
|
|
143
|
+
"Rangoon" => "Asia/Yangon",
|
|
143
144
|
"Bangkok" => "Asia/Bangkok",
|
|
144
145
|
"Hanoi" => "Asia/Bangkok",
|
|
145
146
|
"Jakarta" => "Asia/Jakarta",
|
|
@@ -208,9 +209,7 @@ module ActiveSupport
|
|
|
208
209
|
TZInfo::Timezone.get(MAPPING[name] || name)
|
|
209
210
|
end
|
|
210
211
|
|
|
211
|
-
# :
|
|
212
|
-
alias_method :create, :new
|
|
213
|
-
# :startdoc:
|
|
212
|
+
alias_method :create, :new # :nodoc:
|
|
214
213
|
|
|
215
214
|
# Returns a TimeZone instance with the given name, or +nil+ if no
|
|
216
215
|
# such TimeZone instance exists. (This exists to support the use of
|
|
@@ -315,6 +314,12 @@ module ActiveSupport
|
|
|
315
314
|
end
|
|
316
315
|
# :startdoc:
|
|
317
316
|
|
|
317
|
+
# Returns a standard time zone name defined by IANA
|
|
318
|
+
# https://www.iana.org/time-zones
|
|
319
|
+
def standard_name
|
|
320
|
+
MAPPING[name] || name
|
|
321
|
+
end
|
|
322
|
+
|
|
318
323
|
# Returns the offset of this time zone from UTC in seconds.
|
|
319
324
|
def utc_offset
|
|
320
325
|
@utc_offset || tzinfo&.current_period&.base_utc_offset
|
|
@@ -554,15 +559,11 @@ module ActiveSupport
|
|
|
554
559
|
tzinfo.local_to_utc(time, dst)
|
|
555
560
|
end
|
|
556
561
|
|
|
557
|
-
|
|
558
|
-
# instances.
|
|
559
|
-
def period_for_utc(time)
|
|
562
|
+
def period_for_utc(time) # :nodoc:
|
|
560
563
|
tzinfo.period_for_utc(time)
|
|
561
564
|
end
|
|
562
565
|
|
|
563
|
-
|
|
564
|
-
# instances.
|
|
565
|
-
def period_for_local(time, dst = true)
|
|
566
|
+
def period_for_local(time, dst = true) # :nodoc:
|
|
566
567
|
tzinfo.period_for_local(time, dst) { |periods| periods.last }
|
|
567
568
|
end
|
|
568
569
|
|
|
@@ -570,6 +571,14 @@ module ActiveSupport
|
|
|
570
571
|
tzinfo.periods_for_local(time)
|
|
571
572
|
end
|
|
572
573
|
|
|
574
|
+
def abbr(time) # :nodoc:
|
|
575
|
+
tzinfo.abbr(time)
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
def dst?(time) # :nodoc:
|
|
579
|
+
tzinfo.dst?(time)
|
|
580
|
+
end
|
|
581
|
+
|
|
573
582
|
def init_with(coder) # :nodoc:
|
|
574
583
|
initialize(coder["name"])
|
|
575
584
|
end
|
|
@@ -585,7 +594,7 @@ module ActiveSupport
|
|
|
585
594
|
return if parts.empty?
|
|
586
595
|
|
|
587
596
|
if parts[:seconds]
|
|
588
|
-
time = Time.at(parts[:seconds])
|
|
597
|
+
time = Time.at(parts[:seconds] + parts.fetch(:sec_fraction, 0))
|
|
589
598
|
else
|
|
590
599
|
time = Time.new(
|
|
591
600
|
parts.fetch(:year, now.year),
|
|
@@ -62,11 +62,10 @@ module ActiveSupport
|
|
|
62
62
|
"yaml" => Proc.new { |yaml| yaml.to_yaml }
|
|
63
63
|
} unless defined?(FORMATTING)
|
|
64
64
|
|
|
65
|
-
# TODO use regexp instead of Date.parse
|
|
66
65
|
unless defined?(PARSING)
|
|
67
66
|
PARSING = {
|
|
68
67
|
"symbol" => Proc.new { |symbol| symbol.to_s.to_sym },
|
|
69
|
-
"date" => Proc.new { |date| ::Date.
|
|
68
|
+
"date" => Proc.new { |date| ::Date.strptime(date.to_s.strip, "%Y-%m-%d") },
|
|
70
69
|
"datetime" => Proc.new { |time| Time.xmlschema(time).utc rescue ::DateTime.parse(time).utc },
|
|
71
70
|
"duration" => Proc.new { |duration| Duration.parse(duration) },
|
|
72
71
|
"integer" => Proc.new { |integer| integer.to_i },
|
data/lib/active_support.rb
CHANGED
|
@@ -39,17 +39,22 @@ module ActiveSupport
|
|
|
39
39
|
autoload :Concern
|
|
40
40
|
autoload :CodeGenerator
|
|
41
41
|
autoload :ActionableError
|
|
42
|
+
autoload :Configurable
|
|
42
43
|
autoload :ConfigurationFile
|
|
44
|
+
autoload :ContinuousIntegration
|
|
43
45
|
autoload :CurrentAttributes
|
|
44
46
|
autoload :Dependencies
|
|
45
47
|
autoload :DescendantsTracker
|
|
48
|
+
autoload :Editor
|
|
46
49
|
autoload :ExecutionWrapper
|
|
47
50
|
autoload :Executor
|
|
48
51
|
autoload :ErrorReporter
|
|
52
|
+
autoload :EventReporter
|
|
49
53
|
autoload :FileUpdateChecker
|
|
50
54
|
autoload :EventedFileUpdateChecker
|
|
51
55
|
autoload :ForkTracker
|
|
52
56
|
autoload :LogSubscriber
|
|
57
|
+
autoload :StructuredEventSubscriber
|
|
53
58
|
autoload :IsolatedExecutionState
|
|
54
59
|
autoload :Notifications
|
|
55
60
|
autoload :Reloader
|
|
@@ -57,11 +62,11 @@ module ActiveSupport
|
|
|
57
62
|
|
|
58
63
|
eager_autoload do
|
|
59
64
|
autoload :BacktraceCleaner
|
|
60
|
-
autoload :
|
|
65
|
+
autoload :Benchmark
|
|
61
66
|
autoload :Benchmarkable
|
|
62
67
|
autoload :Cache
|
|
63
68
|
autoload :Callbacks
|
|
64
|
-
autoload :
|
|
69
|
+
autoload :ClassAttribute
|
|
65
70
|
autoload :Deprecation
|
|
66
71
|
autoload :Delegation
|
|
67
72
|
autoload :Digest
|
|
@@ -98,10 +103,16 @@ module ActiveSupport
|
|
|
98
103
|
|
|
99
104
|
cattr_accessor :test_order # :nodoc:
|
|
100
105
|
cattr_accessor :test_parallelization_threshold, default: 50 # :nodoc:
|
|
106
|
+
cattr_accessor :parallelize_test_databases, default: true # :nodoc:
|
|
101
107
|
|
|
102
108
|
@error_reporter = ActiveSupport::ErrorReporter.new
|
|
103
109
|
singleton_class.attr_accessor :error_reporter # :nodoc:
|
|
104
110
|
|
|
111
|
+
@event_reporter = ActiveSupport::EventReporter.new
|
|
112
|
+
singleton_class.attr_accessor :event_reporter # :nodoc:
|
|
113
|
+
|
|
114
|
+
cattr_accessor :filter_parameters, default: [] # :nodoc:
|
|
115
|
+
|
|
105
116
|
def self.cache_format_version
|
|
106
117
|
Cache.format_version
|
|
107
118
|
end
|
|
@@ -111,17 +122,18 @@ module ActiveSupport
|
|
|
111
122
|
end
|
|
112
123
|
|
|
113
124
|
def self.to_time_preserves_timezone
|
|
114
|
-
|
|
125
|
+
ActiveSupport.deprecator.warn(
|
|
126
|
+
"`config.active_support.to_time_preserves_timezone` is deprecated and will be removed in Rails 8.2"
|
|
127
|
+
)
|
|
128
|
+
@to_time_preserves_timezone
|
|
115
129
|
end
|
|
116
130
|
|
|
117
131
|
def self.to_time_preserves_timezone=(value)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
end
|
|
132
|
+
ActiveSupport.deprecator.warn(
|
|
133
|
+
"`config.active_support.to_time_preserves_timezone` is deprecated and will be removed in Rails 8.2"
|
|
134
|
+
)
|
|
123
135
|
|
|
124
|
-
|
|
136
|
+
@to_time_preserves_timezone = value
|
|
125
137
|
end
|
|
126
138
|
|
|
127
139
|
def self.utc_to_local_returns_utc_offset_times
|