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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +247 -136
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +71 -0
  5. data/lib/active_support/broadcast_logger.rb +46 -59
  6. data/lib/active_support/cache/mem_cache_store.rb +25 -27
  7. data/lib/active_support/cache/redis_cache_store.rb +36 -30
  8. data/lib/active_support/cache/strategy/local_cache.rb +16 -7
  9. data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
  10. data/lib/active_support/cache.rb +70 -6
  11. data/lib/active_support/configurable.rb +28 -0
  12. data/lib/active_support/continuous_integration.rb +145 -0
  13. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  14. data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
  15. data/lib/active_support/core_ext/enumerable.rb +16 -4
  16. data/lib/active_support/core_ext/erb/util.rb +3 -3
  17. data/lib/active_support/core_ext/object/json.rb +8 -1
  18. data/lib/active_support/core_ext/object/to_query.rb +7 -1
  19. data/lib/active_support/core_ext/object/try.rb +2 -2
  20. data/lib/active_support/core_ext/range/overlap.rb +3 -3
  21. data/lib/active_support/core_ext/range/sole.rb +17 -0
  22. data/lib/active_support/core_ext/range.rb +1 -1
  23. data/lib/active_support/core_ext/string/filters.rb +3 -3
  24. data/lib/active_support/core_ext/string/multibyte.rb +12 -3
  25. data/lib/active_support/core_ext/string/output_safety.rb +19 -12
  26. data/lib/active_support/current_attributes/test_helper.rb +2 -2
  27. data/lib/active_support/current_attributes.rb +26 -16
  28. data/lib/active_support/deprecation/reporting.rb +4 -2
  29. data/lib/active_support/deprecation.rb +1 -1
  30. data/lib/active_support/editor.rb +70 -0
  31. data/lib/active_support/error_reporter.rb +50 -6
  32. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  33. data/lib/active_support/event_reporter.rb +570 -0
  34. data/lib/active_support/evented_file_update_checker.rb +5 -1
  35. data/lib/active_support/execution_context.rb +64 -7
  36. data/lib/active_support/file_update_checker.rb +7 -5
  37. data/lib/active_support/gem_version.rb +3 -3
  38. data/lib/active_support/gzip.rb +1 -0
  39. data/lib/active_support/hash_with_indifferent_access.rb +47 -24
  40. data/lib/active_support/i18n_railtie.rb +1 -2
  41. data/lib/active_support/inflector/inflections.rb +31 -15
  42. data/lib/active_support/inflector/transliterate.rb +6 -8
  43. data/lib/active_support/isolated_execution_state.rb +7 -13
  44. data/lib/active_support/json/decoding.rb +6 -4
  45. data/lib/active_support/json/encoding.rb +103 -14
  46. data/lib/active_support/lazy_load_hooks.rb +1 -1
  47. data/lib/active_support/log_subscriber.rb +2 -0
  48. data/lib/active_support/logger_thread_safe_level.rb +6 -3
  49. data/lib/active_support/message_encryptors.rb +52 -0
  50. data/lib/active_support/message_pack/extensions.rb +5 -0
  51. data/lib/active_support/message_verifiers.rb +52 -0
  52. data/lib/active_support/messages/rotation_coordinator.rb +9 -0
  53. data/lib/active_support/messages/rotator.rb +5 -0
  54. data/lib/active_support/multibyte/chars.rb +8 -1
  55. data/lib/active_support/multibyte.rb +4 -0
  56. data/lib/active_support/railtie.rb +26 -12
  57. data/lib/active_support/syntax_error_proxy.rb +3 -0
  58. data/lib/active_support/test_case.rb +61 -6
  59. data/lib/active_support/testing/assertions.rb +34 -6
  60. data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
  61. data/lib/active_support/testing/event_reporter_assertions.rb +217 -0
  62. data/lib/active_support/testing/notification_assertions.rb +92 -0
  63. data/lib/active_support/testing/parallelization/worker.rb +2 -0
  64. data/lib/active_support/testing/parallelization.rb +13 -0
  65. data/lib/active_support/testing/tests_without_assertions.rb +1 -1
  66. data/lib/active_support/testing/time_helpers.rb +7 -3
  67. data/lib/active_support/time_with_zone.rb +19 -5
  68. data/lib/active_support/values/time_zone.rb +8 -1
  69. data/lib/active_support/xml_mini.rb +1 -2
  70. data/lib/active_support.rb +11 -0
  71. metadata +11 -5
  72. 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
@@ -78,6 +78,8 @@ module ActiveSupport
78
78
  end
79
79
 
80
80
  def after_fork
81
+ ActiveSupport::TestCase.parallel_worker_id = @number
82
+
81
83
  Parallelization.after_fork_hooks.each do |cb|
82
84
  cb.call(@number)
83
85
  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 +Time.now+. Forwards optional <tt>with_usec</tt> argument.
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 Time.now, with_usec: with_usec, &block
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
- @period = @utc ? period : get_period_and_ensure_valid_local_time(period)
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
- zone == "UTC" || zone == "UCT"
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
- "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z')}"
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 time.kind_of?(Date)
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/Godthab",
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.parse(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 },
@@ -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.2.1
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.2.1/activesupport/CHANGELOG.md
497
- documentation_uri: https://api.rubyonrails.org/v8.0.2.1/
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.2.1/activesupport
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)