activesupport 7.1.4.1 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -1129
  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/broadcast_logger.rb +18 -18
  6. data/lib/active_support/cache/file_store.rb +15 -10
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -74
  8. data/lib/active_support/cache/memory_store.rb +2 -1
  9. data/lib/active_support/cache/redis_cache_store.rb +16 -13
  10. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  11. data/lib/active_support/cache.rb +60 -68
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  14. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  15. data/lib/active_support/core_ext/date/blank.rb +4 -0
  16. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  17. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  18. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  19. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  20. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  21. data/lib/active_support/core_ext/erb/util.rb +5 -0
  22. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  23. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  24. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  25. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  26. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  27. data/lib/active_support/core_ext/object/blank.rb +45 -1
  28. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  29. data/lib/active_support/core_ext/object/json.rb +6 -4
  30. data/lib/active_support/core_ext/object/with.rb +5 -3
  31. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  32. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  33. data/lib/active_support/core_ext/securerandom.rb +8 -24
  34. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/string/filters.rb +1 -1
  36. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  37. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  38. data/lib/active_support/core_ext/time/calculations.rb +18 -28
  39. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  40. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  41. data/lib/active_support/core_ext/time/zones.rb +1 -1
  42. data/lib/active_support/core_ext.rb +0 -1
  43. data/lib/active_support/current_attributes.rb +38 -40
  44. data/lib/active_support/delegation.rb +202 -0
  45. data/lib/active_support/dependencies/autoload.rb +0 -12
  46. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  47. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  48. data/lib/active_support/deprecation/reporting.rb +9 -4
  49. data/lib/active_support/deprecation.rb +8 -5
  50. data/lib/active_support/descendants_tracker.rb +9 -87
  51. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  52. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  53. data/lib/active_support/duration.rb +11 -6
  54. data/lib/active_support/encrypted_file.rb +1 -1
  55. data/lib/active_support/error_reporter.rb +41 -3
  56. data/lib/active_support/evented_file_update_checker.rb +0 -1
  57. data/lib/active_support/execution_wrapper.rb +0 -1
  58. data/lib/active_support/file_update_checker.rb +1 -1
  59. data/lib/active_support/fork_tracker.rb +2 -38
  60. data/lib/active_support/gem_version.rb +2 -2
  61. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  62. data/lib/active_support/html_safe_translation.rb +3 -0
  63. data/lib/active_support/log_subscriber.rb +0 -12
  64. data/lib/active_support/logger.rb +15 -2
  65. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  66. data/lib/active_support/message_pack/extensions.rb +15 -2
  67. data/lib/active_support/message_verifier.rb +12 -0
  68. data/lib/active_support/multibyte/chars.rb +2 -2
  69. data/lib/active_support/notifications/fanout.rb +4 -7
  70. data/lib/active_support/notifications/instrumenter.rb +21 -18
  71. data/lib/active_support/notifications.rb +28 -27
  72. data/lib/active_support/number_helper/number_converter.rb +2 -2
  73. data/lib/active_support/option_merger.rb +2 -2
  74. data/lib/active_support/ordered_options.rb +53 -15
  75. data/lib/active_support/proxy_object.rb +8 -5
  76. data/lib/active_support/railtie.rb +4 -11
  77. data/lib/active_support/string_inquirer.rb +1 -1
  78. data/lib/active_support/subscriber.rb +1 -0
  79. data/lib/active_support/tagged_logging.rb +0 -1
  80. data/lib/active_support/test_case.rb +3 -1
  81. data/lib/active_support/testing/assertions.rb +4 -4
  82. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  83. data/lib/active_support/testing/deprecation.rb +5 -12
  84. data/lib/active_support/testing/isolation.rb +20 -8
  85. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  86. data/lib/active_support/testing/parallelization/server.rb +3 -0
  87. data/lib/active_support/testing/strict_warnings.rb +8 -4
  88. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  89. data/lib/active_support/testing/time_helpers.rb +3 -3
  90. data/lib/active_support/time_with_zone.rb +8 -4
  91. data/lib/active_support/values/time_zone.rb +7 -7
  92. data/lib/active_support/xml_mini.rb +11 -2
  93. data/lib/active_support.rb +2 -1
  94. metadata +49 -15
  95. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  96. data/lib/active_support/ruby_features.rb +0 -7
