activesupport 7.1.5.2 → 8.0.0

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +64 -1234
  3. data/lib/active_support/array_inquirer.rb +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +10 -3
  5. data/lib/active_support/benchmark.rb +21 -0
  6. data/lib/active_support/benchmarkable.rb +3 -2
  7. data/lib/active_support/broadcast_logger.rb +4 -4
  8. data/lib/active_support/cache/file_store.rb +27 -12
  9. data/lib/active_support/cache/mem_cache_store.rb +16 -74
  10. data/lib/active_support/cache/memory_store.rb +8 -3
  11. data/lib/active_support/cache/redis_cache_store.rb +21 -15
  12. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  13. data/lib/active_support/cache.rb +74 -77
  14. data/lib/active_support/callbacks.rb +75 -115
  15. data/lib/active_support/class_attribute.rb +26 -0
  16. data/lib/active_support/code_generator.rb +9 -0
  17. data/lib/active_support/concurrency/share_lock.rb +0 -1
  18. data/lib/active_support/configuration_file.rb +15 -6
  19. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  20. data/lib/active_support/core_ext/benchmark.rb +6 -9
  21. data/lib/active_support/core_ext/class/attribute.rb +10 -19
  22. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  23. data/lib/active_support/core_ext/date/blank.rb +4 -0
  24. data/lib/active_support/core_ext/date/conversions.rb +2 -2
  25. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  26. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  27. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  28. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  29. data/lib/active_support/core_ext/enumerable.rb +8 -3
  30. data/lib/active_support/core_ext/erb/util.rb +5 -0
  31. data/lib/active_support/core_ext/hash/except.rb +0 -12
  32. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  33. data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
  34. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  35. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  36. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  37. data/lib/active_support/core_ext/object/blank.rb +45 -1
  38. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  39. data/lib/active_support/core_ext/object/json.rb +16 -10
  40. data/lib/active_support/core_ext/object/with.rb +5 -3
  41. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  42. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  43. data/lib/active_support/core_ext/securerandom.rb +8 -24
  44. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  45. data/lib/active_support/core_ext/string/filters.rb +1 -1
  46. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  47. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  48. data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
  49. data/lib/active_support/core_ext/time/calculations.rb +32 -30
  50. data/lib/active_support/core_ext/time/compatibility.rb +24 -0
  51. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  52. data/lib/active_support/core_ext/time/zones.rb +1 -1
  53. data/lib/active_support/core_ext.rb +0 -1
  54. data/lib/active_support/current_attributes.rb +38 -40
  55. data/lib/active_support/delegation.rb +200 -0
  56. data/lib/active_support/dependencies/autoload.rb +0 -12
  57. data/lib/active_support/dependencies.rb +0 -1
  58. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  59. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  60. data/lib/active_support/deprecation/reporting.rb +1 -15
  61. data/lib/active_support/deprecation.rb +8 -5
  62. data/lib/active_support/descendants_tracker.rb +9 -87
  63. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  64. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  65. data/lib/active_support/duration.rb +25 -16
  66. data/lib/active_support/encrypted_configuration.rb +20 -2
  67. data/lib/active_support/encrypted_file.rb +1 -1
  68. data/lib/active_support/error_reporter.rb +65 -3
  69. data/lib/active_support/evented_file_update_checker.rb +0 -2
  70. data/lib/active_support/execution_wrapper.rb +0 -1
  71. data/lib/active_support/file_update_checker.rb +1 -1
  72. data/lib/active_support/fork_tracker.rb +2 -38
  73. data/lib/active_support/gem_version.rb +4 -4
  74. data/lib/active_support/hash_with_indifferent_access.rb +21 -23
  75. data/lib/active_support/html_safe_translation.rb +3 -0
  76. data/lib/active_support/i18n_railtie.rb +19 -11
  77. data/lib/active_support/isolated_execution_state.rb +0 -2
  78. data/lib/active_support/json/encoding.rb +2 -2
  79. data/lib/active_support/log_subscriber.rb +0 -12
  80. data/lib/active_support/logger.rb +15 -2
  81. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  82. data/lib/active_support/message_pack/extensions.rb +15 -2
  83. data/lib/active_support/message_verifier.rb +12 -0
  84. data/lib/active_support/multibyte/chars.rb +2 -2
  85. data/lib/active_support/notifications/fanout.rb +4 -8
  86. data/lib/active_support/notifications/instrumenter.rb +21 -18
  87. data/lib/active_support/notifications.rb +28 -27
  88. data/lib/active_support/number_helper/number_converter.rb +2 -2
  89. data/lib/active_support/number_helper.rb +22 -0
  90. data/lib/active_support/option_merger.rb +2 -2
  91. data/lib/active_support/ordered_options.rb +53 -15
  92. data/lib/active_support/railtie.rb +8 -11
  93. data/lib/active_support/string_inquirer.rb +1 -1
  94. data/lib/active_support/subscriber.rb +1 -0
  95. data/lib/active_support/tagged_logging.rb +5 -1
  96. data/lib/active_support/test_case.rb +3 -1
  97. data/lib/active_support/testing/assertions.rb +79 -21
  98. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  99. data/lib/active_support/testing/deprecation.rb +5 -12
  100. data/lib/active_support/testing/isolation.rb +19 -9
  101. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  102. data/lib/active_support/testing/parallelization/server.rb +3 -0
  103. data/lib/active_support/testing/strict_warnings.rb +8 -4
  104. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  105. data/lib/active_support/testing/time_helpers.rb +4 -3
  106. data/lib/active_support/time_with_zone.rb +29 -16
  107. data/lib/active_support/values/time_zone.rb +18 -16
  108. data/lib/active_support/xml_mini.rb +11 -2
  109. data/lib/active_support.rb +11 -3
  110. metadata +32 -22
  111. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  112. data/lib/active_support/proxy_object.rb +0 -17
  113. data/lib/active_support/ruby_features.rb +0 -7
