activesupport 8.1.0.beta1 → 8.1.0.rc1

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +91 -0
  3. data/lib/active_support/callbacks.rb +20 -8
  4. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
  5. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  6. data/lib/active_support/core_ext/array.rb +7 -7
  7. data/lib/active_support/core_ext/benchmark.rb +4 -11
  8. data/lib/active_support/core_ext/big_decimal.rb +1 -1
  9. data/lib/active_support/core_ext/class/attribute.rb +8 -6
  10. data/lib/active_support/core_ext/class.rb +2 -2
  11. data/lib/active_support/core_ext/date.rb +5 -5
  12. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
  13. data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
  14. data/lib/active_support/core_ext/date_time.rb +5 -5
  15. data/lib/active_support/core_ext/digest.rb +1 -1
  16. data/lib/active_support/core_ext/enumerable.rb +2 -2
  17. data/lib/active_support/core_ext/file.rb +1 -1
  18. data/lib/active_support/core_ext/hash.rb +8 -8
  19. data/lib/active_support/core_ext/integer.rb +3 -3
  20. data/lib/active_support/core_ext/kernel.rb +3 -3
  21. data/lib/active_support/core_ext/module.rb +11 -11
  22. data/lib/active_support/core_ext/numeric.rb +3 -3
  23. data/lib/active_support/core_ext/object.rb +13 -13
  24. data/lib/active_support/core_ext/pathname.rb +2 -2
  25. data/lib/active_support/core_ext/range.rb +4 -4
  26. data/lib/active_support/core_ext/string.rb +13 -13
  27. data/lib/active_support/core_ext/symbol.rb +1 -1
  28. data/lib/active_support/core_ext/time/calculations.rb +0 -7
  29. data/lib/active_support/core_ext/time/compatibility.rb +2 -27
  30. data/lib/active_support/core_ext/time.rb +5 -5
  31. data/lib/active_support/core_ext.rb +1 -1
  32. data/lib/active_support/dependencies/interlock.rb +11 -5
  33. data/lib/active_support/dependencies.rb +6 -1
  34. data/lib/active_support/event_reporter.rb +24 -2
  35. data/lib/active_support/file_update_checker.rb +1 -1
  36. data/lib/active_support/gem_version.rb +1 -1
  37. data/lib/active_support/isolated_execution_state.rb +5 -2
  38. data/lib/active_support/json/encoding.rb +48 -19
  39. data/lib/active_support/log_subscriber.rb +0 -6
  40. data/lib/active_support/notifications/fanout.rb +64 -42
  41. data/lib/active_support/notifications/instrumenter.rb +1 -1
  42. data/lib/active_support/railtie.rb +7 -4
  43. data/lib/active_support/structured_event_subscriber.rb +99 -0
  44. data/lib/active_support/subscriber.rb +0 -5
  45. data/lib/active_support/testing/event_reporter_assertions.rb +11 -1
  46. data/lib/active_support/testing/parallelization/server.rb +15 -2
  47. data/lib/active_support/testing/parallelization/worker.rb +2 -2
  48. data/lib/active_support/testing/parallelization.rb +12 -1
  49. data/lib/active_support/time_with_zone.rb +3 -17
  50. data/lib/active_support/xml_mini.rb +2 -0
  51. data/lib/active_support.rb +12 -14
  52. metadata +18 -16
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/subscriber"
4
+
5
+ module ActiveSupport
6
+ # = Active Support Structured Event \Subscriber
7
+ #
8
+ # +ActiveSupport::StructuredEventSubscriber+ consumes ActiveSupport::Notifications
9
+ # in order to emit structured events via +Rails.event+.
10
+ #
11
+ # An example would be the Action Controller structured event subscriber, responsible for
12
+ # emitting request processing events:
13
+ #
14
+ # module ActionController
15
+ # class StructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber
16
+ # attach_to :action_controller
17
+ #
18
+ # def start_processing(event)
19
+ # emit_event("controller.request_started",
20
+ # controller: event.payload[:controller],
21
+ # action: event.payload[:action],
22
+ # format: event.payload[:format]
23
+ # )
24
+ # end
25
+ # end
26
+ # end
27
+ #
28
+ # After configured, whenever a <tt>"start_processing.action_controller"</tt> notification is published,
29
+ # it will properly dispatch the event (+ActiveSupport::Notifications::Event+) to the +start_processing+ method.
30
+ # The subscriber can then emit a structured event via the +emit_event+ method.
31
+ class StructuredEventSubscriber < Subscriber
32
+ class_attribute :debug_methods, instance_accessor: false, default: [] # :nodoc:
33
+
34
+ DEBUG_CHECK = proc { !ActiveSupport.event_reporter.debug_mode? }
35
+
36
+ class << self
37
+ def attach_to(...) # :nodoc:
38
+ result = super
39
+ set_silenced_events
40
+ result
41
+ end
42
+
43
+ private
44
+ def set_silenced_events
45
+ if subscriber
46
+ subscriber.silenced_events = debug_methods.to_h { |method| ["#{method}.#{namespace}", DEBUG_CHECK] }
47
+ end
48
+ end
49
+
50
+ def debug_only(method)
51
+ self.debug_methods << method
52
+ set_silenced_events
53
+ end
54
+ end
55
+
56
+ def initialize
57
+ super
58
+ @silenced_events = {}
59
+ end
60
+
61
+ def silenced?(event)
62
+ ActiveSupport.event_reporter.subscribers.none? || @silenced_events[event]&.call
63
+ end
64
+
65
+ attr_writer :silenced_events # :nodoc:
66
+
67
+ # Emit a structured event via Rails.event.notify.
68
+ #
69
+ # ==== Arguments
70
+ #
71
+ # * +name+ - The event name as a string or symbol
72
+ # * +payload+ - The event payload as a hash or object
73
+ # * +caller_depth+ - Stack depth for source location (default: 1)
74
+ # * +kwargs+ - Additional payload data merged with the payload hash
75
+ def emit_event(name, payload = nil, caller_depth: 1, **kwargs)
76
+ ActiveSupport.event_reporter.notify(name, payload, caller_depth: caller_depth + 1, **kwargs)
77
+ rescue => e
78
+ handle_event_error(name, e)
79
+ end
80
+
81
+ # Like +emit_event+, but only emits when the event reporter is in debug mode
82
+ def emit_debug_event(name, payload = nil, caller_depth: 1, **kwargs)
83
+ ActiveSupport.event_reporter.debug(name, payload, caller_depth: caller_depth + 1, **kwargs)
84
+ rescue => e
85
+ handle_event_error(name, e)
86
+ end
87
+
88
+ def call(event)
89
+ super
90
+ rescue => e
91
+ handle_event_error(event.name, e)
92
+ end
93
+
94
+ private
95
+ def handle_event_error(name, error)
96
+ ActiveSupport.error_reporter.report(error, source: name)
97
+ end
98
+ end
99
+ end
@@ -137,10 +137,5 @@ module ActiveSupport
137
137
  method = event.name[0, event.name.index(".")]