@@ -52,7 +52,7 @@ module ActiveSupport
52
52
  autoload :LocalCache, "active_support/cache/strategy/local_cache"
53
53
  end
54
54
 
55
- @format_version = 6.1
55
+ @format_version = 7.0
56
56
 
57
57
  class << self
58
58
  attr_accessor :format_version
@@ -86,13 +86,7 @@ module ActiveSupport
86
86
  case store
87
87
  when Symbol
88
88
  options = parameters.extract_options!
89
- # clean this up once Ruby 2.7 support is dropped
90
- # see https://github.com/rails/rails/pull/41522#discussion_r581186602
91
- if options.empty?
92
- retrieve_store_class(store).new(*parameters)
93
- else
94
- retrieve_store_class(store).new(*parameters, **options)
95
- end
89
+ retrieve_store_class(store).new(*parameters, **options)
96
90
  when Array
97
91
  lookup_store(*store)
98
92
  when nil
@@ -166,7 +160,7 @@ module ActiveSupport
166
160
  # cache = ActiveSupport::Cache::MemoryStore.new
167
161
  #
168
162
  # cache.read('city') # => nil
169
- # cache.write('city', "Duckburgh")
163
+ # cache.write('city', "Duckburgh") # => true
170
164
  # cache.read('city') # => "Duckburgh"
171
165
  #
172
166
  # cache.write('not serializable', Proc.new {}) # => TypeError
@@ -206,24 +200,6 @@ module ActiveSupport
206
200
  def retrieve_pool_options(options)
207
201
  if options.key?(:pool)
208
202
  pool_options = options.delete(:pool)
209
- elsif options.key?(:pool_size) || options.key?(:pool_timeout)
210
- pool_options = {}
211
-
212
- if options.key?(:pool_size)
213
- ActiveSupport.deprecator.warn(<<~MSG)
214
- Using :pool_size is deprecated and will be removed in Rails 7.2.
215
- Use `pool: { size: #{options[:pool_size].inspect} }` instead.
216
- MSG
217
- pool_options[:size] = options.delete(:pool_size)
218
- end
219
-
220
- if options.key?(:pool_timeout)
221
- ActiveSupport.deprecator.warn(<<~MSG)
222
- Using :pool_timeout is deprecated and will be removed in Rails 7.2.
223
- Use `pool: { timeout: #{options[:pool_timeout].inspect} }` instead.
224
- MSG
225
- pool_options[:timeout] = options.delete(:pool_timeout)
226
- end
227
203
  else
228
204
  pool_options = true
229
205
  end
@@ -344,7 +320,7 @@ module ActiveSupport
344
320
 
345
321
  # Silences the logger within a block.
346
322
  def mute
347
- previous_silence, @silence = defined?(@silence) && @silence, true
323
+ previous_silence, @silence = @silence, true
348
324
  yield
349
325
  ensure
350
326
  @silence = previous_silence
@@ -411,31 +387,47 @@ module ActiveSupport
411
387
  # has elapsed.
412
388
  #
413
389
  # # Set all values to expire after one minute.
414
- # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
390
+ # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
415
391
  #
416
- # cache.write('foo', 'original value')
392
+ # cache.write("foo", "original value")
417
393
  # val_1 = nil
418
394
  # val_2 = nil
419
- # sleep 60
395
+ # p cache.read("foo") # => "original value"
420
396
  #