@@ -59,8 +59,8 @@ module ActiveSupport # :nodoc:
59
59
  end
60
60
 
61
61
  # Forward all undefined methods to the wrapped string.
62
- def method_missing(method, *args, &block)
63
- result = @wrapped_string.__send__(method, *args, &block)
62
+ def method_missing(method, ...)
63
+ result = @wrapped_string.__send__(method, ...)
64
64
  if method.end_with?("!")
65
65
  self if result
66
66
  else
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mutex_m"
4
3
  require "concurrent/map"
5
- require "set"
6
4
  require "active_support/core_ext/object/try"
7
5
 
8
6
  module ActiveSupport
@@ -49,15 +47,13 @@ module ActiveSupport
49
47
  #
50
48
  # This class is thread safe. All methods are reentrant.
51
49
  class Fanout
52
- include Mutex_m
53
-
54
50
  def initialize
51
+ @mutex = Mutex.new
55
52
  @string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
56
53
  @other_subscribers = []
57
54
  @all_listeners_for = Concurrent::Map.new
58
55
  @groups_for = Concurrent::Map.new
59
56
  @silenceable_groups_for = Concurrent::Map.new
60
- super
61
57
  end
62
58
 
63
59
  def inspect # :nodoc:
@@ -67,7 +63,7 @@ module ActiveSupport
67
63
 
68
64
  def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
69
65
  subscriber = Subscribers.new(pattern, callable || block, monotonic)
70
- synchronize do
66
+ @mutex.synchronize do
71
67
  case pattern
72
68
  when String
73
69
  @string_subscribers[pattern] << subscriber
@@ -83,7 +79,7 @@ module ActiveSupport
83
79
  end
84
80
 
85
81
  def unsubscribe(subscriber_or_name)
86
- synchronize do
82
+ @mutex.synchronize do
87
83
  case subscriber_or_name