138
138
  send(method, event)
139
139
  end
140
-
141
- def publish_event(event) # :nodoc:
142
- method = event.name[0, event.name.index(".")]
143
- send(method, event)
144
- end
145
140
  end
146
141
  end
@@ -149,7 +149,7 @@ module ActiveSupport
149
149
  event.event_data
150
150
  else
151
151
  message = "Expected an event to be reported matching:\n " \
152
- "name: #{name}\n " \
152
+ "name: #{name.inspect}\n " \
153
153
  "payload: #{payload.inspect}\n " \
154
154
  "tags: #{tags.inspect}\n" \
155
155
  "but none of the #{events.size} reported events matched:\n " \
@@ -212,6 +212,16 @@ module ActiveSupport
212
212
 
213
213
  assert(true)
214
214
  end
215
+
216
+ # Allows debug events to be reported to +Rails.event+ for the duration of a given block.
217
+ #
218
+ # with_debug_event_reporting do
219
+ # service_that_reports_debug_events.perform
220
+ # end
221
+ #
222
+ def with_debug_event_reporting(&block)
223
+ ActiveSupport.event_reporter.with_debug(&block)
224
+ end
215
225
  end
216
226
  end
217
227
  end
@@ -14,6 +14,7 @@ module ActiveSupport
14
14
  def initialize