421
- # Thread.new do
422
- # val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
397
+ # sleep 1 # wait until the cache expires
398
+ #
399
+ # t1 = Thread.new do
400
+ # # fetch does the following:
401
+ # # 1. gets an recent expired entry
402
+ # # 2. extends the expiry by 2 seconds (race_condition_ttl)
403
+ # # 3. regenerates the new value
404
+ # val_1 = cache.fetch("foo", race_condition_ttl: 2) do
423
405
  # sleep 1
424
- # 'new value 1'
406
+ # "new value 1"
425
407
  # end
426
408
  # end
427
409
  #
428
- # Thread.new do
429
- # val_2 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
430
- # 'new value 2'
431
- # end
410
+ # # Wait until t1 extends the expiry of the entry
411
+ # # but before generating the new value
412
+ # sleep 0.1
413
+ #
414
+ # val_2 = cache.fetch("foo", race_condition_ttl: 2) do
415
+ # # This block won't be executed because t1 extended the expiry
416
+ # "new value 2"
432
417
  # end
433
418
  #
434
- # cache.fetch('foo') # => "original value"
435
- # sleep 10 # First thread extended the life of cache by another 10 seconds
436
- # cache.fetch('foo') # => "new value 1"
437
- # val_1 # => "new value 1"
438
- # val_2 # => "original value"
419
+ # t1.join
420
+ #
421
+ # p val_1 # => "new value 1"
422
+ # p val_2 # => "oritinal value"
423
+ # p cache.fetch("foo") # => "new value 1"
424
+ #
425
+ # # The entry requires 3 seconds to expire (expires_in + race_condition_ttl)
426
+ # # We have waited 2 seconds already (sleep(1) + t1.join) thus we need to wait 1
427
+ # # more second to see the entry expire.
428
+ # sleep 1
429
+ #
430
+ # p cache.fetch("foo") # => nil
439
431
  #
440
432
  # ==== Dynamic Options
441
433
  #
@@ -456,7 +448,7 @@ module ActiveSupport
456
448
 
457
449
  entry = nil
458
450
  unless options[:force]
459
- instrument(:read, name, options) do |payload|
451
+ instrument(:read, key, options) do |payload|
460
452
  cached_entry = read_entry(key, **options, event: payload)
461
453
  entry = handle_expired_entry(cached_entry, key, options)
462
454
  if entry
@@ -478,7 +470,7 @@ module ActiveSupport
478
470
  if entry
479
471
  get_entry_value(entry, name, options)
480
472
  else
481
- save_block_result_to_cache(name, options, &block)
473
+ save_block_result_to_cache(name, key, options, &block)
482
474
  end
483
475
  elsif options && options[:force]
484
476
  raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
@@ -508,7 +500,7 @@ module ActiveSupport
508
500
  key = normalize_key(name, options)
509
501
  version = normalize_version(name, options)
510
502
 
511
- instrument(:read, name, options) do |payload|
503
+ instrument(:read, key, options) do |payload|
512
504
  entry = read_entry(key, **options, event: payload)
513
505
 
514
506
  if entry
@@ -605,14 +597,14 @@ module ActiveSupport
605
597
  options = names.extract_options!
606
598
  options = merged_options(options)
607
599
 
608
- instrument_multi :read_multi, names, options do |payload|
600
+ writes = {}
601
+ ordered = instrument_multi :read_multi, names, options do |payload|
609
602
  if options[:force]
610
603
  reads = {}
611
604
  else
612
605
  reads = read_multi_entries(names, **options)
613
606
  end
614
607
 
615
- writes = {}
616
608
  ordered = names.index_with do |name|
617
609
  reads.fetch(name) { writes[name] = yield(name) }
618
610
  end
@@ -621,15 +613,20 @@ module ActiveSupport
621
613
  payload[:hits] = reads.keys
622
614
  payload[:super_operation] = :fetch_multi
623
615
 
624
- write_multi(writes, options)
625
-
626
616
  ordered
627
617
  end
618
+
619
+ write_multi(writes, options)
620
+
621
+ ordered
628
622
  end
629
623
 
630
624
  # Writes the value to the cache with the key. The value must be supported
