activesupport 8.0.2.1 → 8.1.0.beta1
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 +247 -136
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +71 -0
- data/lib/active_support/broadcast_logger.rb +46 -59
- data/lib/active_support/cache/mem_cache_store.rb +25 -27
- data/lib/active_support/cache/redis_cache_store.rb +36 -30
- data/lib/active_support/cache/strategy/local_cache.rb +16 -7
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +70 -6
- data/lib/active_support/configurable.rb +28 -0
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/enumerable.rb +16 -4
- data/lib/active_support/core_ext/erb/util.rb +3 -3
- data/lib/active_support/core_ext/object/json.rb +8 -1
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/multibyte.rb +12 -3
- data/lib/active_support/core_ext/string/output_safety.rb +19 -12
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +26 -16
- data/lib/active_support/deprecation/reporting.rb +4 -2
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/error_reporter.rb +50 -6
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +570 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -1
- data/lib/active_support/execution_context.rb +64 -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 +47 -24
- data/lib/active_support/i18n_railtie.rb +1 -2
- data/lib/active_support/inflector/inflections.rb +31 -15
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +7 -13
- data/lib/active_support/json/decoding.rb +6 -4
- data/lib/active_support/json/encoding.rb +103 -14
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +2 -0
- 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 +5 -0
- 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/multibyte/chars.rb +8 -1
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/railtie.rb +26 -12
- data/lib/active_support/syntax_error_proxy.rb +3 -0
- data/lib/active_support/test_case.rb +61 -6
- data/lib/active_support/testing/assertions.rb +34 -6
- data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
- data/lib/active_support/testing/event_reporter_assertions.rb +217 -0
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/worker.rb +2 -0
- data/lib/active_support/testing/parallelization.rb +13 -0
- data/lib/active_support/testing/tests_without_assertions.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +7 -3
- data/lib/active_support/time_with_zone.rb +19 -5
- data/lib/active_support/values/time_zone.rb +8 -1
- data/lib/active_support/xml_mini.rb +1 -2
- data/lib/active_support.rb +11 -0
- metadata +11 -5
- data/lib/active_support/core_ext/range/each.rb +0 -24
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Testing
|
5
|
+
# Provides test helpers for asserting on ActiveSupport::EventReporter events.
|
6
|
+
module EventReporterAssertions
|
7
|
+
module EventCollector # :nodoc:
|
8
|
+
@subscribed = false
|
9
|
+
@mutex = Mutex.new
|
10
|
+
|
11
|
+
class Event # :nodoc:
|
12
|
+
attr_reader :event_data
|
13
|
+
|
14
|
+
def initialize(event_data)
|
15
|
+
@event_data = event_data
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
"#{event_data[:name]} (payload: #{event_data[:payload].inspect}, tags: #{event_data[:tags].inspect})"
|
20
|
+
end
|
21
|
+
|
22
|
+
def matches?(name, payload, tags)
|
23
|
+
return false unless name.to_s == event_data[:name]
|
24
|
+
|
25
|
+
if payload && payload.is_a?(Hash)
|
26
|
+
return false unless matches_hash?(payload, :payload)
|
27
|
+
end
|
28
|
+
|
29
|
+
return false unless matches_hash?(tags, :tags)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def matches_hash?(expected_hash, event_key)
|
35
|
+
expected_hash.all? do |k, v|
|
36
|
+
if v.is_a?(Regexp)
|
37
|
+
event_data.dig(event_key, k).to_s.match?(v)
|
38
|
+
else
|
39
|
+
event_data.dig(event_key, k) == v
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
def emit(event)
|
47
|
+
event_recorders&.each do |events|
|
48
|
+
events << Event.new(event)
|
49
|
+
end
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def record
|
54
|
+
subscribe
|
55
|
+
events = []
|
56
|
+
event_recorders << events
|
57
|
+
begin
|
58
|
+
yield
|
59
|
+
events
|
60
|
+
ensure
|
61
|
+
event_recorders.delete_if { |r| events.equal?(r) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def subscribe
|
67
|
+
return if @subscribed
|
68
|
+
|
69
|
+
@mutex.synchronize do
|
70
|
+
unless @subscribed
|
71
|
+
if ActiveSupport.event_reporter
|
72
|
+
ActiveSupport.event_reporter.subscribe(self)
|
73
|
+
@subscribed = true
|
74
|
+
else
|
75
|
+
raise Minitest::Assertion, "No event reporter is configured"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def event_recorders
|
82
|
+
ActiveSupport::IsolatedExecutionState[:active_support_event_reporter_assertions] ||= []
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Asserts that the block does not cause an event to be reported to +Rails.event+.
|
88
|
+
#
|
89
|
+
# If no name is provided, passes if evaluated code in the yielded block reports no events.
|
90
|
+
#
|
91
|
+
# assert_no_event_reported do
|
92
|
+
# service_that_does_not_report_events.perform
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# If a name is provided, passes if evaluated code in the yielded block reports no events
|
96
|
+
# with that name.
|
97
|
+
#
|
98
|
+
# assert_no_event_reported("user.created") do
|
99
|
+
# service_that_does_not_report_events.perform
|
100
|
+
# end
|
101
|
+
def assert_no_event_reported(name = nil, payload: {}, tags: {}, &block)
|
102
|
+
events = EventCollector.record(&block)
|
103
|
+
|
104
|
+
if name.nil?
|
105
|
+
assert_predicate(events, :empty?)
|
106
|
+
else
|
107
|
+
matching_event = events.find { |event| event.matches?(name, payload, tags) }
|
108
|
+
if matching_event
|
109
|
+
message = "Expected no '#{name}' event to be reported, but found:\n " \
|
110
|
+
"#{matching_event.inspect}"
|
111
|
+
flunk(message)
|
112
|
+
end
|
113
|
+
assert(true)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Asserts that the block causes an event with the given name to be reported
|
118
|
+
# to +Rails.event+.
|
119
|
+
#
|
120
|
+
# Passes if the evaluated code in the yielded block reports a matching event.
|
121
|
+
#
|
122
|
+
# assert_event_reported("user.created") do
|
123
|
+
# Rails.event.notify("user.created", { id: 123 })
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# To test further details about the reported event, you can specify payload and tag matchers.
|
127
|
+
#
|
128
|
+
# assert_event_reported("user.created",
|
129
|
+
# payload: { id: 123, name: "John Doe" },
|
130
|
+
# tags: { request_id: /[0-9]+/ }
|
131
|
+
# ) do
|
132
|
+
# Rails.event.tagged(request_id: "123") do
|
133
|
+
# Rails.event.notify("user.created", { id: 123, name: "John Doe" })
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# The matchers support partial matching - only the specified keys need to match.
|
138
|
+
#
|
139
|
+
# assert_event_reported("user.created", payload: { id: 123 }) do
|
140
|
+
# Rails.event.notify("user.created", { id: 123, name: "John Doe" })
|
141
|
+
# end
|
142
|
+
def assert_event_reported(name, payload: nil, tags: {}, &block)
|
143
|
+
events = EventCollector.record(&block)
|
144
|
+
|
145
|
+
if events.empty?
|
146
|
+
flunk("Expected an event to be reported, but there were no events reported.")
|
147
|
+
elsif (event = events.find { |event| event.matches?(name, payload, tags) })
|
148
|
+
assert(true)
|
149
|
+
event.event_data
|
150
|
+
else
|
151
|
+
message = "Expected an event to be reported matching:\n " \
|
152
|
+
"name: #{name}\n " \
|
153
|
+
"payload: #{payload.inspect}\n " \
|
154
|
+
"tags: #{tags.inspect}\n" \
|
155
|
+
"but none of the #{events.size} reported events matched:\n " \
|
156
|
+
"#{events.map(&:inspect).join("\n ")}"
|
157
|
+
flunk(message)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Asserts that the provided events were reported, regardless of order.
|
162
|
+
#
|
163
|
+
# assert_events_reported([
|
164
|
+
# { name: "user.created", payload: { id: 123 } },
|
165
|
+
# { name: "email.sent", payload: { to: "user@example.com" } }
|
166
|
+
# ]) do
|
167
|
+
# create_user_and_send_welcome_email
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# Supports the same payload and tag matching as +assert_event_reported+.
|
171
|
+
#
|
172
|
+
# assert_events_reported([
|
173
|
+
# {
|
174
|
+
# name: "process.started",
|
175
|
+
# payload: { id: 123 },
|
176
|
+
# tags: { request_id: /[0-9]+/ }
|
177
|
+
# },
|
178
|
+
# { name: "process.completed" }
|
179
|
+
# ]) do
|
180
|
+
# Rails.event.tagged(request_id: "456") do
|
181
|
+
# start_and_complete_process(123)
|
182
|
+
# end
|
183
|
+
# end
|
184
|
+
def assert_events_reported(expected_events, &block)
|
185
|
+
events = EventCollector.record(&block)
|
186
|
+
|
187
|
+
if events.empty? && expected_events.size > 0
|
188
|
+
flunk("Expected #{expected_events.size} events to be reported, but there were no events reported.")
|
189
|
+
end
|
190
|
+
|
191
|
+
events_copy = events.dup
|
192
|
+
|
193
|
+
expected_events.each do |expected_event|
|
194
|
+
name = expected_event[:name]
|
195
|
+
payload = expected_event[:payload] || {}
|
196
|
+
tags = expected_event[:tags] || {}
|
197
|
+
|
198
|
+
matching_event_index = events_copy.find_index { |event| event.matches?(name, payload, tags) }
|
199
|
+
|
200
|
+
if matching_event_index
|
201
|
+
events_copy.delete_at(matching_event_index)
|
202
|
+
else
|
203
|
+
message = "Expected an event to be reported matching:\n " \
|
204
|
+
"name: #{name.inspect}\n " \
|
205
|
+
"payload: #{payload.inspect}\n " \
|
206
|
+
"tags: #{tags.inspect}\n" \
|
207
|
+
"but none of the #{events.size} reported events matched:\n " \
|
208
|
+
"#{events.map(&:inspect).join("\n ")}"
|
209
|
+
flunk(message)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
assert(true)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -238,12 +238,16 @@ module ActiveSupport
|
|
238
238
|
end
|
239
239
|
alias_method :unfreeze_time, :travel_back
|
240
240
|
|
241
|
-
# 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.
|
242
243
|
#
|
243
244
|
# Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
|
244
245
|
# freeze_time
|
245
246
|
# sleep(1)
|
246
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
|
247
251
|
#
|
248
252
|
# This method also accepts a block, which will return the current time back to its original
|
249
253
|
# state at the end of the block:
|
@@ -254,8 +258,8 @@ module ActiveSupport
|
|
254
258
|
# User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00
|
255
259
|
# end
|
256
260
|
# Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00
|
257
|
-
def freeze_time(with_usec: false, &block)
|
258
|
-
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
|
259
263
|
end
|
260
264
|
|
261
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
|
|
@@ -146,7 +152,13 @@ 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
|
+
if @is_utc
|
156
|
+
utc.iso8601(fraction_digits || 0)
|
157
|
+
else
|
158
|
+
str = time.iso8601(fraction_digits || 0)
|
159
|
+
str[-1] = formatted_offset(true, "Z")
|
160
|
+
str
|
161
|
+
end
|
150
162
|
end
|
151
163
|
alias_method :iso8601, :xmlschema
|
152
164
|
alias_method :rfc3339, :xmlschema
|
@@ -560,7 +572,9 @@ module ActiveSupport
|
|
560
572
|
SECONDS_PER_DAY = 86400
|
561
573
|
|
562
574
|
def incorporate_utc_offset(time, offset)
|
563
|
-
if
|
575
|
+
if offset.zero?
|
576
|
+
time
|
577
|
+
elsif time.kind_of?(Date)
|
564
578
|
time + Rational(offset, SECONDS_PER_DAY)
|
565
579
|
else
|
566
580
|
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",
|
@@ -313,6 +314,12 @@ module ActiveSupport
|
|
313
314
|
end
|
314
315
|
# :startdoc:
|
315
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
|
+
|
316
323
|
# Returns the offset of this time zone from UTC in seconds.
|
317
324
|
def utc_offset
|
318
325
|
@utc_offset || tzinfo&.current_period&.base_utc_offset
|
@@ -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, "%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
@@ -40,12 +40,15 @@ module ActiveSupport
|
|
40
40
|
autoload :CodeGenerator
|
41
41
|
autoload :ActionableError
|
42
42
|
autoload :ConfigurationFile
|
43
|
+
autoload :ContinuousIntegration
|
43
44
|
autoload :CurrentAttributes
|
44
45
|
autoload :Dependencies
|
45
46
|
autoload :DescendantsTracker
|
47
|
+
autoload :Editor
|
46
48
|
autoload :ExecutionWrapper
|
47
49
|
autoload :Executor
|
48
50
|
autoload :ErrorReporter
|
51
|
+
autoload :EventReporter
|
49
52
|
autoload :FileUpdateChecker
|
50
53
|
autoload :EventedFileUpdateChecker
|
51
54
|
autoload :ForkTracker
|
@@ -91,6 +94,10 @@ module ActiveSupport
|
|
91
94
|
autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
|
92
95
|
autoload :TestCase
|
93
96
|
|
97
|
+
include Deprecation::DeprecatedConstantAccessor
|
98
|
+
|
99
|
+
deprecate_constant :Configurable, "class_attribute :config, default: {}", deprecator: ActiveSupport.deprecator
|
100
|
+
|
94
101
|
def self.eager_load!
|
95
102
|
super
|
96
103
|
|
@@ -99,10 +106,14 @@ module ActiveSupport
|
|
99
106
|
|
100
107
|
cattr_accessor :test_order # :nodoc:
|
101
108
|
cattr_accessor :test_parallelization_threshold, default: 50 # :nodoc:
|
109
|
+
cattr_accessor :parallelize_test_databases, default: true # :nodoc:
|
102
110
|
|
103
111
|
@error_reporter = ActiveSupport::ErrorReporter.new
|
104
112
|
singleton_class.attr_accessor :error_reporter # :nodoc:
|
105
113
|
|
114
|
+
@event_reporter = ActiveSupport::EventReporter.new
|
115
|
+
singleton_class.attr_accessor :event_reporter # :nodoc:
|
116
|
+
|
106
117
|
def self.cache_format_version
|
107
118
|
Cache.format_version
|
108
119
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activesupport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.0.
|
4
|
+
version: 8.1.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
@@ -235,6 +235,7 @@ files:
|
|
235
235
|
- lib/active_support/concurrency/share_lock.rb
|
236
236
|
- lib/active_support/configurable.rb
|
237
237
|
- lib/active_support/configuration_file.rb
|
238
|
+
- lib/active_support/continuous_integration.rb
|
238
239
|
- lib/active_support/core_ext.rb
|
239
240
|
- lib/active_support/core_ext/array.rb
|
240
241
|
- lib/active_support/core_ext/array/access.rb
|
@@ -327,8 +328,8 @@ files:
|
|
327
328
|
- lib/active_support/core_ext/range.rb
|
328
329
|
- lib/active_support/core_ext/range/compare_range.rb
|
329
330
|
- lib/active_support/core_ext/range/conversions.rb
|
330
|
-
- lib/active_support/core_ext/range/each.rb
|
331
331
|
- lib/active_support/core_ext/range/overlap.rb
|
332
|
+
- lib/active_support/core_ext/range/sole.rb
|
332
333
|
- lib/active_support/core_ext/regexp.rb
|
333
334
|
- lib/active_support/core_ext/securerandom.rb
|
334
335
|
- lib/active_support/core_ext/string.rb
|
@@ -376,11 +377,14 @@ files:
|
|
376
377
|
- lib/active_support/duration.rb
|
377
378
|
- lib/active_support/duration/iso8601_parser.rb
|
378
379
|
- lib/active_support/duration/iso8601_serializer.rb
|
380
|
+
- lib/active_support/editor.rb
|
379
381
|
- lib/active_support/encrypted_configuration.rb
|
380
382
|
- lib/active_support/encrypted_file.rb
|
381
383
|
- lib/active_support/environment_inquirer.rb
|
382
384
|
- lib/active_support/error_reporter.rb
|
383
385
|
- lib/active_support/error_reporter/test_helper.rb
|
386
|
+
- lib/active_support/event_reporter.rb
|
387
|
+
- lib/active_support/event_reporter/test_helper.rb
|
384
388
|
- lib/active_support/evented_file_update_checker.rb
|
385
389
|
- lib/active_support/execution_context.rb
|
386
390
|
- lib/active_support/execution_context/test_helper.rb
|
@@ -465,9 +469,11 @@ files:
|
|
465
469
|
- lib/active_support/testing/declarative.rb
|
466
470
|
- lib/active_support/testing/deprecation.rb
|
467
471
|
- lib/active_support/testing/error_reporter_assertions.rb
|
472
|
+
- lib/active_support/testing/event_reporter_assertions.rb
|
468
473
|
- lib/active_support/testing/file_fixtures.rb
|
469
474
|
- lib/active_support/testing/isolation.rb
|
470
475
|
- lib/active_support/testing/method_call_assertions.rb
|
476
|
+
- lib/active_support/testing/notification_assertions.rb
|
471
477
|
- lib/active_support/testing/parallelization.rb
|
472
478
|
- lib/active_support/testing/parallelization/server.rb
|
473
479
|
- lib/active_support/testing/parallelization/worker.rb
|
@@ -493,10 +499,10 @@ licenses:
|
|
493
499
|
- MIT
|
494
500
|
metadata:
|
495
501
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
496
|
-
changelog_uri: https://github.com/rails/rails/blob/v8.0.
|
497
|
-
documentation_uri: https://api.rubyonrails.org/v8.0.
|
502
|
+
changelog_uri: https://github.com/rails/rails/blob/v8.1.0.beta1/activesupport/CHANGELOG.md
|
503
|
+
documentation_uri: https://api.rubyonrails.org/v8.1.0.beta1/
|
498
504
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
499
|
-
source_code_uri: https://github.com/rails/rails/tree/v8.0.
|
505
|
+
source_code_uri: https://github.com/rails/rails/tree/v8.1.0.beta1/activesupport
|
500
506
|
rubygems_mfa_required: 'true'
|
501
507
|
rdoc_options:
|
502
508
|
- "--encoding"
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "active_support/time_with_zone"
|
4
|
-
|
5
|
-
module ActiveSupport
|
6
|
-
module EachTimeWithZone # :nodoc:
|
7
|
-
def each(&block)
|
8
|
-
ensure_iteration_allowed
|
9
|
-
super
|
10
|
-
end
|
11
|
-
|
12
|
-
def step(n = 1, &block)
|
13
|
-
ensure_iteration_allowed
|
14
|
-
super
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def ensure_iteration_allowed
|
19
|
-
raise TypeError, "can't iterate from #{first.class}" if first.is_a?(TimeWithZone)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
Range.prepend(ActiveSupport::EachTimeWithZone)
|