activesupport 7.1.3.2 → 8.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -1126
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +15 -3
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +19 -18
- data/lib/active_support/cache/file_store.rb +27 -12
- data/lib/active_support/cache/mem_cache_store.rb +16 -74
- data/lib/active_support/cache/memory_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +21 -15
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache.rb +76 -78
- data/lib/active_support/callbacks.rb +79 -116
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +24 -10
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/core_ext/array/conversions.rb +3 -5
- data/lib/active_support/core_ext/benchmark.rb +6 -9
- data/lib/active_support/core_ext/class/attribute.rb +24 -20
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -2
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/enumerable.rb +8 -3
- data/lib/active_support/core_ext/erb/util.rb +7 -2
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -148
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/duplicable.rb +24 -15
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +21 -13
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/range/overlap.rb +1 -1
- data/lib/active_support/core_ext/securerandom.rb +4 -4
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +0 -7
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +32 -30
- data/lib/active_support/core_ext/time/compatibility.rb +24 -0
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +38 -40
- data/lib/active_support/delegation.rb +200 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/dependencies.rb +0 -1
- data/lib/active_support/deprecation/constant_accessor.rb +47 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +3 -17
- data/lib/active_support/deprecation.rb +8 -5
- data/lib/active_support/descendants_tracker.rb +9 -87
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -2
- data/lib/active_support/duration.rb +25 -16
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +65 -3
- data/lib/active_support/evented_file_update_checker.rb +0 -2
- data/lib/active_support/execution_wrapper.rb +0 -1
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +21 -23
- data/lib/active_support/html_safe_translation.rb +7 -4
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/isolated_execution_state.rb +0 -2
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/log_subscriber.rb +1 -12
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +0 -8
- data/lib/active_support/message_pack/extensions.rb +15 -2
- data/lib/active_support/message_verifier.rb +12 -0
- data/lib/active_support/messages/codec.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +2 -2
- data/lib/active_support/notifications/fanout.rb +4 -8
- data/lib/active_support/notifications/instrumenter.rb +32 -21
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/railtie.rb +8 -11
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +1 -0
- data/lib/active_support/syntax_error_proxy.rb +1 -11
- data/lib/active_support/tagged_logging.rb +9 -1
- data/lib/active_support/test_case.rb +3 -1
- data/lib/active_support/testing/assertions.rb +79 -21
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/isolation.rb +19 -9
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/parallelization/server.rb +3 -0
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/strict_warnings.rb +8 -4
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +4 -3
- data/lib/active_support/time_with_zone.rb +30 -17
- data/lib/active_support/values/time_zone.rb +25 -14
- data/lib/active_support/xml_mini.rb +11 -2
- data/lib/active_support.rb +12 -4
- metadata +68 -19
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/proxy_object.rb +0 -17
- data/lib/active_support/ruby_features.rb +0 -7
data/lib/active_support/cache.rb
CHANGED
|
@@ -52,7 +52,7 @@ module ActiveSupport
|
|
|
52
52
|
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
@format_version =
|
|
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
|
-
|
|
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
|
|
@@ -310,7 +286,7 @@ module ActiveSupport
|
|
|
310
286
|
# <tt>coder: nil</tt> to avoid the overhead of safeguarding against
|
|
311
287
|
# mutation.
|
|
312
288
|
#
|
|
313
|
-
# The +:coder+ option is
|
|
289
|
+
# The +:coder+ option is mutually exclusive with the +:serializer+ and
|
|
314
290
|
# +:compressor+ options. Specifying them together will raise an
|
|
315
291
|
# +ArgumentError+.
|
|
316
292
|
#
|
|
@@ -344,7 +320,7 @@ module ActiveSupport
|
|
|
344
320
|
|
|
345
321
|
# Silences the logger within a block.
|
|
346
322
|
def mute
|
|
347
|
-
previous_silence, @silence =
|
|
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
|
|
390
|
+
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
|
|
415
391
|
#
|
|
416
|
-
# cache.write(
|
|
392
|
+
# cache.write("foo", "original value")
|
|
417
393
|
# val_1 = nil
|
|
418
394
|
# val_2 = nil
|
|
419
|
-
#
|
|
395
|
+
# p cache.read("foo") # => "original value"
|
|
420
396
|
#
|
|
421
|
-
#
|
|
422
|
-
#
|
|
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
|
-
#
|
|
406
|
+
# "new value 1"
|
|
425
407
|
# end
|
|
426
408
|
# end
|
|
427
409
|
#
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
#
|
|
431
|
-
#
|
|
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
|
-
#
|
|
435
|
-
#
|
|
436
|
-
#
|
|
437
|
-
#
|
|
438
|
-
#
|
|
419
|
+
# t1.join
|
|
420
|
+
#
|
|
421
|
+
# p val_1 # => "new value 1"
|
|
422
|
+
# p val_2 # => "original 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,
|
|
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,
|
|
503
|
+
instrument(:read, key, options) do |payload|
|
|
512
504
|
entry = read_entry(key, **options, event: payload)
|
|
513
505
|
|
|
514
506
|
if entry
|
|
@@ -546,10 +538,11 @@ module ActiveSupport
|
|
|
546
538
|
|
|
547
539
|
options = names.extract_options!
|
|
548
540
|
options = merged_options(options)
|
|
541
|
+
keys = names.map { |name| normalize_key(name, options) }
|
|
549
542
|
|
|
550
|
-
instrument_multi :read_multi,
|
|
543
|
+
instrument_multi :read_multi, keys, options do |payload|
|
|
551
544
|
read_multi_entries(names, **options, event: payload).tap do |results|
|
|
552
|
-
payload[:hits] = results.keys
|
|
545
|
+
payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
|
|
553
546
|
end
|
|
554
547
|
end
|
|
555
548
|
end
|
|
@@ -559,8 +552,9 @@ module ActiveSupport
|
|
|
559
552
|
return hash if hash.empty?
|
|
560
553
|
|
|
561
554
|
options = merged_options(options)
|
|
555
|
+
normalized_hash = hash.transform_keys { |key| normalize_key(key, options) }
|
|
562
556
|
|
|
563
|
-
instrument_multi :write_multi,
|
|
557
|
+
instrument_multi :write_multi, normalized_hash, options do |payload|
|
|
564
558
|
entries = hash.each_with_object({}) do |(name, value), memo|
|
|
565
559
|
memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
|
566
560
|
end
|
|
@@ -604,32 +598,37 @@ module ActiveSupport
|
|
|
604
598
|
|
|
605
599
|
options = names.extract_options!
|
|
606
600
|
options = merged_options(options)
|
|
607
|
-
|
|
608
|
-
|
|
601
|
+
keys = names.map { |name| normalize_key(name, options) }
|
|
602
|
+
writes = {}
|
|
603
|
+
ordered = instrument_multi :read_multi, keys, options do |payload|
|
|
609
604
|
if options[:force]
|
|
610
605
|
reads = {}
|
|
611
606
|
else
|
|
612
607
|
reads = read_multi_entries(names, **options)
|
|
613
608
|
end
|
|
614
609
|
|
|
615
|
-
writes = {}
|
|
616
610
|
ordered = names.index_with do |name|
|
|
617
611
|
reads.fetch(name) { writes[name] = yield(name) }
|
|
618
612
|
end
|
|
619
613
|
writes.compact! if options[:skip_nil]
|
|
620
614
|
|
|
621
|
-
payload[:hits] = reads.keys
|
|
615
|
+
payload[:hits] = reads.keys.map { |name| normalize_key(name, options) }
|
|
622
616
|
payload[:super_operation] = :fetch_multi
|
|
623
617
|
|
|
624
|
-
write_multi(writes, options)
|
|
625
|
-
|
|
626
618
|
ordered
|
|
627
619
|
end
|
|
620
|
+
|
|
621
|
+
write_multi(writes, options)
|
|
622
|
+
|
|
623
|
+
ordered
|
|
628
624
|
end
|
|
629
625
|
|
|
630
626
|
# Writes the value to the cache with the key. The value must be supported
|
|
631
627
|
# by the +coder+'s +dump+ and +load+ methods.
|
|
632
628
|
#
|
|
629
|
+
# Returns +true+ if the write succeeded, +nil+ if there was an error talking
|
|
630
|
+
# to the cache backend, or +false+ if the write failed for another reason.
|
|
631
|
+
#
|
|
633
632
|
# By default, cache entries larger than 1kB are compressed. Compression
|
|
634
633
|
# allows more data to be stored in the same memory footprint, leading to
|
|
635
634
|
# fewer cache evictions and higher hit rates.
|
|
@@ -662,10 +661,11 @@ module ActiveSupport
|
|
|
662
661
|
# Other options will be handled by the specific cache store implementation.
|
|
663
662
|
def write(name, value, options = nil)
|
|
664
663
|
options = merged_options(options)
|
|
664
|
+
key = normalize_key(name, options)
|
|
665
665
|
|
|
666
|
-
instrument(:write,
|
|
666
|
+
instrument(:write, key, options) do
|
|
667
667
|
entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
|
668
|
-
write_entry(
|
|
668
|
+
write_entry(key, entry, **options)
|
|
669
669
|
end
|
|
670
670
|
end
|
|
671
671
|
|
|
@@ -675,9 +675,10 @@ module ActiveSupport
|
|
|
675
675
|
# Options are passed to the underlying cache implementation.
|
|
676
676
|
def delete(name, options = nil)
|
|
677
677
|
options = merged_options(options)
|
|
678
|
+
key = normalize_key(name, options)
|
|
678
679
|
|
|
679
|
-
instrument(:delete,
|
|
680
|
-
delete_entry(
|
|
680
|
+
instrument(:delete, key, options) do
|
|
681
|
+
delete_entry(key, **options)
|
|
681
682
|
end
|
|
682
683
|
end
|
|
683
684
|
|
|
@@ -691,7 +692,7 @@ module ActiveSupport
|
|
|
691
692
|
options = merged_options(options)
|
|
692
693
|
names.map! { |key| normalize_key(key, options) }
|
|
693
694
|
|
|
694
|
-
instrument_multi
|
|
695
|
+
instrument_multi(:delete_multi, names, options) do
|
|
695
696
|
delete_multi_entries(names, **options)
|
|
696
697
|
end
|
|
697
698
|
end
|
|
@@ -701,9 +702,10 @@ module ActiveSupport
|
|
|
701
702
|
# Options are passed to the underlying cache implementation.
|
|
702
703
|
def exist?(name, options = nil)
|
|
703
704
|
options = merged_options(options)
|
|
705
|
+
key = normalize_key(name, options)
|
|
704
706
|
|
|
705
|
-
instrument(:exist?,
|
|
706
|
-
entry = read_entry(
|
|
707
|
+
instrument(:exist?, key) do |payload|
|
|
708
|
+
entry = read_entry(key, **options, event: payload)
|
|
707
709
|
(entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
|
|
708
710
|
end
|
|
709
711
|
end
|
|
@@ -761,14 +763,6 @@ module ActiveSupport
|
|
|
761
763
|
private
|
|
762
764
|
def default_serializer
|
|
763
765
|
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
766
|
when 7.0
|
|
773
767
|
Cache::SerializerWithFallback[:marshal_7_0]
|
|
774
768
|
when 7.1
|
|
@@ -951,9 +945,12 @@ module ActiveSupport
|
|
|
951
945
|
#
|
|
952
946
|
# namespace_key 'foo', namespace: -> { 'cache' }
|
|
953
947
|
# # => 'cache:foo'
|
|
954
|
-
def namespace_key(key,
|
|
955
|
-
|
|
956
|
-
|
|
948
|
+
def namespace_key(key, call_options = nil)
|
|
949
|
+
namespace = if call_options&.key?(:namespace)
|
|
950
|
+
call_options[:namespace]
|
|
951
|
+
else
|
|
952
|
+
options[:namespace]
|
|
953
|
+
end
|
|
957
954
|
|
|
958
955
|
if namespace.respond_to?(:call)
|
|
959
956
|
namespace = namespace.call
|
|
@@ -1016,7 +1013,7 @@ module ActiveSupport
|
|
|
1016
1013
|
if multi
|
|
1017
1014
|
": #{payload[:key].size} key(s) specified"
|
|
1018
1015
|
elsif payload[:key]
|
|
1019
|
-
": #{
|
|
1016
|
+
": #{payload[:key]}"
|
|
1020
1017
|
end
|
|
1021
1018
|
|
|
1022
1019
|
debug_options = " (#{options.inspect})" unless options.blank?
|
|
@@ -1038,7 +1035,8 @@ module ActiveSupport
|
|
|
1038
1035
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
|
1039
1036
|
# for a brief period while the entry is being recalculated.
|
|
1040
1037
|
entry.expires_at = Time.now.to_f + race_ttl
|
|
1041
|
-
|
|
1038
|
+
options[:expires_in] = race_ttl * 2
|
|
1039
|
+
write_entry(key, entry, **options)
|
|
1042
1040
|
else
|
|
1043
1041
|
delete_entry(key, **options)
|
|
1044
1042
|
end
|
|
@@ -1052,10 +1050,10 @@ module ActiveSupport
|
|
|
1052
1050
|
entry.value
|
|
1053
1051
|
end
|
|
1054
1052
|
|
|
1055
|
-
def save_block_result_to_cache(name, options)
|
|
1053
|
+
def save_block_result_to_cache(name, key, options)
|
|
1056
1054
|
options = options.dup
|
|
1057
1055
|
|
|
1058
|
-
result = instrument(:generate,
|
|
1056
|
+
result = instrument(:generate, key, options) do
|
|
1059
1057
|
yield(name, WriteOptions.new(options))
|
|
1060
1058
|
end
|
|
1061
1059
|
|
|
@@ -6,7 +6,6 @@ require "active_support/core_ext/array/extract_options"
|
|
|
6
6
|
require "active_support/core_ext/class/attribute"
|
|
7
7
|
require "active_support/core_ext/string/filters"
|
|
8
8
|
require "active_support/core_ext/object/blank"
|
|
9
|
-
require "thread"
|
|
10
9
|
|
|
11
10
|
module ActiveSupport
|
|
12
11
|
# = Active Support \Callbacks
|
|
@@ -67,7 +66,7 @@ module ActiveSupport
|
|
|
67
66
|
|
|
68
67
|
included do
|
|
69
68
|
extend ActiveSupport::DescendantsTracker
|
|
70
|
-
class_attribute :__callbacks, instance_writer: false, default: {}
|
|
69
|
+
class_attribute :__callbacks, instance_writer: false, instance_predicate: false, default: {}
|
|
71
70
|
end
|
|
72
71
|
|
|
73
72
|
CALLBACK_FILTER_TYPES = [:before, :after, :around].freeze
|
|
@@ -150,7 +149,7 @@ module ActiveSupport
|
|
|
150
149
|
def halted_callback_hook(filter, name)
|
|
151
150
|
end
|
|
152
151
|
|
|
153
|
-
module Conditionals # :nodoc:
|
|
152
|
+
module Conditionals # :nodoc: all
|
|
154
153
|
class Value
|
|
155
154
|
def initialize(&block)
|
|
156
155
|
@block = block
|
|
@@ -159,128 +158,76 @@ module ActiveSupport
|
|
|
159
158
|
end
|
|
160
159
|
end
|
|
161
160
|
|
|
162
|
-
module Filters
|
|
161
|
+
module Filters # :nodoc: all
|
|
163
162
|
Environment = Struct.new(:target, :halted, :value)
|
|
164
163
|
|
|
165
164
|
class Before
|
|
166
|
-
def
|
|
165
|
+
def initialize(user_callback, user_conditions, chain_config, filter, name)
|
|
167
166
|
halted_lambda = chain_config[:terminator]
|
|
168
|
-
|
|
169
|
-
|
|
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
|
|
167
|
+
@user_callback, @user_conditions, @halted_lambda, @filter, @name = user_callback, user_conditions, halted_lambda, filter, name
|
|
168
|
+
freeze
|
|
174
169
|
end
|
|
170
|
+
attr_reader :user_callback, :user_conditions, :halted_lambda, :filter, :name
|
|
175
171
|
|
|
176
|
-
def
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
halted = env.halted
|
|
172
|
+
def call(env)
|
|
173
|
+
target = env.target
|
|
174
|
+
value = env.value
|
|
175
|
+
halted = env.halted
|
|
181
176
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
end
|
|
177
|
+
if !halted && user_conditions.all? { |c| c.call(target, value) }
|
|
178
|
+
result_lambda = -> { user_callback.call target, value }
|
|
179
|
+
env.halted = halted_lambda.call(target, result_lambda)
|
|
180
|
+
if env.halted
|
|
181
|
+
target.send :halted_callback_hook, filter, name
|
|
188
182
|
end
|
|
189
|
-
|
|
190
|
-
env
|
|
191
183
|
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
184
|
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
185
|
+
env
|
|
186
|
+
end
|
|
208
187
|
|
|
209
|
-
|
|
210
|
-
|
|
188
|
+
def apply(callback_sequence)
|
|
189
|
+
callback_sequence.before(self)
|
|
211
190
|
end
|
|
212
|
-
private_class_method :halting
|
|
213
191
|
end
|
|
214
192
|
|
|
215
193
|
class After
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
|
194
|
+
attr_reader :user_callback, :user_conditions, :halting
|
|
195
|
+
def initialize(user_callback, user_conditions, chain_config)
|
|
196
|
+
halting = chain_config[:skip_after_callbacks_if_terminated]
|
|
197
|
+
@user_callback, @user_conditions, @halting = user_callback, user_conditions, halting
|
|
198
|
+
freeze
|
|
230
199
|
end
|
|
231
200
|
|
|
232
|
-
def
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
halted = env.halted
|
|
237
|
-
|
|
238
|
-
if !halted && user_conditions.all? { |c| c.call(target, value) }
|
|
239
|
-
user_callback.call target, value
|
|
240
|
-
end
|
|
201
|
+
def call(env)
|
|
202
|
+
target = env.target
|
|
203
|
+
value = env.value
|
|
204
|
+
halted = env.halted
|
|
241
205
|
|
|
242
|
-
|
|
206
|
+
if (!halted || !@halting) && user_conditions.all? { |c| c.call(target, value) }
|
|
207
|
+
user_callback.call target, value
|
|
243
208
|
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
209
|
|
|
253
|
-
|
|
254
|
-
end
|
|
210
|
+
env
|
|
255
211
|
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
212
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
env
|
|
268
|
-
end
|
|
213
|
+
def apply(callback_sequence)
|
|
214
|
+
callback_sequence.after(self)
|
|
269
215
|
end
|
|
270
|
-
|
|
216
|
+
end
|
|
271
217
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
218
|
+
class Around
|
|
219
|
+
def initialize(user_callback, user_conditions)
|
|
220
|
+
@user_callback, @user_conditions = user_callback, user_conditions
|
|
221
|
+
freeze
|
|
222
|
+
end
|
|
275
223
|
|
|
276
|
-
|
|
277
|
-
|
|
224
|
+
def apply(callback_sequence)
|
|
225
|
+
callback_sequence.around(@user_callback, @user_conditions)
|
|
278
226
|
end
|
|
279
|
-
private_class_method :simple
|
|
280
227
|
end
|
|
281
228
|
end
|
|
282
229
|
|
|
283
|
-
class Callback # :nodoc
|
|
230
|
+
class Callback # :nodoc:
|
|
284
231
|
def self.build(chain, filter, kind, options)
|
|
285
232
|
if filter.is_a?(String)
|
|
286
233
|
raise ArgumentError, <<-MSG.squish
|
|
@@ -302,6 +249,8 @@ module ActiveSupport
|
|
|
302
249
|
@filter = filter
|
|
303
250
|
@if = check_conditionals(options[:if])
|
|
304
251
|
@unless = check_conditionals(options[:unless])
|
|
252
|
+
|
|
253
|
+
compiled
|
|
305
254
|
end
|
|
306
255
|
|
|
307
256
|
def merge_conditional_options(chain, if_option:, unless_option:)
|
|
@@ -329,19 +278,26 @@ module ActiveSupport
|
|
|
329
278
|
end
|
|
330
279
|
end
|
|
331
280
|
|
|
281
|
+
def compiled
|
|
282
|
+
@compiled ||=
|
|
283
|
+
begin
|
|
284
|
+
user_conditions = conditions_lambdas
|
|
285
|
+
user_callback = CallTemplate.build(@filter, self)
|
|
286
|
+
|
|
287
|
+
case kind
|
|
288
|
+
when :before
|
|
289
|
+
Filters::Before.new(user_callback.make_lambda, user_conditions, chain_config, @filter, name)
|
|
290
|
+
when :after
|
|
291
|
+
Filters::After.new(user_callback.make_lambda, user_conditions, chain_config)
|
|
292
|
+
when :around
|
|
293
|
+
Filters::Around.new(user_callback, user_conditions)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
332
298
|
# Wraps code with filter
|
|
333
299
|
def apply(callback_sequence)
|
|
334
|
-
|
|
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
|
|
300
|
+
compiled.apply(callback_sequence)
|
|
345
301
|
end
|
|
346
302
|
|
|
347
303
|
def current_scopes
|
|
@@ -368,14 +324,16 @@ module ActiveSupport
|
|
|
368
324
|
end
|
|
369
325
|
|
|
370
326
|
def conditions_lambdas
|
|
371
|
-
|
|
327
|
+
conditions =
|
|
328
|
+
@if.map { |c| CallTemplate.build(c, self).make_lambda } +
|
|
372
329
|
@unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
|
|
330
|
+
conditions.empty? ? EMPTY_ARRAY : conditions
|
|
373
331
|
end
|
|
374
332
|
end
|
|
375
333
|
|
|
376
334
|
# A future invocation of user-supplied code (either as a callback,
|
|
377
335
|
# or a condition filter).
|
|
378
|
-
module CallTemplate # :nodoc:
|
|
336
|
+
module CallTemplate # :nodoc: all
|
|
379
337
|
class MethodCall
|
|
380
338
|
def initialize(method)
|
|
381
339
|
@method_name = method
|
|
@@ -562,16 +520,18 @@ module ActiveSupport
|
|
|
562
520
|
@call_template = call_template
|
|
563
521
|
@user_conditions = user_conditions
|
|
564
522
|
|
|
565
|
-
@before =
|
|
566
|
-
@after =
|
|
523
|
+
@before = nil
|
|
524
|
+
@after = nil
|
|
567
525
|
end
|
|
568
526
|
|
|
569
|
-
def before(
|
|
527
|
+
def before(before)
|
|
528
|
+
@before ||= []
|
|
570
529
|
@before.unshift(before)
|
|
571
530
|
self
|
|
572
531
|
end
|
|
573
532
|
|
|
574
|
-
def after(
|
|
533
|
+
def after(after)
|
|
534
|
+
@after ||= []
|
|
575
535
|
@after.push(after)
|
|
576
536
|
self
|
|
577
537
|
end
|
|
@@ -595,11 +555,11 @@ module ActiveSupport
|
|
|
595
555
|
end
|
|
596
556
|
|
|
597
557
|
def invoke_before(arg)
|
|
598
|
-
@before
|
|
558
|
+
@before&.each { |b| b.call(arg) }
|
|
599
559
|
end
|
|
600
560
|
|
|
601
561
|
def invoke_after(arg)
|
|
602
|
-
@after
|
|
562
|
+
@after&.each { |a| a.call(arg) }
|
|
603
563
|
end
|
|
604
564
|
end
|
|
605
565
|
|
|
@@ -973,7 +933,10 @@ module ActiveSupport
|
|
|
973
933
|
end
|
|
974
934
|
|
|
975
935
|
def set_callbacks(name, callbacks) # :nodoc:
|
|
976
|
-
|
|
936
|
+
# HACK: We're making assumption on how `class_attribute` is implemented
|
|
937
|
+
# to save constantly duping the callback hash. If this desync with class_attribute
|
|
938
|
+
# we'll lose the optimization, but won't cause an actual behavior bug.
|
|
939
|
+
unless singleton_class.private_method_defined?(:__class_attr__callbacks, false)
|
|
977
940
|
self.__callbacks = __callbacks.dup
|
|
978
941
|
end
|
|
979
942
|
self.__callbacks[name.to_sym] = callbacks
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module ClassAttribute # :nodoc:
|
|
5
|
+
class << self
|
|
6
|
+
def redefine(owner, name, namespaced_name, value)
|
|
7
|
+
if owner.singleton_class?
|
|
8
|
+
if owner.attached_object.is_a?(Module)
|
|
9
|
+
redefine_method(owner, namespaced_name, private: true) { value }
|
|
10
|
+
else
|
|
11
|
+
redefine_method(owner, name) { value }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
redefine_method(owner.singleton_class, namespaced_name, private: true) { value }
|
|
16
|
+
|
|
17
|
+
redefine_method(owner.singleton_class, "#{namespaced_name}=", private: true) do |new_value|
|
|
18
|
+
if owner.equal?(self)
|
|
19
|
+
value = new_value
|
|
20
|
+
else
|
|
21
|
+
::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, new_value)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def redefine_method(owner, name, private: false, &block)
|
|
27
|
+
owner.silence_redefinition_of_method(name)
|
|
28
|
+
owner.define_method(name, &block)
|
|
29
|
+
owner.send(:private, name) if private
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|