631
625
  # by the +coder+'s +dump+ and +load+ methods.
632
626
  #
627
+ # Returns +true+ if the write succeeded, +nil+ if there was an error talking
628
+ # to the cache backend, or +false+ if the write failed for another reason.
629
+ #
633
630
  # By default, cache entries larger than 1kB are compressed. Compression
634
631
  # allows more data to be stored in the same memory footprint, leading to
635
632
  # fewer cache evictions and higher hit rates.
@@ -662,10 +659,11 @@ module ActiveSupport
662
659
  # Other options will be handled by the specific cache store implementation.
663
660
  def write(name, value, options = nil)
664
661
  options = merged_options(options)
662
+ key = normalize_key(name, options)
665
663
 
666
- instrument(:write, name, options) do
664
+ instrument(:write, key, options) do
667
665
  entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
668
- write_entry(normalize_key(name, options), entry, **options)
666
+ write_entry(key, entry, **options)
669
667
  end
670
668
  end
671
669
 
@@ -675,9 +673,10 @@ module ActiveSupport
675
673
  # Options are passed to the underlying cache implementation.
676
674
  def delete(name, options = nil)
677
675
  options = merged_options(options)
676
+ key = normalize_key(name, options)
678
677
 
679
- instrument(:delete, name) do
680
- delete_entry(normalize_key(name, options), **options)
678
+ instrument(:delete, key, options) do
679
+ delete_entry(key, **options)
681
680
  end
682
681
  end
683
682
 
@@ -691,7 +690,7 @@ module ActiveSupport
691
690
  options = merged_options(options)
692
691
  names.map! { |key| normalize_key(key, options) }
693
692
 
694
- instrument_multi :delete_multi, names do
693
+ instrument_multi(:delete_multi, names, options) do
695
694
  delete_multi_entries(names, **options)
696
695
  end
697
696
  end
@@ -701,9 +700,10 @@ module ActiveSupport
701
700
  # Options are passed to the underlying cache implementation.
702
701
  def exist?(name, options = nil)
703
702
  options = merged_options(options)
703
+ key = normalize_key(name, options)
704
704
 
705
- instrument(:exist?, name) do |payload|
706
- entry = read_entry(normalize_key(name, options), **options, event: payload)
705
+ instrument(:exist?, key) do |payload|
706
+ entry = read_entry(key, **options, event: payload)
707
707
  (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
708
708
  end
709
709
  end
@@ -761,14 +761,6 @@ module ActiveSupport
761
761
  private
762
762
  def default_serializer
763
763
  case Cache.format_version
764
- when 6.1
765
- ActiveSupport.deprecator.warn <<~EOM
766
- Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.
767
-
768
- Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
769
- for more information on how to upgrade.
770
- EOM
771
- Cache::SerializerWithFallback[:marshal_6_1]
772
764
  when 7.0
773
765
  Cache::SerializerWithFallback[:marshal_7_0]
774
766
  when 7.1
@@ -1016,7 +1008,7 @@ module ActiveSupport
1016
1008
  if multi
1017
1009
  ": #{payload[:key].size} key(s) specified"
1018
1010
  elsif payload[:key]
1019
- ": #{normalize_key(payload[:key], options)}"
1011
+ ": #{payload[:key]}"
1020
1012
  end
1021
1013
 
1022
1014
  debug_options = " (#{options.inspect})" unless options.blank?
@@ -1053,10 +1045,10 @@ module ActiveSupport
1053
1045
  entry.value
1054
1046
  end
1055
1047
 
1056
- def save_block_result_to_cache(name, options)
1048
+ def save_block_result_to_cache(name, key, options)
1057
1049
  options = options.dup
1058
1050
 
1059
- result = instrument(:generate, name, options) do
1051
+ result = instrument(:generate, key, options) do
1060
1052
  yield(name, WriteOptions.new(options))
1061
1053
  end
1062
1054
 
@@ -150,7 +150,7 @@ module ActiveSupport
150
150
  def halted_callback_hook(filter, name)
151
151
  end
152
152
 
153
- module Conditionals # :nodoc:
153
+ module Conditionals # :nodoc: all
154
154
  class Value
155
155
  def initialize(&block)
156
156
  @block = block
@@ -159,128 +159,76 @@ module ActiveSupport
159
159
  end
160
160
  end
161
161
 
162
- module Filters
162
+ module Filters # :nodoc: all
163
163
  Environment = Struct.new(:target, :halted, :value)
164
164
 
165
165
  class Before
166
- def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter, name)
166
+ def initialize(user_callback, user_conditions, chain_config, filter, name)
167
167
  halted_lambda = chain_config[:terminator]
