activesupport 6.0.6.1 → 6.1.7.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +441 -455
- data/MIT-LICENSE +1 -1
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +3 -3
- data/lib/active_support/cache/mem_cache_store.rb +28 -18
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +25 -25
- data/lib/active_support/cache/strategy/local_cache.rb +20 -5
- data/lib/active_support/cache.rb +87 -40
- data/lib/active_support/callbacks.rb +65 -56
- data/lib/active_support/concern.rb +46 -2
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/digest/uuid.rb +1 -0
- data/lib/active_support/core_ext/enumerable.rb +76 -4
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +38 -28
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +12 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +9 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/inflections.rb +38 -4
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +7 -4
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +19 -0
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +5 -1
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +9 -2
- data/lib/active_support/dependencies/zeitwerk_integration.rb +4 -1
- data/lib/active_support/dependencies.rb +37 -18
- data/lib/active_support/deprecation/behaviors.rb +15 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -2
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/digest.rb +2 -0
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/duration.rb +75 -25
- data/lib/active_support/encrypted_file.rb +27 -11
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +48 -24
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +1 -2
- data/lib/active_support/inflector/methods.rb +36 -33
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +5 -1
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +8 -0
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -12
- data/lib/active_support/message_encryptor.rb +4 -7
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +4 -42
- data/lib/active_support/multibyte/unicode.rb +9 -83
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/notifications.rb +32 -5
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/option_merger.rb +2 -1
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +16 -11
- data/lib/active_support/per_thread_registry.rb +2 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +4 -2
- data/lib/active_support/subscriber.rb +12 -7
- data/lib/active_support/tagged_logging.rb +30 -5
- data/lib/active_support/testing/assertions.rb +18 -11
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +12 -95
- data/lib/active_support/testing/time_helpers.rb +40 -3
- data/lib/active_support/time_with_zone.rb +67 -43
- data/lib/active_support/values/time_zone.rb +22 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- data/lib/active_support.rb +13 -1
- metadata +34 -36
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
data/lib/active_support/cache.rb
CHANGED
@@ -3,10 +3,12 @@
|
|
3
3
|
require "zlib"
|
4
4
|
require "active_support/core_ext/array/extract_options"
|
5
5
|
require "active_support/core_ext/array/wrap"
|
6
|
+
require "active_support/core_ext/enumerable"
|
6
7
|
require "active_support/core_ext/module/attribute_accessors"
|
7
8
|
require "active_support/core_ext/numeric/bytes"
|
8
9
|
require "active_support/core_ext/numeric/time"
|
9
10
|
require "active_support/core_ext/object/to_param"
|
11
|
+
require "active_support/core_ext/object/try"
|
10
12
|
require "active_support/core_ext/string/inflections"
|
11
13
|
|
12
14
|
module ActiveSupport
|
@@ -20,7 +22,7 @@ module ActiveSupport
|
|
20
22
|
|
21
23
|
# These options mean something to all cache implementations. Individual cache
|
22
24
|
# implementations may support additional options.
|
23
|
-
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl]
|
25
|
+
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
|
24
26
|
|
25
27
|
module Strategy
|
26
28
|
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
@@ -56,7 +58,13 @@ module ActiveSupport
|
|
56
58
|
case store
|
57
59
|
when Symbol
|
58
60
|
options = parameters.extract_options!
|
59
|
-
|
61
|
+
# clean this up once Ruby 2.7 support is dropped
|
62
|
+
# see https://github.com/rails/rails/pull/41522#discussion_r581186602
|
63
|
+
if options.empty?
|
64
|
+
retrieve_store_class(store).new(*parameters)
|
65
|
+
else
|
66
|
+
retrieve_store_class(store).new(*parameters, **options)
|
67
|
+
end
|
60
68
|
when Array
|
61
69
|
lookup_store(*store)
|
62
70
|
when nil
|
@@ -79,7 +87,7 @@ module ActiveSupport
|
|
79
87
|
#
|
80
88
|
# The +key+ argument can also respond to +cache_key+ or +to_param+.
|
81
89
|
def expand_cache_key(key, namespace = nil)
|
82
|
-
expanded_cache_key =
|
90
|
+
expanded_cache_key = namespace ? +"#{namespace}/" : +""
|
83
91
|
|
84
92
|
if prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
|
85
93
|
expanded_cache_key << "#{prefix}/"
|
@@ -156,6 +164,8 @@ module ActiveSupport
|
|
156
164
|
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
157
165
|
# specified in bytes.
|
158
166
|
class Store
|
167
|
+
DEFAULT_CODER = Marshal
|
168
|
+
|
159
169
|
cattr_accessor :logger, instance_writer: true
|
160
170
|
|
161
171
|
attr_reader :silence, :options
|
@@ -183,6 +193,7 @@ module ActiveSupport
|
|
183
193
|
# namespace for the cache.
|
184
194
|
def initialize(options = nil)
|
185
195
|
@options = options ? options.dup : {}
|
196
|
+
@coder = @options.delete(:coder) { self.class::DEFAULT_CODER } || NullCoder
|
186
197
|
end
|
187
198
|
|
188
199
|
# Silences the logger.
|
@@ -319,7 +330,7 @@ module ActiveSupport
|
|
319
330
|
|
320
331
|
entry = nil
|
321
332
|
instrument(:read, name, options) do |payload|
|
322
|
-
cached_entry = read_entry(key, **options) unless options[:force]
|
333
|
+
cached_entry = read_entry(key, **options, event: payload) unless options[:force]
|
323
334
|
entry = handle_expired_entry(cached_entry, key, options)
|
324
335
|
entry = nil if entry && entry.mismatched?(normalize_version(name, options))
|
325
336
|
payload[:super_operation] = :fetch if payload
|
@@ -353,7 +364,7 @@ module ActiveSupport
|
|
353
364
|
version = normalize_version(name, options)
|
354
365
|
|
355
366
|
instrument(:read, name, options) do |payload|
|
356
|
-
entry = read_entry(key, **options)
|
367
|
+
entry = read_entry(key, **options, event: payload)
|
357
368
|
|
358
369
|
if entry
|
359
370
|
if entry.expired?
|
@@ -385,7 +396,7 @@ module ActiveSupport
|
|
385
396
|
options = merged_options(options)
|
386
397
|
|
387
398
|
instrument :read_multi, names, options do |payload|
|
388
|
-
read_multi_entries(names, **options).tap do |results|
|
399
|
+
read_multi_entries(names, **options, event: payload).tap do |results|
|
389
400
|
payload[:hits] = results.keys
|
390
401
|
end
|
391
402
|
end
|
@@ -441,8 +452,8 @@ module ActiveSupport
|
|
441
452
|
instrument :read_multi, names, options do |payload|
|
442
453
|
reads = read_multi_entries(names, **options)
|
443
454
|
writes = {}
|
444
|
-
ordered = names.
|
445
|
-
|
455
|
+
ordered = names.index_with do |name|
|
456
|
+
reads.fetch(name) { writes[name] = yield(name) }
|
446
457
|
end
|
447
458
|
|
448
459
|
payload[:hits] = reads.keys
|
@@ -477,14 +488,26 @@ module ActiveSupport
|
|
477
488
|
end
|
478
489
|
end
|
479
490
|
|
491
|
+
# Deletes multiple entries in the cache.
|
492
|
+
#
|
493
|
+
# Options are passed to the underlying cache implementation.
|
494
|
+
def delete_multi(names, options = nil)
|
495
|
+
options = merged_options(options)
|
496
|
+
names.map! { |key| normalize_key(key, options) }
|
497
|
+
|
498
|
+
instrument :delete_multi, names do
|
499
|
+
delete_multi_entries(names, **options)
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
480
503
|
# Returns +true+ if the cache contains an entry for the given key.
|
481
504
|
#
|
482
505
|
# Options are passed to the underlying cache implementation.
|
483
506
|
def exist?(name, options = nil)
|
484
507
|
options = merged_options(options)
|
485
508
|
|
486
|
-
instrument(:exist?, name) do
|
487
|
-
entry = read_entry(normalize_key(name, options), **options)
|
509
|
+
instrument(:exist?, name) do |payload|
|
510
|
+
entry = read_entry(normalize_key(name, options), **options, event: payload)
|
488
511
|
(entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
|
489
512
|
end
|
490
513
|
end
|
@@ -567,26 +590,31 @@ module ActiveSupport
|
|
567
590
|
raise NotImplementedError.new
|
568
591
|
end
|
569
592
|
|
593
|
+
def serialize_entry(entry)
|
594
|
+
@coder.dump(entry)
|
595
|
+
end
|
596
|
+
|
597
|
+
def deserialize_entry(payload)
|
598
|
+
payload.nil? ? nil : @coder.load(payload)
|
599
|
+
end
|
600
|
+
|
570
601
|
# Reads multiple entries from the cache implementation. Subclasses MAY
|
571
602
|
# implement this method.
|
572
603
|
def read_multi_entries(names, **options)
|
573
|
-
|
574
|
-
|
575
|
-
|
604
|
+
names.each_with_object({}) do |name, results|
|
605
|
+
key = normalize_key(name, options)
|
606
|
+
entry = read_entry(key, **options)
|
607
|
+
|
608
|
+
next unless entry
|
609
|
+
|
576
610
|
version = normalize_version(name, options)
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
elsif entry.mismatched?(version)
|
583
|
-
# Skip mismatched versions
|
584
|
-
else
|
585
|
-
results[name] = entry.value
|
586
|
-
end
|
611
|
+
|
612
|
+
if entry.expired?
|
613
|
+
delete_entry(key, **options)
|
614
|
+
elsif !entry.mismatched?(version)
|
615
|
+
results[name] = entry.value
|
587
616
|
end
|
588
617
|
end
|
589
|
-
results
|
590
618
|
end
|
591
619
|
|
592
620
|
# Writes multiple entries to the cache implementation. Subclasses MAY
|
@@ -603,6 +631,12 @@ module ActiveSupport
|
|
603
631
|
raise NotImplementedError.new
|
604
632
|
end
|
605
633
|
|
634
|
+
# Deletes multiples entries in the cache implementation. Subclasses MAY
|
635
|
+
# implement this method.
|
636
|
+
def delete_multi_entries(entries, **options)
|
637
|
+
entries.count { |key| delete_entry(key, **options) }
|
638
|
+
end
|
639
|
+
|
606
640
|
# Merges the default options with ones specific to a method call.
|
607
641
|
def merged_options(call_options)
|
608
642
|
if call_options
|
@@ -639,6 +673,10 @@ module ActiveSupport
|
|
639
673
|
namespace = namespace.call
|
640
674
|
end
|
641
675
|
|
676
|
+
if key && key.encoding != Encoding::UTF_8
|
677
|
+
key = key.dup.force_encoding(Encoding::UTF_8)
|
678
|
+
end
|
679
|
+
|
642
680
|
if namespace
|
643
681
|
"#{namespace}:#{key}"
|
644
682
|
else
|
@@ -655,15 +693,15 @@ module ActiveSupport
|
|
655
693
|
case key
|
656
694
|
when Array
|
657
695
|
if key.size > 1
|
658
|
-
key
|
696
|
+
key.collect { |element| expanded_key(element) }
|
659
697
|
else
|
660
|
-
|
698
|
+
expanded_key(key.first)
|
661
699
|
end
|
662
700
|
when Hash
|
663
|
-
key
|
664
|
-
|
665
|
-
|
666
|
-
|
701
|
+
key.collect { |k, v| "#{k}=#{v}" }.sort!
|
702
|
+
else
|
703
|
+
key
|
704
|
+
end.to_param
|
667
705
|
end
|
668
706
|
|
669
707
|
def normalize_version(key, options = nil)
|
@@ -673,24 +711,21 @@ module ActiveSupport
|
|
673
711
|
def expanded_version(key)
|
674
712
|
case
|
675
713
|
when key.respond_to?(:cache_version) then key.cache_version.to_param
|
676
|
-
when key.is_a?(Array) then key.map { |element| expanded_version(element) }.compact.to_param
|
714
|
+
when key.is_a?(Array) then key.map { |element| expanded_version(element) }.tap(&:compact!).to_param
|
677
715
|
when key.respond_to?(:to_a) then expanded_version(key.to_a)
|
678
716
|
end
|
679
717
|
end
|
680
718
|
|
681
719
|
def instrument(operation, key, options = nil)
|
682
|
-
|
720
|
+
if logger && logger.debug? && !silence?
|
721
|
+
logger.debug "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}"
|
722
|
+
end
|
683
723
|
|
684
|
-
payload = { key: key }
|
724
|
+
payload = { key: key, store: self.class.name }
|
685
725
|
payload.merge!(options) if options.is_a?(Hash)
|
686
726
|
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) }
|
687
727
|
end
|
688
728
|
|
689
|
-
def log
|
690
|
-
return unless logger && logger.debug? && !silence?
|
691
|
-
logger.debug(yield)
|
692
|
-
end
|
693
|
-
|
694
729
|
def handle_expired_entry(entry, key, options)
|
695
730
|
if entry && entry.expired?
|
696
731
|
race_ttl = options[:race_condition_ttl].to_i
|
@@ -722,6 +757,18 @@ module ActiveSupport
|
|
722
757
|
end
|
723
758
|
end
|
724
759
|
|
760
|
+
module NullCoder # :nodoc:
|
761
|
+
class << self
|
762
|
+
def load(payload)
|
763
|
+
payload
|
764
|
+
end
|
765
|
+
|
766
|
+
def dump(entry)
|
767
|
+
entry
|
768
|
+
end
|
769
|
+
end
|
770
|
+
end
|
771
|
+
|
725
772
|
# This class is used to represent cache entries. Cache entries have a value, an optional
|
726
773
|
# expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
|
727
774
|
# on the cache. The version is used to support the :version option on the cache for rejecting
|
@@ -772,8 +819,8 @@ module ActiveSupport
|
|
772
819
|
end
|
773
820
|
|
774
821
|
# Returns the size of the cached value. This could be less than
|
775
|
-
# <tt>value.
|
776
|
-
def
|
822
|
+
# <tt>value.bytesize</tt> if the data is compressed.
|
823
|
+
def bytesize
|
777
824
|
case value
|
778
825
|
when NilClass
|
779
826
|
0
|
@@ -4,10 +4,7 @@ require "active_support/concern"
|
|
4
4
|
require "active_support/descendants_tracker"
|
5
5
|
require "active_support/core_ext/array/extract_options"
|
6
6
|
require "active_support/core_ext/class/attribute"
|
7
|
-
require "active_support/core_ext/kernel/reporting"
|
8
|
-
require "active_support/core_ext/kernel/singleton_class"
|
9
7
|
require "active_support/core_ext/string/filters"
|
10
|
-
require "active_support/deprecation"
|
11
8
|
require "thread"
|
12
9
|
|
13
10
|
module ActiveSupport
|
@@ -103,32 +100,6 @@ module ActiveSupport
|
|
103
100
|
env = Filters::Environment.new(self, false, nil)
|
104
101
|
next_sequence = callbacks.compile
|
105
102
|
|
106
|
-
invoke_sequence = Proc.new do
|
107
|
-
skipped = nil
|
108
|
-
while true
|
109
|
-
current = next_sequence
|
110
|
-
current.invoke_before(env)
|
111
|
-
if current.final?
|
112
|
-
env.value = !env.halted && (!block_given? || yield)
|
113
|
-
elsif current.skip?(env)
|
114
|
-
(skipped ||= []) << current
|
115
|
-
next_sequence = next_sequence.nested
|
116
|
-
next
|
117
|
-
else
|
118
|
-
next_sequence = next_sequence.nested
|
119
|
-
begin
|
120
|
-
target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
|
121
|
-
target.send(method, *arguments, &block)
|
122
|
-
ensure
|
123
|
-
next_sequence = current
|
124
|
-
end
|
125
|
-
end
|
126
|
-
current.invoke_after(env)
|
127
|
-
skipped.pop.invoke_after(env) while skipped && skipped.first
|
128
|
-
break env.value
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
103
|
# Common case: no 'around' callbacks defined
|
133
104
|
if next_sequence.final?
|
134
105
|
next_sequence.invoke_before(env)
|
@@ -136,6 +107,33 @@ module ActiveSupport
|
|
136
107
|
next_sequence.invoke_after(env)
|
137
108
|
env.value
|
138
109
|
else
|
110
|
+
invoke_sequence = Proc.new do
|
111
|
+
skipped = nil
|
112
|
+
|
113
|
+
while true
|
114
|
+
current = next_sequence
|
115
|
+
current.invoke_before(env)
|
116
|
+
if current.final?
|
117
|
+
env.value = !env.halted && (!block_given? || yield)
|
118
|
+
elsif current.skip?(env)
|
119
|
+
(skipped ||= []) << current
|
120
|
+
next_sequence = next_sequence.nested
|
121
|
+
next
|
122
|
+
else
|
123
|
+
next_sequence = next_sequence.nested
|
124
|
+
begin
|
125
|
+
target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
|
126
|
+
target.send(method, *arguments, &block)
|
127
|
+
ensure
|
128
|
+
next_sequence = current
|
129
|
+
end
|
130
|
+
end
|
131
|
+
current.invoke_after(env)
|
132
|
+
skipped.pop.invoke_after(env) while skipped&.first
|
133
|
+
break env.value
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
139
137
|
invoke_sequence.call
|
140
138
|
end
|
141
139
|
end
|
@@ -145,7 +143,7 @@ module ActiveSupport
|
|
145
143
|
# A hook invoked every time a before callback is halted.
|
146
144
|
# This can be overridden in ActiveSupport::Callbacks implementors in order
|
147
145
|
# to provide better debugging/logging.
|
148
|
-
def halted_callback_hook(filter)
|
146
|
+
def halted_callback_hook(filter, name)
|
149
147
|
end
|
150
148
|
|
151
149
|
module Conditionals # :nodoc:
|
@@ -161,17 +159,17 @@ module ActiveSupport
|
|
161
159
|
Environment = Struct.new(:target, :halted, :value)
|
162
160
|
|
163
161
|
class Before
|
164
|
-
def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
|
162
|
+
def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter, name)
|
165
163
|
halted_lambda = chain_config[:terminator]
|
166
164
|
|
167
165
|
if user_conditions.any?
|
168
|
-
halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
|
166
|
+
halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
|
169
167
|
else
|
170
|
-
halting(callback_sequence, user_callback, halted_lambda, filter)
|
168
|
+
halting(callback_sequence, user_callback, halted_lambda, filter, name)
|
171
169
|
end
|
172
170
|
end
|
173
171
|
|
174
|
-
def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
|
172
|
+
def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
|
175
173
|
callback_sequence.before do |env|
|
176
174
|
target = env.target
|
177
175
|
value = env.value
|
@@ -181,7 +179,7 @@ module ActiveSupport
|
|
181
179
|
result_lambda = -> { user_callback.call target, value }
|
182
180
|
env.halted = halted_lambda.call(target, result_lambda)
|
183
181
|
if env.halted
|
184
|
-
target.send :halted_callback_hook, filter
|
182
|
+
target.send :halted_callback_hook, filter, name
|
185
183
|
end
|
186
184
|
end
|
187
185
|
|
@@ -190,7 +188,7 @@ module ActiveSupport
|
|
190
188
|
end
|
191
189
|
private_class_method :halting_and_conditional
|
192
190
|
|
193
|
-
def self.halting(callback_sequence, user_callback, halted_lambda, filter)
|
191
|
+
def self.halting(callback_sequence, user_callback, halted_lambda, filter, name)
|
194
192
|
callback_sequence.before do |env|
|
195
193
|
target = env.target
|
196
194
|
value = env.value
|
@@ -199,9 +197,8 @@ module ActiveSupport
|
|
199
197
|
unless halted
|
200
198
|
result_lambda = -> { user_callback.call target, value }
|
201
199
|
env.halted = halted_lambda.call(target, result_lambda)
|
202
|
-
|
203
200
|
if env.halted
|
204
|
-
target.send :halted_callback_hook, filter
|
201
|
+
target.send :halted_callback_hook, filter, name
|
205
202
|
end
|
206
203
|
end
|
207
204
|
|
@@ -300,8 +297,8 @@ module ActiveSupport
|
|
300
297
|
@kind = kind
|
301
298
|
@filter = filter
|
302
299
|
@key = compute_identifier filter
|
303
|
-
@if = check_conditionals(
|
304
|
-
@unless = check_conditionals(
|
300
|
+
@if = check_conditionals(options[:if])
|
301
|
+
@unless = check_conditionals(options[:unless])
|
305
302
|
end
|
306
303
|
|
307
304
|
def filter; @key; end
|
@@ -339,7 +336,7 @@ module ActiveSupport
|
|
339
336
|
|
340
337
|
case kind
|
341
338
|
when :before
|
342
|
-
Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter)
|
339
|
+
Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter, name)
|
343
340
|
when :after
|
344
341
|
Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
|
345
342
|
when :around
|
@@ -352,7 +349,13 @@ module ActiveSupport
|
|
352
349
|
end
|
353
350
|
|
354
351
|
private
|
352
|
+
EMPTY_ARRAY = [].freeze
|
353
|
+
private_constant :EMPTY_ARRAY
|
354
|
+
|
355
355
|
def check_conditionals(conditionals)
|
356
|
+
return EMPTY_ARRAY if conditionals.blank?
|
357
|
+
|
358
|
+
conditionals = Array(conditionals)
|
356
359
|
if conditionals.any? { |c| c.is_a?(String) }
|
357
360
|
raise ArgumentError, <<-MSG.squish
|
358
361
|
Passing string to be evaluated in :if and :unless conditional
|
@@ -361,7 +364,7 @@ module ActiveSupport
|
|
361
364
|
MSG
|
362
365
|
end
|
363
366
|
|
364
|
-
conditionals
|
367
|
+
conditionals.freeze
|
365
368
|
end
|
366
369
|
|
367
370
|
def compute_identifier(filter)
|
@@ -403,21 +406,17 @@ module ActiveSupport
|
|
403
406
|
# The actual invocation is left up to the caller to minimize
|
404
407
|
# call stack pollution.
|
405
408
|
def expand(target, value, block)
|
406
|
-
|
409
|
+
expanded = [@override_target || target, @override_block || block, @method_name]
|
410
|
+
|
411
|
+
@arguments.each do |arg|
|
407
412
|
case arg
|
408
|
-
when :value
|
409
|
-
when :target
|
410
|
-
when :block
|
413
|
+
when :value then expanded << value
|
414
|
+
when :target then expanded << target
|
415
|
+
when :block then expanded << (block || raise(ArgumentError))
|
411
416
|
end
|
412
|
-
|
413
|
-
|
414
|
-
result.unshift @method_name
|
415
|
-
result.unshift @override_block || block
|
416
|
-
result.unshift @override_target || target
|
417
|
+
end
|
417
418
|
|
418
|
-
|
419
|
-
# target.send(method, *arguments, &block)
|
420
|
-
result
|
419
|
+
expanded
|
421
420
|
end
|
422
421
|
|
423
422
|
# Return a lambda that will make this call when given the input
|
@@ -845,8 +844,18 @@ module ActiveSupport
|
|
845
844
|
__callbacks[name.to_sym]
|
846
845
|
end
|
847
846
|
|
848
|
-
|
849
|
-
|
847
|
+
if Module.instance_method(:method_defined?).arity == 1 # Ruby 2.5 and older
|
848
|
+
def set_callbacks(name, callbacks) # :nodoc:
|
849
|
+
self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
|
850
|
+
end
|
851
|
+
else # Ruby 2.6 and newer
|
852
|
+
def set_callbacks(name, callbacks) # :nodoc:
|
853
|
+
unless singleton_class.method_defined?(:__callbacks, false)
|
854
|
+
self.__callbacks = __callbacks.dup
|
855
|
+
end
|
856
|
+
self.__callbacks[name.to_sym] = callbacks
|
857
|
+
self.__callbacks
|
858
|
+
end
|
850
859
|
end
|
851
860
|
end
|
852
861
|
end
|
@@ -19,7 +19,7 @@ module ActiveSupport
|
|
19
19
|
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be
|
20
20
|
# written as:
|
21
21
|
#
|
22
|
-
# require
|
22
|
+
# require "active_support/concern"
|
23
23
|
#
|
24
24
|
# module M
|
25
25
|
# extend ActiveSupport::Concern
|
@@ -76,7 +76,7 @@ module ActiveSupport
|
|
76
76
|
# is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
|
77
77
|
# module dependencies are properly resolved:
|
78
78
|
#
|
79
|
-
# require
|
79
|
+
# require "active_support/concern"
|
80
80
|
#
|
81
81
|
# module Foo
|
82
82
|
# extend ActiveSupport::Concern
|
@@ -99,6 +99,14 @@ module ActiveSupport
|
|
99
99
|
# class Host
|
100
100
|
# include Bar # It works, now Bar takes care of its dependencies
|
101
101
|
# end
|
102
|
+
#
|
103
|
+
# === Prepending concerns
|
104
|
+
#
|
105
|
+
# Just like <tt>include</tt>, concerns also support <tt>prepend</tt> with a corresponding
|
106
|
+
# <tt>prepended do</tt> callback. <tt>module ClassMethods</tt> or <tt>class_methods do</tt> are
|
107
|
+
# prepended as well.
|
108
|
+
#
|
109
|
+
# <tt>prepend</tt> is also used for any dependencies.
|
102
110
|
module Concern
|
103
111
|
class MultipleIncludedBlocks < StandardError #:nodoc:
|
104
112
|
def initialize
|
@@ -106,6 +114,12 @@ module ActiveSupport
|
|
106
114
|
end
|
107
115
|
end
|
108
116
|
|
117
|
+
class MultiplePrependBlocks < StandardError #:nodoc:
|
118
|
+
def initialize
|
119
|
+
super "Cannot define multiple 'prepended' blocks for a Concern"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
109
123
|
def self.extended(base) #:nodoc:
|
110
124
|
base.instance_variable_set(:@_dependencies, [])
|
111
125
|
end
|
@@ -123,6 +137,19 @@ module ActiveSupport
|
|
123
137
|
end
|
124
138
|
end
|
125
139
|
|
140
|
+
def prepend_features(base) #:nodoc:
|
141
|
+
if base.instance_variable_defined?(:@_dependencies)
|
142
|
+
base.instance_variable_get(:@_dependencies).unshift self
|
143
|
+
false
|
144
|
+
else
|
145
|
+
return false if base < self
|
146
|
+
@_dependencies.each { |dep| base.prepend(dep) }
|
147
|
+
super
|
148
|
+
base.singleton_class.prepend const_get(:ClassMethods) if const_defined?(:ClassMethods)
|
149
|
+
base.class_eval(&@_prepended_block) if instance_variable_defined?(:@_prepended_block)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
126
153
|
# Evaluate given block in context of base class,
|
127
154
|
# so that you can write class macros here.
|
128
155
|
# When you define more than one +included+ block, it raises an exception.
|
@@ -140,6 +167,23 @@ module ActiveSupport
|
|
140
167
|
end
|
141
168
|
end
|
142
169
|
|
170
|
+
# Evaluate given block in context of base class,
|
171
|
+
# so that you can write class macros here.
|
172
|
+
# When you define more than one +prepended+ block, it raises an exception.
|
173
|
+
def prepended(base = nil, &block)
|
174
|
+
if base.nil?
|
175
|
+
if instance_variable_defined?(:@_prepended_block)
|
176
|
+
if @_prepended_block.source_location != block.source_location
|
177
|
+
raise MultiplePrependBlocks
|
178
|
+
end
|
179
|
+
else
|
180
|
+
@_prepended_block = block
|
181
|
+
end
|
182
|
+
else
|
183
|
+
super
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
143
187
|
# Define class methods from given block.
|
144
188
|
# You can define private class methods as well.
|
145
189
|
#
|
@@ -5,7 +5,7 @@ require "active_support/ordered_options"
|
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
# Configurable provides a <tt>config</tt> method to store and retrieve
|
8
|
-
# configuration options as an <tt>
|
8
|
+
# configuration options as an <tt>OrderedOptions</tt>.
|
9
9
|
module Configurable
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
@@ -124,9 +124,9 @@ module ActiveSupport
|
|
124
124
|
private :config_accessor
|
125
125
|
end
|
126
126
|
|
127
|
-
# Reads and writes attributes from a configuration <tt>
|
127
|
+
# Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
|
128
128
|
#
|
129
|
-
# require
|
129
|
+
# require "active_support/configurable"
|
130
130
|
#
|
131
131
|
# class User
|
132
132
|
# include ActiveSupport::Configurable
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
# Reads a YAML configuration file, evaluating any ERB, then
|
5
|
+
# parsing the resulting YAML.
|
6
|
+
#
|
7
|
+
# Warns in case of YAML confusing characters, like invisible
|
8
|
+
# non-breaking spaces.
|
9
|
+
class ConfigurationFile # :nodoc:
|
10
|
+
class FormatError < StandardError; end
|
11
|
+
|
12
|
+
def initialize(content_path)
|
13
|
+
@content_path = content_path.to_s
|
14
|
+
@content = read content_path
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse(content_path, **options)
|
18
|
+
new(content_path).parse(**options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse(context: nil, **options)
|
22
|
+
source = render(context)
|
23
|
+
if YAML.respond_to?(:unsafe_load)
|
24
|
+
YAML.unsafe_load(source, **options) || {}
|
25
|
+
else
|
26
|
+
YAML.load(source, **options) || {}
|
27
|
+
end
|
28
|
+
rescue Psych::SyntaxError => error
|
29
|
+
raise "YAML syntax error occurred while parsing #{@content_path}. " \
|
30
|
+
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
|
31
|
+
"Error: #{error.message}"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def read(content_path)
|
36
|
+
require "yaml"
|
37
|
+
require "erb"
|
38
|
+
|
39
|
+
File.read(content_path).tap do |content|
|
40
|
+
if content.include?("\u00A0")
|
41
|
+
warn "File contains invisible non-breaking spaces, you may want to remove those"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def render(context)
|
47
|
+
erb = ERB.new(@content).tap { |e| e.filename = @content_path }
|
48
|
+
context ? erb.result(context) : erb.result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|