88
84
  when String
89
85
  @string_subscribers[subscriber_or_name].clear
@@ -300,7 +296,7 @@ module ActiveSupport
300
296
 
301
297
  def all_listeners_for(name)
302
298
  # this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
303
- @all_listeners_for[name] || synchronize do
299
+ @all_listeners_for[name] || @mutex.synchronize do
304
300
  # use synchronisation when accessing @subscribers
305
301
  @all_listeners_for[name] ||=
306
302
  @string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
@@ -117,6 +117,8 @@ module ActiveSupport
117
117
  @cpu_time_finish = 0.0
118
118
  @allocation_count_start = 0
119
119
  @allocation_count_finish = 0
120
+ @gc_time_start = 0
121
+ @gc_time_finish = 0
120
122
  end
121
123
 
122
124
  def time
@@ -144,12 +146,14 @@ module ActiveSupport
144
146
  def start!
145
147
  @time = now
146
148
  @cpu_time_start = now_cpu
149
+ @gc_time_start = now_gc
147
150
  @allocation_count_start = now_allocations
148
151
  end
149
152
 
150
153
  # Record information at the time this event finishes
151
154
  def finish!
152
155
  @cpu_time_finish = now_cpu
156
+ @gc_time_finish = now_gc
153
157
  @end = now
154
158
  @allocation_count_finish = now_allocations
155
159
  end
@@ -173,28 +177,17 @@ module ActiveSupport
173
177
  @allocation_count_finish - @allocation_count_start
174
178
  end
175
179
 
176
- def children # :nodoc:
177
- ActiveSupport.deprecator.warn <<~EOM
178
- ActiveSupport::Notifications::Event#children is deprecated and will
179
- be removed in Rails 7.2.
180
- EOM
181
- []
182
- end
183
-
184
- def parent_of?(event) # :nodoc:
185
- ActiveSupport.deprecator.warn <<~EOM
186
- ActiveSupport::Notifications::Event#parent_of? is deprecated and will
187
- be removed in Rails 7.2.
188
- EOM
189
- start = (time - event.time) * 1000
190
- start <= 0 && (start + duration >= event.duration)
180
+ # Returns the time spent in GC (in milliseconds) between the call to #start!
181
+ # and the call to #finish!
182
+ def gc_time
183
+ (@gc_time_finish - @gc_time_start) / 1_000_000.0
191
184
  end
192
185
 
193
186
  # Returns the difference in milliseconds between when the execution of the
194
187
  # event started and when it ended.
195
188
  #
196
- # ActiveSupport::Notifications.subscribe('wait') do |*args|
197
- # @event = ActiveSupport::Notifications::Event.new(*args)
189
+ # ActiveSupport::Notifications.subscribe('wait') do |event|
190
+ # @event = event
198
191
  # end
199
192
  #
200
193
  # ActiveSupport::Notifications.instrument('wait') do
@@ -218,11 +211,21 @@ module ActiveSupport
218
211
  Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_millisecond)
219
212
  end
220
213
  rescue
221
- def now_cpu # rubocop:disable Lint/DuplicateMethods
214
+ def now_cpu
222
215
  0.0
223
216
  end
224
217
  end
225
218
 
219
+ if GC.respond_to?(:total_time)
220
+ def now_gc
221
+ GC.total_time
222
+ end
223
+ else
224
+ def now_gc
225
+ 0
226
+ end
227
+ end
228
+
226
229
  if GC.stat.key?(:total_allocated_objects)
227
230
  def now_allocations
228
231
  GC.stat(:total_allocated_objects)
@@ -29,6 +29,16 @@ module ActiveSupport
29
29
  # You can consume those events and the information they provide by registering
30
30
  # a subscriber.
31
31
  #