168
-
169
- if user_conditions.any?
170
- halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
171
- else
172
- halting(callback_sequence, user_callback, halted_lambda, filter, name)
173
- end
168
+ @user_callback, @user_conditions, @halted_lambda, @filter, @name = user_callback, user_conditions, halted_lambda, filter, name
169
+ freeze
174
170
  end
171
+ attr_reader :user_callback, :user_conditions, :halted_lambda, :filter, :name
175
172
 
176
- def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
177
- callback_sequence.before do |env|
178
- target = env.target
179
- value = env.value
180
- halted = env.halted
173
+ def call(env)
174
+ target = env.target
175
+ value = env.value
176
+ halted = env.halted
181
177
 
182
- if !halted && user_conditions.all? { |c| c.call(target, value) }
183
- result_lambda = -> { user_callback.call target, value }
184
- env.halted = halted_lambda.call(target, result_lambda)
185
- if env.halted
186
- target.send :halted_callback_hook, filter, name
187
- end
178
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
179
+ result_lambda = -> { user_callback.call target, value }
180
+ env.halted = halted_lambda.call(target, result_lambda)
181
+ if env.halted
182
+ target.send :halted_callback_hook, filter, name
188
183
  end
189
-
190
- env
191
184
  end
192
- end
193
- private_class_method :halting_and_conditional
194
-
195
- def self.halting(callback_sequence, user_callback, halted_lambda, filter, name)
196
- callback_sequence.before do |env|
197
- target = env.target
198
- value = env.value
199
- halted = env.halted
200
185
 
201
- unless halted
202
- result_lambda = -> { user_callback.call target, value }
203
- env.halted = halted_lambda.call(target, result_lambda)
204
- if env.halted
205
- target.send :halted_callback_hook, filter, name
206
- end
207
- end
186
+ env
187
+ end
208
188
 
209
- env
210
- end
189
+ def apply(callback_sequence)
190
+ callback_sequence.before(self)
211
191
  end
212
- private_class_method :halting
213
192
  end
214
193
 
215
194
  class After
216
- def self.build(callback_sequence, user_callback, user_conditions, chain_config)
217
- if chain_config[:skip_after_callbacks_if_terminated]
218
- if user_conditions.any?
219
- halting_and_conditional(callback_sequence, user_callback, user_conditions)
220
- else
221
- halting(callback_sequence, user_callback)
222
- end
223
- else
224
- if user_conditions.any?
225
- conditional callback_sequence, user_callback, user_conditions
226
- else
227
- simple callback_sequence, user_callback
228
- end
229
- end
195
+ attr_reader :user_callback, :user_conditions, :halting
196
+ def initialize(user_callback, user_conditions, chain_config)
197
+ halting = chain_config[:skip_after_callbacks_if_terminated]
198
+ @user_callback, @user_conditions, @halting = user_callback, user_conditions, halting
199
+ freeze
230
200
  end
231
201
 
232
- def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
233
- callback_sequence.after do |env|
234
- target = env.target
235
- value = env.value
236
- halted = env.halted
237
-
238
- if !halted && user_conditions.all? { |c| c.call(target, value) }
239
- user_callback.call target, value
240
- end
202
+ def call(env)
203
+ target = env.target
204
+ value = env.value
205
+ halted = env.halted
241
206
 