15
15
  @queue = Queue.new
16
16
  @active_workers = Concurrent::Map.new
17
+ @worker_pids = Concurrent::Map.new
17
18
  @in_flight = Concurrent::Map.new
18
19
  end
19
20
 
@@ -40,12 +41,24 @@ module ActiveSupport
40
41
  end
41
42
  end
42
43
 
43
- def start_worker(worker_id)
44
+ def start_worker(worker_id, worker_pid)
44
45
  @active_workers[worker_id] = true
46
+ @worker_pids[worker_id] = worker_pid
45
47
  end
46
48
 
47
- def stop_worker(worker_id)
49
+ def stop_worker(worker_id, worker_pid)
48
50
  @active_workers.delete(worker_id)
51
+ @worker_pids.delete(worker_id)
52
+ end
53
+
54
+ def remove_dead_workers(dead_pids)
55
+ dead_pids.each do |dead_pid|
56
+ worker_id = @worker_pids.key(dead_pid)
57
+ if worker_id
58
+ @active_workers.delete(worker_id)
59
+ @worker_pids.delete(worker_id)
60
+ end
61
+ end
49
62
  end
50
63
 
51
64
  def active_workers?
@@ -18,7 +18,7 @@ module ActiveSupport
18
18
  DRb.stop_service
19
19
 
20
20
  @queue = DRbObject.new_with_uri(@url)
21
- @queue.start_worker(@id)
21
+ @queue.start_worker(@id, Process.pid)
22
22
 
23
23
  begin
24
24
  after_fork
@@ -29,7 +29,7 @@ module ActiveSupport
29
29
  set_process_title("(stopping)")
30
30
 
31
31
  run_cleanup
32
- @queue.stop_worker(@id)
32
+ @queue.stop_worker(@id, Process.pid)
33
33
  end
34
34
  end
35
35
 
@@ -60,8 +60,19 @@ module ActiveSupport
60
60
  end
61
61
 
62
62
  def shutdown
63
+ dead_worker_pids = @worker_pool.filter_map do |pid|
64
+ Process.waitpid(pid, Process::WNOHANG)
65
+ rescue Errno::ECHILD
66
+ pid
67
+ end
68
+ @queue_server.remove_dead_workers(dead_worker_pids)
69
+
63
70
  @queue_server.shutdown
64
- @worker_pool.each { |pid| Process.waitpid pid }
71
+ @worker_pool.each do |pid|
72
+ Process.waitpid(pid)
73
+ rescue Errno::ECHILD
74
+ nil
75
+ end
65
76
  end
66
77
  end
67
78
  end
@@ -311,16 +311,8 @@ module ActiveSupport
311
311
  if duration_of_variable_length?(other)
312
312
  method_missing(:+, other)
313
313
  else
314
- begin
315
- result = utc + other
316
- rescue TypeError
317
- result = utc.to_datetime.since(other)
318
- ActiveSupport.deprecator.warn(
319
- "Adding an instance of #{other.class} to an instance of #{self.class} is deprecated. This behavior will raise " \
320
- "a `TypeError` in Rails 8.1."
321
- )
322
- result.in_time_zone(time_zone)
323
- end
314
+ result = utc + other
315
+
324
316
  result.in_time_zone(time_zone)
325
317
  end