32
+ # ActiveSupport::Notifications.subscribe('render') do |event|
33
+ # event.name # => "render"
34
+ # event.duration # => 10 (in milliseconds)
35
+ # event.payload # => { extra: :information }
36
+ # event.allocations # => 1826 (objects)
37
+ # end
38
+ #
39
+ # +Event+ objects record CPU time and allocations. If you don't need this
40
+ # it's also possible to pass a block that accepts five arguments:
41
+ #
32
42
  # ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
33
43
  # name # => String, name of the event (such as 'render' from above)
34
44
  # start # => Time, when the instrumented block started execution
@@ -42,20 +52,18 @@ module ActiveSupport
42
52
  #
43
53
  # ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
44
54
  # name # => String, name of the event (such as 'render' from above)
45
- # start # => Monotonic time, when the instrumented block started execution
46
- # finish # => Monotonic time, when the instrumented block ended execution
55
+ # start # => Float, monotonic time when the instrumented block started execution
56
+ # finish # => Float, monotonic time when the instrumented block ended execution
47
57
  # id # => String, unique ID for the instrumenter that fired the event
48
58
  # payload # => Hash, the payload
49
59
  # end
50
60
  #
51
- # The +start+ and +finish+ values above represent monotonic time.
52
- #
53
61
  # For instance, let's store all "render" events in an array:
54
62
  #
55
63
  # events = []
56
64
  #
57
- # ActiveSupport::Notifications.subscribe('render') do |*args|
58
- # events << ActiveSupport::Notifications::Event.new(*args)
65
+ # ActiveSupport::Notifications.subscribe('render') do |event|
66
+ # events << event
59
67
  # end
60
68
  #
61
69
  # That code returns right away, you are just subscribing to "render" events.
@@ -66,14 +74,10 @@ module ActiveSupport
66
74
  # end
67
75
  #
68
76
  # event = events.first
69
- # event.name # => "render"
70
- # event.duration # => 10 (in milliseconds)
71
- # event.payload # => { extra: :information }
72
- #
73
- # The block in the <tt>subscribe</tt> call gets the name of the event, start
74
- # timestamp, end timestamp, a string with a unique identifier for that event's instrumenter
75
- # (something like "535801666f04d0298cd6"), and a hash with the payload, in
76
- # that order.
77
+ # event.name # => "render"
78
+ # event.duration # => 10 (in milliseconds)
79
+ # event.payload # => { extra: :information }
80
+ # event.allocations # => 1826 (objects)
77
81
  #
78
82
  # If an exception happens during that particular instrumentation the payload will
79
83
  # have a key <tt>:exception</tt> with an array of two elements as value: a string with
@@ -138,7 +142,7 @@ module ActiveSupport
138
142
  # You can subscribe to some event temporarily while some block runs. For
139
143
  # example, in
140
144
  #
141
- # callback = lambda {|*args| ... }
145
+ # callback = lambda {|event| ... }
142
146
  # ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
143
147
  # ...
144
148
  # end
@@ -161,7 +165,7 @@ module ActiveSupport
161
165
  #
162
166
  # The +subscribe+ method returns a subscriber object:
163
167
  #
164
- # subscriber = ActiveSupport::Notifications.subscribe("render") do |*args|
168
+ # subscriber = ActiveSupport::Notifications.subscribe("render") do |event|
165
169
  # ...
166
170
  # end
167
171
  #
@@ -214,11 +218,15 @@ module ActiveSupport
214
218
  # You can subscribe to events by passing a String to match exact event
215
219
  # names, or by passing a Regexp to match all events that match a pattern.
216
220
  #
217
- # ActiveSupport::Notifications.subscribe(/render/) do |*args|
218
- # @event = ActiveSupport::Notifications::Event.new(*args)
221
+ # If the block passed to the method only takes one argument,
222
+ # it will yield an +Event+ object to the block:
223
+ #
224
+ # ActiveSupport::Notifications.subscribe(/render/) do |event|
225
+ # @event = event
219
226
  # end
220
227
  #