242
- env
207
+ if (!halted || !@halting) && user_conditions.all? { |c| c.call(target, value) }
208
+ user_callback.call target, value
243
209
  end
244
- end
245
- private_class_method :halting_and_conditional
246
-
247
- def self.halting(callback_sequence, user_callback)
248
- callback_sequence.after do |env|
249
- unless env.halted
250
- user_callback.call env.target, env.value
251
- end
252
210
 
253
- env
254
- end
211
+ env
255
212
  end
256
- private_class_method :halting
257
-
258
- def self.conditional(callback_sequence, user_callback, user_conditions)
259
- callback_sequence.after do |env|
260
- target = env.target
261
- value = env.value
262
213
 
263
- if user_conditions.all? { |c| c.call(target, value) }
264
- user_callback.call target, value
265
- end
266
-
267
- env
268
- end
214
+ def apply(callback_sequence)
215
+ callback_sequence.after(self)
269
216
  end
270
- private_class_method :conditional
217
+ end
271
218
 
272
- def self.simple(callback_sequence, user_callback)
273
- callback_sequence.after do |env|
274
- user_callback.call env.target, env.value
219
+ class Around
220
+ def initialize(user_callback, user_conditions)
221
+ @user_callback, @user_conditions = user_callback, user_conditions
222
+ freeze
223
+ end
275
224
 
276
- env
277
- end
225
+ def apply(callback_sequence)
226
+ callback_sequence.around(@user_callback, @user_conditions)
278
227
  end
279
- private_class_method :simple
280
228
  end
281
229
  end
282
230
 
283
- class Callback # :nodoc:#
231
+ class Callback # :nodoc:
284
232
  def self.build(chain, filter, kind, options)
285
233
  if filter.is_a?(String)
286
234
  raise ArgumentError, <<-MSG.squish
@@ -302,6 +250,8 @@ module ActiveSupport
302
250
  @filter = filter
303
251
  @if = check_conditionals(options[:if])
304
252
  @unless = check_conditionals(options[:unless])
253
+
254
+ compiled
305
255
  end
306
256
 
307
257
  def merge_conditional_options(chain, if_option:, unless_option:)
@@ -329,19 +279,26 @@ module ActiveSupport
329
279
  end
330
280
  end
331
281
 
282
+ def compiled
283
+ @compiled ||=
284
+ begin
285
+ user_conditions = conditions_lambdas
286
+ user_callback = CallTemplate.build(@filter, self)
287
+
288
+ case kind
289
+ when :before
290
+ Filters::Before.new(user_callback.make_lambda, user_conditions, chain_config, @filter, name)
291
+ when :after
292
+ Filters::After.new(user_callback.make_lambda, user_conditions, chain_config)
293
+ when :around
294
+ Filters::Around.new(user_callback, user_conditions)
295
+ end
296
+ end
297
+ end
298
+
332
299
  # Wraps code with filter
333
300
  def apply(callback_sequence)
334
- user_conditions = conditions_lambdas
335
- user_callback = CallTemplate.build(@filter, self)
336
-
337
- case kind
338
- when :before
339
- Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter, name)
340
- when :after
341
- Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
342
- when :around
343
- callback_sequence.around(user_callback, user_conditions)
344
- end
301
+ compiled.apply(callback_sequence)
345
302
  end
346
303
 
347
304
  def current_scopes
@@ -368,14 +325,16 @@ module ActiveSupport
368
325
  end
369
326
 
370
327
  def conditions_lambdas
371
- @if.map { |c| CallTemplate.build(c, self).make_lambda } +
328
+ conditions =
329
+ @if.map { |c| CallTemplate.build(c, self).make_lambda } +
372
330
  @unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
331
+ conditions.empty? ? EMPTY_ARRAY : conditions
373
332
  end
374
333
  end
375
334
 
376
335
  # A future invocation of user-supplied code (either as a callback,
377
336
  # or a condition filter).