326
318
  end
@@ -503,13 +495,7 @@ module ActiveSupport
503
495
  # with the same UTC offset as +self+ or in the local system timezone
504
496
  # depending on the setting of +ActiveSupport.to_time_preserves_timezone+.
505
497
  def to_time
506
- if preserve_timezone == :zone
507
- @to_time_with_timezone ||= getlocal(time_zone)
508
- elsif preserve_timezone
509
- @to_time_with_instance_offset ||= getlocal(utc_offset)
510
- else
511
- @to_time_with_system_offset ||= getlocal
512
- end
498
+ @to_time_with_timezone ||= getlocal(time_zone)
513
499
  end
514
500
 
515
501
  # So that +self+ <tt>acts_like?(:time)</tt>.
@@ -73,6 +73,8 @@ module ActiveSupport
73
73
  "decimal" => Proc.new do |number|
74
74
  if String === number
75
75
  number.to_d
76
+ elsif Float === number
77
+ BigDecimal(number, 0)
76
78
  else
77
79
  BigDecimal(number)
78
80
  end
@@ -53,6 +53,7 @@ module ActiveSupport
53
53
  autoload :EventedFileUpdateChecker
54
54
  autoload :ForkTracker
55
55
  autoload :LogSubscriber
56
+ autoload :StructuredEventSubscriber
56
57
  autoload :IsolatedExecutionState
57
58
  autoload :Notifications
58
59
  autoload :Reloader
@@ -114,6 +115,8 @@ module ActiveSupport
114
115
  @event_reporter = ActiveSupport::EventReporter.new
115
116
  singleton_class.attr_accessor :event_reporter # :nodoc:
116
117
 
118
+ cattr_accessor :filter_parameters, default: [] # :nodoc:
119
+
117
120
  def self.cache_format_version
118
121
  Cache.format_version
119
122
  end
@@ -123,23 +126,18 @@ module ActiveSupport
123
126
  end
124
127
 
125
128
  def self.to_time_preserves_timezone
126
- DateAndTime::Compatibility.preserve_timezone
129
+ ActiveSupport.deprecator.warn(
130
+ "`config.active_support.to_time_preserves_timezone` is deprecated and will be removed in Rails 8.2"
131
+ )
132
+ @to_time_preserves_timezone
127
133
  end
128
134
 
129
135
  def self.to_time_preserves_timezone=(value)
130
- if !value
131
- ActiveSupport.deprecator.warn(
132
- "`to_time` will always preserve the receiver timezone rather than system local time in Rails 8.1. " \
133
- "To opt in to the new behavior, set `config.active_support.to_time_preserves_timezone = :zone`."
134
- )
135
- elsif value != :zone
136
- ActiveSupport.deprecator.warn(
137
- "`to_time` will always preserve the full timezone rather than offset of the receiver in Rails 8.1. " \
138
- "To opt in to the new behavior, set `config.active_support.to_time_preserves_timezone = :zone`."
139
- )
140
- end
141
-
142
- DateAndTime::Compatibility.preserve_timezone = value
136
+ ActiveSupport.deprecator.warn(
137
+ "`config.active_support.to_time_preserves_timezone` is deprecated and will be removed in Rails 8.2"
138
+ )
139
+
140
+ @to_time_preserves_timezone = value
143
141
  end
144
142
 
145
143
  def self.utc_to_local_returns_utc_offset_times
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.1.0.beta1
4
+ version: 8.1.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -140,61 +140,61 @@ dependencies:
140
140
  - !ruby/object:Gem::Version
141
141
  version: '0'
142
142
  - !ruby/object:Gem::Dependency
143
- name: logger
143
+ name: json
144
144
  requirement: !ruby/object:Gem::Requirement
145
145
  requirements:
146
146
  - - ">="
147
147
  - !ruby/object:Gem::Version
148
- version: 1.4.2
148
+ version: '0'
149
149
  type: :runtime