221
- # The +block+ will receive five parameters with information about the event:
228
+ # Otherwise the +block+ will receive five arguments with information
229
+ # about the event:
222
230
  #
223
231
  # ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
224
232
  # name # => String, name of the event (such as 'render' from above)
@@ -228,16 +236,9 @@ module ActiveSupport
228
236
  # payload # => Hash, the payload
229
237
  # end
230
238
  #
231
- # If the block passed to the method only takes one parameter,
232
- # it will yield an event object to the block:
233
- #
234
- # ActiveSupport::Notifications.subscribe(/render/) do |event|
235
- # @event = event
236
- # end
237
- #
238
239
  # Raises an error if invalid event name type is passed:
239
240
  #
240
- # ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
241
+ # ActiveSupport::Notifications.subscribe(:render) {|event| ...}
241
242
  # #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
242
243
  #
243
244
  def subscribe(pattern = nil, callback = nil, &block)
@@ -164,11 +164,11 @@ module ActiveSupport
164
164
  end
165
165
 
166
166
  def translate_number_value_with_default(key, **i18n_options)
167
- I18n.translate(key, **{ default: default_value(key), scope: :number }.merge!(i18n_options))
167
+ I18n.translate(key, default: default_value(key), scope: :number, **i18n_options)
168
168
  end
169
169
 
170
170
  def translate_in_locale(key, **i18n_options)
171
- translate_number_value_with_default(key, **{ locale: options[:locale] }.merge(i18n_options))
171
+ translate_number_value_with_default(key, locale: options[:locale], **i18n_options)
172
172
  end
173
173
 
174
174
  def default_value(key)
@@ -1,6 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
+ # = Number Helper
5
+ #
6
+ # Provides methods for formatting numbers into currencies, percentages,
7
+ # phone numbers, and more.
8
+ #
9
+ # Example usage in a class:
10
+ # class Topic
11
+ # include ActiveSupport::NumberHelper
12
+ #
13
+ # def price
14
+ # number_to_currency(@price)
15
+ # end
16
+ # end
17
+ #
18
+ # Example usage in a module:
19
+ # require "active_support/number_helper"
20
+ #
21
+ # module NumberFormatting
22
+ # def format_price(price)
23
+ # ActiveSupport::NumberHelper.number_to_currency(price)
24
+ # end
25
+ # end
4
26
  module NumberHelper
5
27
  extend ActiveSupport::Autoload
6
28
 
@@ -31,8 +31,8 @@ module ActiveSupport
31
31
  end
32
32
  end
33
33
 
34
- def respond_to_missing?(*arguments)
35
- @context.respond_to?(*arguments)
34
+ def respond_to_missing?(...)
35
+ @context.respond_to?(...)
36
36
  end
37
37
  end
38
38
  end
@@ -46,18 +46,14 @@ module ActiveSupport
46
46
  super(key.to_sym, *identifiers)
47
47
  end
48
48
 
49
- def method_missing(name, *args)
50
- name_string = +name.to_s
51
- if name_string.chomp!("=")
52
- self[name_string] = args.first
49
+ def method_missing(method, *args)
50
+ if method.end_with?("=")
51
+ self[method.name.chomp("=")] = args.first
52
+ elsif method.end_with?("!")
53
+ name_string = method.name.chomp("!")
54
+ self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
53
55
  else
54
- bangs = name_string.chomp!("!")
55
-
56
- if bangs
57
- self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
58
- else
59
- self[name_string]
60
- end
56
+ self[method.name]
61
57
  end
62
58
  end
63
59
 
@@ -92,18 +88,60 @@ module ActiveSupport
92
88
  # h.boy # => 'John'
93
89
  class InheritableOptions < OrderedOptions
94
90
  def initialize(parent = nil)
95
- if parent.kind_of?(OrderedOptions)
91
+ @parent = parent
92
+ if @parent.kind_of?(OrderedOptions)
96
93
  # use the faster _get when dealing with OrderedOptions