378
- module CallTemplate # :nodoc:
337
+ module CallTemplate # :nodoc: all
379
338
  class MethodCall
380
339
  def initialize(method)
381
340
  @method_name = method
@@ -562,16 +521,18 @@ module ActiveSupport
562
521
  @call_template = call_template
563
522
  @user_conditions = user_conditions
564
523
 
565
- @before = []
566
- @after = []
524
+ @before = nil
525
+ @after = nil
567
526
  end
568
527
 
569
- def before(&before)
528
+ def before(before)
529
+ @before ||= []
570
530
  @before.unshift(before)
571
531
  self
572
532
  end
573
533
 
574
- def after(&after)
534
+ def after(after)
535
+ @after ||= []
575
536
  @after.push(after)
576
537
  self
577
538
  end
@@ -595,11 +556,11 @@ module ActiveSupport
595
556
  end
596
557
 
597
558
  def invoke_before(arg)
598
- @before.each { |b| b.call(arg) }
559
+ @before&.each { |b| b.call(arg) }
599
560
  end
600
561
 
601
562
  def invoke_after(arg)
602
- @after.each { |a| a.call(arg) }
563
+ @after&.each { |a| a.call(arg) }
603
564
  end
604
565
  end
605
566
 
@@ -104,8 +104,6 @@ class Array
104
104
  end
105
105
  end
106
106
  alias_method :to_formatted_s, :to_fs
107
- alias_method :to_default_s, :to_s
108
- deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
109
107
 
110
108
  # Returns a string that represents the array in XML by invoking +to_xml+
111
109
  # on each element. Active Record collections delegate their representation
@@ -1,43 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/ruby_features"
4
3
  require "active_support/descendants_tracker"
5
4
 
6
5
  class Class
7
- if ActiveSupport::RubyFeatures::CLASS_SUBCLASSES
8
- # Returns an array with all classes that are < than its receiver.
9
- #
10
- # class C; end
11
- # C.descendants # => []
12
- #
13
- # class B < C; end
14
- # C.descendants # => [B]
15
- #
16
- # class A < B; end
17
- # C.descendants # => [B, A]
18
- #
19
- # class D < C; end
20
- # C.descendants # => [B, A, D]
21
- def descendants
22
- subclasses.concat(subclasses.flat_map(&:descendants))
23
- end
24
- else
25
- def descendants
26
- ObjectSpace.each_object(singleton_class).reject do |k|
27
- k.singleton_class? || k == self
28
- end
29
- end
30
-
31
- # Returns an array with the direct children of +self+.
32
- #
33
- # class Foo; end
34
- # class Bar < Foo; end
35
- # class Baz < Bar; end
36
- #
37
- # Foo.subclasses # => [Bar]
38
- def subclasses
39
- descendants.select { |descendant| descendant.superclass == self }
40
- end
6
+ # Returns an array with all classes that are < than its receiver.
7
+ #
8
+ # class C; end
9
+ # C.descendants # => []
10
+ #
11
+ # class B < C; end
12
+ # C.descendants # => [B]
13
+ #
14
+ # class A < B; end
15
+ # C.descendants # => [B, A]
16
+ #
17
+ # class D < C; end
18
+ # C.descendants # => [B, A, D]
19
+ def descendants
20
+ subclasses.concat(subclasses.flat_map(&:descendants))
41
21
  end
42
22
 
43
23
  prepend ActiveSupport::DescendantsTracker::ReloadedClassesFiltering
@@ -11,4 +11,8 @@ class Date # :nodoc:
11
11
  def blank?
12
12
  false
13
13
  end
14
+
15
+ def present?
16
+ true
17
+ end
14
18
  end
@@ -56,8 +56,6 @@ class Date
56
56
  end
57
57
  end
58
58
  alias_method :to_formatted_s, :to_fs
59
- alias_method :to_default_s, :to_s
60
- deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
61
59
 
62
60
  # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
63
61
  def readable_inspect