150
150
  prerelease: false
151
151
  version_requirements: !ruby/object:Gem::Requirement
152
152
  requirements:
153
153
  - - ">="
154
154
  - !ruby/object:Gem::Version
155
- version: 1.4.2
155
+ version: '0'
156
156
  - !ruby/object:Gem::Dependency
157
- name: securerandom
157
+ name: logger
158
158
  requirement: !ruby/object:Gem::Requirement
159
159
  requirements:
160
160
  - - ">="
161
161
  - !ruby/object:Gem::Version
162
- version: '0.3'
162
+ version: 1.4.2
163
163
  type: :runtime
164
164
  prerelease: false
165
165
  version_requirements: !ruby/object:Gem::Requirement
166
166
  requirements:
167
167
  - - ">="
168
168
  - !ruby/object:Gem::Version
169
- version: '0.3'
169
+ version: 1.4.2
170
170
  - !ruby/object:Gem::Dependency
171
- name: uri
171
+ name: securerandom
172
172
  requirement: !ruby/object:Gem::Requirement
173
173
  requirements:
174
174
  - - ">="
175
175
  - !ruby/object:Gem::Version
176
- version: 0.13.1
176
+ version: '0.3'
177
177
  type: :runtime
178
178
  prerelease: false
179
179
  version_requirements: !ruby/object:Gem::Requirement
180
180
  requirements:
181
181
  - - ">="
182
182
  - !ruby/object:Gem::Version
183
- version: 0.13.1
183
+ version: '0.3'
184
184
  - !ruby/object:Gem::Dependency
185
- name: benchmark
185
+ name: uri
186
186
  requirement: !ruby/object:Gem::Requirement
187
187
  requirements:
188
188
  - - ">="
189
189
  - !ruby/object:Gem::Version
190
- version: '0.3'
190
+ version: 0.13.1
191
191
  type: :runtime
192
192
  prerelease: false
193
193
  version_requirements: !ruby/object:Gem::Requirement
194
194
  requirements:
195
195
  - - ">="
196
196
  - !ruby/object:Gem::Version
197
- version: '0.3'
197
+ version: 0.13.1
198
198
  description: A toolkit of support libraries and Ruby core extensions extracted from
199
199
  the Rails framework. Rich support for multibyte strings, internationalization, time
200
200
  zones, and testing.
@@ -233,6 +233,7 @@ files:
233
233
  - lib/active_support/concurrency/load_interlock_aware_monitor.rb
234
234
  - lib/active_support/concurrency/null_lock.rb
235
235
  - lib/active_support/concurrency/share_lock.rb
236
+ - lib/active_support/concurrency/thread_monitor.rb
236
237
  - lib/active_support/configurable.rb
237
238
  - lib/active_support/configuration_file.rb
238
239
  - lib/active_support/continuous_integration.rb
@@ -458,6 +459,7 @@ files:
458
459
  - lib/active_support/secure_compare_rotator.rb
459
460
  - lib/active_support/security_utils.rb
460
461
  - lib/active_support/string_inquirer.rb
462
+ - lib/active_support/structured_event_subscriber.rb
461
463
  - lib/active_support/subscriber.rb
462
464
  - lib/active_support/syntax_error_proxy.rb
463
465
  - lib/active_support/tagged_logging.rb
@@ -499,10 +501,10 @@ licenses:
499
501
  - MIT
500
502
  metadata:
501
503
  bug_tracker_uri: https://github.com/rails/rails/issues
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/
504
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.0.rc1/activesupport/CHANGELOG.md
505
+ documentation_uri: https://api.rubyonrails.org/v8.1.0.rc1/
504
506
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
505
- source_code_uri: https://github.com/rails/rails/tree/v8.1.0.beta1/activesupport
507
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.0.rc1/activesupport
506
508
  rubygems_mfa_required: 'true'
507
509
  rdoc_options:
508
510
  - "--encoding"