97
- super() { |h, k| parent._get(k) }
98
- elsif parent
99
- super() { |h, k| parent[k] }
94
+ super() { |h, k| @parent._get(k) }
95
+ elsif @parent
96
+ super() { |h, k| @parent[k] }
100
97
  else
101
98
  super()
99
+ @parent = {}
102
100
  end
103
101
  end
104
102
 
103
+ def to_h
104
+ @parent.merge(self)
105
+ end
106
+
107
+ def ==(other)
108
+ to_h == other.to_h
109
+ end
110
+
111
+ def inspect
112
+ "#<#{self.class.name} #{to_h.inspect}>"
113
+ end
114
+
115
+ def to_s
116
+ to_h.to_s
117
+ end
118
+
119
+ def pretty_print(pp)
120
+ pp.pp_hash(to_h)
121
+ end
122
+
123
+ alias_method :own_key?, :key?
124
+ private :own_key?
125
+
126
+ def key?(key)
127
+ super || @parent.key?(key)
128
+ end
129
+
130
+ def overridden?(key)
131
+ !!(@parent && @parent.key?(key) && own_key?(key.to_sym))
132
+ end
133
+
105
134
  def inheritable_copy
106
135
  self.class.new(self)
107
136
  end
137
+
138
+ def to_a
139
+ entries
140
+ end
141
+
142
+ def each(&block)
143
+ to_h.each(&block)
144
+ self
145
+ end
108
146
  end
109
147
  end
@@ -89,10 +89,15 @@ module ActiveSupport
89
89
  begin
90
90
  TZInfo::DataSource.get
91
91
  rescue TZInfo::DataSourceNotFound => e
92
- raise e.exception "tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install"
92
+ raise e.exception('tzinfo-data is not present. Please add gem "tzinfo-data" to your Gemfile and run bundle install')
93
93
  end
94
94
  require "active_support/core_ext/time/zones"
95
95
  Time.zone_default = Time.find_zone!(app.config.time_zone)
96
+ config.eager_load_namespaces << TZInfo
97
+ end
98
+
99
+ initializer "active_support.to_time_preserves_timezone" do |app|
100
+ ActiveSupport.to_time_preserves_timezone = app.config.active_support.to_time_preserves_timezone
96
101
  end
97
102
 
98
103
  # Sets the default week start
@@ -117,16 +122,8 @@ module ActiveSupport
117
122
 
118
123
  initializer "active_support.set_configs" do |app|
119
124
  app.config.active_support.each do |k, v|
120
- if k == :disable_to_s_conversion
121
- ActiveSupport.deprecator.warn("config.active_support.disable_to_s_conversion is deprecated and will be removed in Rails 7.2.")
122
- elsif k == :remove_deprecated_time_with_zone_name
123
- ActiveSupport.deprecator.warn("config.active_support.remove_deprecated_time_with_zone_name is deprecated and will be removed in Rails 7.2.")
124
- elsif k == :use_rfc4122_namespaced_uuids
125
- ActiveSupport.deprecator.warn("config.active_support.use_rfc4122_namespaced_uuids is deprecated and will be removed in Rails 7.2.")
126
- else
127
- k = "#{k}="
128
- ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
129
- end
125
+ k = "#{k}="
126
+ ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
130
127
  end
131
128
  end
132
129
 
@@ -24,7 +24,7 @@ module ActiveSupport
24
24
  method_name.end_with?("?") || super
25
25
  end
26
26
 
27
- def method_missing(method_name, *arguments)
27
+ def method_missing(method_name, ...)
28
28
  if method_name.end_with?("?")
29
29
  self == method_name[0..-2]
30
30
  else
@@ -67,6 +67,7 @@ module ActiveSupport
67
67
 
68
68
  # Adds event subscribers for all new methods added to the class.
69
69
  def method_added(event)
