activesupport 6.0.4 → 6.1.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +388 -460
- 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/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 +3 -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 +17 -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 +8 -2
- 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/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/duration.rb +71 -22
- data/lib/active_support/encrypted_file.rb +19 -2
- 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 +1 -1
- 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 +35 -31
- 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 +1 -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 +29 -4
- 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 +20 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- data/lib/active_support.rb +13 -1
- metadata +33 -35
- 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
|