70
+ super
70
71
  # Only public methods are added as subscribers, and only if a notifier
71
72
  # has been set up. This means that subscribers will only be set up for
72
73
  # classes that call #attach_to.
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "active_support/core_ext/module/delegation"
4
4
  require "active_support/core_ext/object/blank"
5
- require "logger"
6
5
  require "active_support/logger"
7
6
 
8
7
  module ActiveSupport
@@ -114,6 +113,11 @@ module ActiveSupport
114
113
  end
115
114
  end
116
115
 
116
+ # Returns an `ActiveSupport::Logger` that has already been wrapped with tagged logging concern.
117
+ def self.logger(*args, **kwargs)
118
+ new ActiveSupport::Logger.new(*args, **kwargs)
119
+ end
120
+
117
121
  def self.new(logger)
118
122
  logger = logger.clone
119
123
 
@@ -3,6 +3,7 @@
3
3
  require "minitest"
4
4
  require "active_support/testing/tagged_logging"
5
5
  require "active_support/testing/setup_and_teardown"
6
+ require "active_support/testing/tests_without_assertions"
6
7
  require "active_support/testing/assertions"
7
8
  require "active_support/testing/error_reporter_assertions"
8
9
  require "active_support/testing/deprecation"
@@ -78,7 +79,7 @@ module ActiveSupport
78
79
  # number of tests to run is above the +threshold+ param. The default value is
79
80
  # 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
80
81
  def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
81
- workers = Concurrent.physical_processor_count if workers == :number_of_processors
82
+ workers = Concurrent.processor_count if workers == :number_of_processors
82
83
  workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
83
84
 
84
85
  Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
@@ -142,6 +143,7 @@ module ActiveSupport
142
143
 
143
144
  include ActiveSupport::Testing::TaggedLogging
144
145
  prepend ActiveSupport::Testing::SetupAndTeardown
146
+ prepend ActiveSupport::Testing::TestsWithoutAssertions
145
147
  include ActiveSupport::Testing::Assertions
146
148
  include ActiveSupport::Testing::ErrorReporterAssertions
147
149
  include ActiveSupport::Testing::Deprecation
@@ -19,7 +19,7 @@ module ActiveSupport
19
19
  #
20
20
  # assert_not foo, 'foo should be false'
21
21
  def assert_not(object, message = nil)
22
- message ||= "Expected #{mu_pp(object)} to be nil or false"
22
+ message ||= -> { "Expected #{mu_pp(object)} to be nil or false" }
23
23
  assert !object, message
24
24
  end
25
25
 
@@ -118,9 +118,13 @@ module ActiveSupport
118
118
 
119
119
  expressions.zip(exps, before) do |(code, diff), exp, before_value|
120
120
  actual = exp.call
121
- error = "#{code.inspect} didn't change by #{diff}, but by #{actual - before_value}"
122
- error = "#{message}.\n#{error}" if message
123
- assert_equal(before_value + diff, actual, error)
121
+ rich_message = -> do
122
+ code_string = code.respond_to?(:call) ? _callable_to_source_string(code) : code
123
+ error = "`#{code_string}` didn't change by #{diff}, but by #{actual - before_value}"
124
+ error = "#{message}.\n#{error}" if message
125
+ error
126
+ end
127
+ assert_equal(before_value + diff, actual, rich_message)
124
128
  end
125
129
 
126
130
  retval
@@ -195,22 +199,32 @@ module ActiveSupport
195
199
  retval = _assert_nothing_raised_or_warn("assert_changes", &block)
196
200
 
197
201
  unless from == UNTRACKED
198
- error = "Expected change from #{from.inspect}, got #{before}"
199
- error = "#{message}.\n#{error}" if message
200
- assert from === before, error
202
+ rich_message = -> do
203
+ error = "Expected change from #{from.inspect}, got #{before.inspect}"
204
+ error = "#{message}.\n#{error}" if message
205
+ error
206
+ end
207
+ assert from === before, rich_message
201
208
  end
202
209
 
203
210
  after = exp.call
204
211
 
205
- error = "#{expression.inspect} didn't change"
206
- error = "#{error}. It was already #{to}" if before == to
207
- error = "#{message}.\n#{error}" if message
208
- refute_equal before, after, error
212
+ rich_message = -> do
213
+ code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
214
+ error = "`#{code_string}` didn't change"
215
+ error = "#{error}. It was already #{to.inspect}" if before == to
216
+ error = "#{message}.\n#{error}" if message
217
+ error
218
+ end
219
+ refute_equal before, after, rich_message
209
220
 
210
221
  unless to == UNTRACKED
211
- error = "Expected change to #{to}, got #{after}\n"
212
- error = "#{message}.\n#{error}" if message
213
- assert to === after, error
222
+ rich_message = -> do
223
+ error = "Expected change to #{to.inspect}, got #{after.inspect}\n"
224
+ error = "#{message}.\n#{error}" if message
225
+ error
226
+ end
227
+ assert to === after, rich_message
214
228
  end
215
229
 
216
230
  retval
@@ -242,20 +256,27 @@ module ActiveSupport
242
256
  retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
243
257
 
244
258
  unless from == UNTRACKED
245
- error = "Expected initial value of #{from.inspect}"
246
- error = "#{message}.\n#{error}" if message
247
- assert from === before, error
259
+ rich_message = -> do
260
+ error = "Expected initial value of #{from.inspect}, got #{before.inspect}"
261
+ error = "#{message}.\n#{error}" if message
262
+ error
263
+ end
264
+ assert from === before, rich_message
248
265
  end
249
266
 
250
267
  after = exp.call
251
268
 
252
- error = "#{expression.inspect} changed"
253
- error = "#{message}.\n#{error}" if message
269
+ rich_message = -> do
270
+ code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
271
+ error = "`#{code_string}` changed"
272
+ error = "#{message}.\n#{error}" if message
273
+ error
274
+ end
254
275
 
255
276
  if before.nil?
256
- assert_nil after, error
277
+ assert_nil after, rich_message
257
278
  else
258
- assert_equal before, after, error
279
+ assert_equal before, after, rich_message
259
280
  end
260
281
 
261
282
  retval
@@ -276,6 +297,43 @@ module ActiveSupport
276
297
 
277
298
  raise
278
299
  end
300
+
301
+ def _callable_to_source_string(callable)
302
+ if defined?(RubyVM::InstructionSequence) && callable.is_a?(Proc)
303
+ iseq = RubyVM::InstructionSequence.of(callable)
304
+ source =
305
+ if iseq.script_lines
306
+ iseq.script_lines.join("\n")
307
+ elsif File.readable?(iseq.absolute_path)
308
+ File.read(iseq.absolute_path)
309
+ end
310
+
311
+ return callable unless source
312
+
313
+ location = iseq.to_a[4][:code_location]
314
+ return callable unless location
315
+
316
+ lines = source.lines[(location[0] - 1)..(location[2] - 1)]
317
+ lines[-1] = lines[-1].byteslice(...location[3])
318
+ lines[0] = lines[0].byteslice(location[1]...)
319
+ source = lines.join.strip
320
+
321
+ # We ignore procs defined with do/end as they are likely multi-line anyway.
322
+ if source.start_with?("{")
323
+ source.delete_suffix!("}")
324
+ source.delete_prefix!("{")
325
+ source.strip!
326
+ # It won't read nice if the callable contains multiple
327
+ # lines, and it should be a rare occurrence anyway.
328
+ # Same if it takes arguments.
329
+ if !source.include?("\n") && !source.start_with?("|")
330
+ return source
331
+ end
332
+ end
333
+ end
334
+
335
+ callable
336
+ end
279
337
  end
280
338
  end
281
339
  end