activesupport 6.1.7.3 → 7.0.0.alpha1
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 +151 -627
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +15 -9
- data/lib/active_support/cache/mem_cache_store.rb +119 -28
- data/lib/active_support/cache/memory_store.rb +21 -13
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +39 -59
- data/lib/active_support/cache/strategy/local_cache.rb +29 -49
- data/lib/active_support/cache.rb +189 -45
- data/lib/active_support/callbacks.rb +35 -31
- data/lib/active_support/concern.rb +5 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +6 -3
- data/lib/active_support/configuration_file.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +6 -6
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +2 -2
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/digest/uuid.rb +13 -13
- data/lib/active_support/core_ext/enumerable.rb +64 -12
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +2 -2
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +29 -24
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +60 -68
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +4 -5
- data/lib/active_support/core_ext/time/zones.rb +2 -17
- data/lib/active_support/core_ext/uri.rb +0 -14
- data/lib/active_support/current_attributes.rb +17 -2
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +4 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/descendants_tracker.rb +12 -9
- data/lib/active_support/digest.rb +4 -4
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -1
- data/lib/active_support/duration.rb +80 -52
- data/lib/active_support/encrypted_configuration.rb +11 -1
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/evented_file_update_checker.rb +1 -1
- data/lib/active_support/execution_wrapper.rb +13 -16
- data/lib/active_support/fork_tracker.rb +2 -4
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/inflector/inflections.rb +11 -4
- data/lib/active_support/inflector/methods.rb +23 -46
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +18 -1
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber.rb +13 -3
- data/lib/active_support/logger_thread_safe_level.rb +5 -13
- data/lib/active_support/message_encryptor.rb +3 -3
- data/lib/active_support/message_verifier.rb +4 -4
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +31 -11
- data/lib/active_support/notifications/instrumenter.rb +17 -0
- data/lib/active_support/notifications.rb +10 -0
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_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_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/rounding_helper.rb +1 -5
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +4 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/parameter_filter.rb +5 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/railtie.rb +33 -10
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +2 -2
- data/lib/active_support/secure_compare_rotator.rb +1 -1
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +5 -0
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +34 -4
- data/lib/active_support/testing/deprecation.rb +1 -1
- data/lib/active_support/testing/isolation.rb +1 -1
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +13 -2
- data/lib/active_support/time_with_zone.rb +19 -6
- data/lib/active_support/values/time_zone.rb +25 -11
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +2 -1
- data/lib/active_support.rb +14 -1
- metadata +14 -29
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -34,57 +34,40 @@ module ActiveSupport
|
|
34
34
|
|
35
35
|
# Simple memory backed cache. This cache is not thread safe and is intended only
|
36
36
|
# for serving as a temporary memory cache for a single thread.
|
37
|
-
class LocalStore
|
37
|
+
class LocalStore
|
38
38
|
def initialize
|
39
|
-
super
|
40
39
|
@data = {}
|
41
40
|
end
|
42
41
|
|
43
|
-
# Don't allow synchronizing since it isn't thread safe.
|
44
|
-
def synchronize # :nodoc:
|
45
|
-
yield
|
46
|
-
end
|
47
|
-
|
48
42
|
def clear(options = nil)
|
49
43
|
@data.clear
|
50
44
|
end
|
51
45
|
|
52
|
-
def read_entry(key
|
46
|
+
def read_entry(key)
|
53
47
|
@data[key]
|
54
48
|
end
|
55
49
|
|
56
|
-
def read_multi_entries(keys
|
57
|
-
|
58
|
-
|
59
|
-
keys.each do |name|
|
60
|
-
entry = read_entry(name, **options)
|
61
|
-
values[name] = entry.value if entry
|
62
|
-
end
|
63
|
-
|
64
|
-
values
|
50
|
+
def read_multi_entries(keys)
|
51
|
+
@data.slice(*keys)
|
65
52
|
end
|
66
53
|
|
67
|
-
def write_entry(key, entry
|
68
|
-
entry.dup_value!
|
54
|
+
def write_entry(key, entry)
|
69
55
|
@data[key] = entry
|
70
56
|
true
|
71
57
|
end
|
72
58
|
|
73
|
-
def delete_entry(key
|
59
|
+
def delete_entry(key)
|
74
60
|
!!@data.delete(key)
|
75
61
|
end
|
76
62
|
|
77
|
-
def fetch_entry(key
|
78
|
-
|
79
|
-
dup_entry = entry.dup
|
80
|
-
dup_entry&.dup_value!
|
81
|
-
dup_entry
|
63
|
+
def fetch_entry(key) # :nodoc:
|
64
|
+
@data.fetch(key) { @data[key] = yield }
|
82
65
|
end
|
83
66
|
end
|
84
67
|
|
85
68
|
# Use a local cache for the duration of block.
|
86
|
-
def with_local_cache
|
87
|
-
use_temporary_local_cache(LocalStore.new)
|
69
|
+
def with_local_cache(&block)
|
70
|
+
use_temporary_local_cache(LocalStore.new, &block)
|
88
71
|
end
|
89
72
|
|
90
73
|
# Middleware class can be inserted as a Rack handler to be local cache for the
|
@@ -116,27 +99,27 @@ module ActiveSupport
|
|
116
99
|
def increment(name, amount = 1, **options) # :nodoc:
|
117
100
|
return super unless local_cache
|
118
101
|
value = bypass_local_cache { super }
|
119
|
-
write_cache_value(name, value, **options)
|
102
|
+
write_cache_value(name, value, raw: true, **options)
|
120
103
|
value
|
121
104
|
end
|
122
105
|
|
123
106
|
def decrement(name, amount = 1, **options) # :nodoc:
|
124
107
|
return super unless local_cache
|
125
108
|
value = bypass_local_cache { super }
|
126
|
-
write_cache_value(name, value, **options)
|
109
|
+
write_cache_value(name, value, raw: true, **options)
|
127
110
|
value
|
128
111
|
end
|
129
112
|
|
130
113
|
private
|
131
|
-
def
|
114
|
+
def read_serialized_entry(key, raw: false, **options)
|
132
115
|
if cache = local_cache
|
133
116
|
hit = true
|
134
|
-
|
117
|
+
entry = cache.fetch_entry(key) do
|
135
118
|
hit = false
|
136
119
|
super
|
137
120
|
end
|
138
121
|
options[:event][:store] = cache.class.name if hit && options[:event]
|
139
|
-
|
122
|
+
entry
|
140
123
|
else
|
141
124
|
super
|
142
125
|
end
|
@@ -145,7 +128,7 @@ module ActiveSupport
|
|
145
128
|
def read_multi_entries(keys, **options)
|
146
129
|
return super unless local_cache
|
147
130
|
|
148
|
-
local_entries = local_cache.read_multi_entries(keys
|
131
|
+
local_entries = local_cache.read_multi_entries(keys)
|
149
132
|
missed_keys = keys - local_entries.keys
|
150
133
|
|
151
134
|
if missed_keys.any?
|
@@ -155,30 +138,27 @@ module ActiveSupport
|
|
155
138
|
end
|
156
139
|
end
|
157
140
|
|
158
|
-
def
|
159
|
-
if
|
160
|
-
local_cache.
|
141
|
+
def write_serialized_entry(key, payload, **)
|
142
|
+
if return_value = super
|
143
|
+
local_cache.write_entry(key, payload) if local_cache
|
161
144
|
else
|
162
|
-
local_cache.
|
145
|
+
local_cache.delete_entry(key) if local_cache
|
163
146
|
end
|
164
|
-
|
165
|
-
super
|
147
|
+
return_value
|
166
148
|
end
|
167
149
|
|
168
|
-
def delete_entry(key, **
|
169
|
-
local_cache.delete_entry(key
|
150
|
+
def delete_entry(key, **)
|
151
|
+
local_cache.delete_entry(key) if local_cache
|
170
152
|
super
|
171
153
|
end
|
172
154
|
|
173
155
|
def write_cache_value(name, value, **options)
|
174
156
|
name = normalize_key(name, options)
|
175
157
|
cache = local_cache
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
cache.delete(name, **options)
|
181
|
-
end
|
158
|
+
if value
|
159
|
+
cache.write_entry(name, serialize_entry(new_entry(value, **options), **options))
|
160
|
+
else
|
161
|
+
cache.delete_entry(name)
|
182
162
|
end
|
183
163
|
end
|
184
164
|
|
@@ -190,8 +170,8 @@ module ActiveSupport
|
|
190
170
|
LocalCacheRegistry.cache_for(local_cache_key)
|
191
171
|
end
|
192
172
|
|
193
|
-
def bypass_local_cache
|
194
|
-
use_temporary_local_cache(nil)
|
173
|
+
def bypass_local_cache(&block)
|
174
|
+
use_temporary_local_cache(nil, &block)
|
195
175
|
end
|
196
176
|
|
197
177
|
def use_temporary_local_cache(temporary_cache)
|
data/lib/active_support/cache.rb
CHANGED
@@ -22,13 +22,24 @@ module ActiveSupport
|
|
22
22
|
|
23
23
|
# These options mean something to all cache implementations. Individual cache
|
24
24
|
# implementations may support additional options.
|
25
|
-
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
|
25
|
+
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :expire_in, :expired_in, :race_condition_ttl, :coder, :skip_nil]
|
26
|
+
|
27
|
+
DEFAULT_COMPRESS_LIMIT = 1.kilobyte
|
28
|
+
|
29
|
+
# Mapping of canonical option names to aliases that a store will recognize.
|
30
|
+
OPTION_ALIASES = {
|
31
|
+
expires_in: [:expire_in, :expired_in]
|
32
|
+
}.freeze
|
26
33
|
|
27
34
|
module Strategy
|
28
35
|
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
29
36
|
end
|
30
37
|
|
38
|
+
@format_version = 6.1
|
39
|
+
|
31
40
|
class << self
|
41
|
+
attr_accessor :format_version
|
42
|
+
|
32
43
|
# Creates a new Store object according to the given options.
|
33
44
|
#
|
34
45
|
# If no arguments are passed to this method, then a new
|
@@ -164,8 +175,6 @@ module ActiveSupport
|
|
164
175
|
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
165
176
|
# specified in bytes.
|
166
177
|
class Store
|
167
|
-
DEFAULT_CODER = Marshal
|
168
|
-
|
169
178
|
cattr_accessor :logger, instance_writer: true
|
170
179
|
|
171
180
|
attr_reader :silence, :options
|
@@ -192,8 +201,12 @@ module ActiveSupport
|
|
192
201
|
# except for <tt>:namespace</tt> which can be used to set the global
|
193
202
|
# namespace for the cache.
|
194
203
|
def initialize(options = nil)
|
195
|
-
@options = options ? options
|
196
|
-
@
|
204
|
+
@options = options ? normalize_options(options) : {}
|
205
|
+
@options[:compress] = true unless @options.key?(:compress)
|
206
|
+
@options[:compress_threshold] = DEFAULT_COMPRESS_LIMIT unless @options.key?(:compress_threshold)
|
207
|
+
|
208
|
+
@coder = @options.delete(:coder) { default_coder } || NullCoder
|
209
|
+
@coder_supports_compression = @coder.respond_to?(:dump_compressed)
|
197
210
|
end
|
198
211
|
|
199
212
|
# Silences the logger.
|
@@ -255,11 +268,21 @@ module ActiveSupport
|
|
255
268
|
# All caches support auto-expiring content after a specified number of
|
256
269
|
# seconds. This value can be specified as an option to the constructor
|
257
270
|
# (in which case all entries will be affected), or it can be supplied to
|
258
|
-
# the +fetch+ or +write+ method to
|
271
|
+
# the +fetch+ or +write+ method to affect just one entry.
|
272
|
+
# <tt>:expire_in</tt> and <tt>:expired_in</tt> are aliases for
|
273
|
+
# <tt>:expires_in</tt>.
|
259
274
|
#
|
260
275
|
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
261
276
|
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
|
262
277
|
#
|
278
|
+
# Setting <tt>:expires_at</tt> will set an absolute expiration time on the cache.
|
279
|
+
# All caches support auto-expiring content after a specified number of
|
280
|
+
# seconds. This value can only be supplied to the +fetch+ or +write+ method to
|
281
|
+
# affect just one entry.
|
282
|
+
#
|
283
|
+
# cache = ActiveSupport::Cache::MemoryStore.new
|
284
|
+
# cache.write(key, value, expires_at: Time.now.at_end_of_hour)
|
285
|
+
#
|
263
286
|
# Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
|
264
287
|
# is of the same version. nil is returned on mismatches despite contents.
|
265
288
|
# This feature is used to support recyclable cache keys.
|
@@ -512,6 +535,10 @@ module ActiveSupport
|
|
512
535
|
end
|
513
536
|
end
|
514
537
|
|
538
|
+
def new_entry(value, options = nil) # :nodoc:
|
539
|
+
Entry.new(value, **merged_options(options))
|
540
|
+
end
|
541
|
+
|
515
542
|
# Deletes all entries with keys matching the pattern.
|
516
543
|
#
|
517
544
|
# Options are passed to the underlying cache implementation.
|
@@ -559,6 +586,10 @@ module ActiveSupport
|
|
559
586
|
end
|
560
587
|
|
561
588
|
private
|
589
|
+
def default_coder
|
590
|
+
Coders[Cache.format_version]
|
591
|
+
end
|
592
|
+
|
562
593
|
# Adds the namespace defined in the options to a pattern designed to
|
563
594
|
# match keys. Implementations that support delete_matched should call
|
564
595
|
# this method to translate a pattern that matches names into one that
|
@@ -590,8 +621,13 @@ module ActiveSupport
|
|
590
621
|
raise NotImplementedError.new
|
591
622
|
end
|
592
623
|
|
593
|
-
def serialize_entry(entry)
|
594
|
-
|
624
|
+
def serialize_entry(entry, **options)
|
625
|
+
options = merged_options(options)
|
626
|
+
if @coder_supports_compression && options[:compress]
|
627
|
+
@coder.dump_compressed(entry, options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT)
|
628
|
+
else
|
629
|
+
@coder.dump(entry)
|
630
|
+
end
|
595
631
|
end
|
596
632
|
|
597
633
|
def deserialize_entry(payload)
|
@@ -640,6 +676,7 @@ module ActiveSupport
|
|
640
676
|
# Merges the default options with ones specific to a method call.
|
641
677
|
def merged_options(call_options)
|
642
678
|
if call_options
|
679
|
+
call_options = normalize_options(call_options)
|
643
680
|
if options.empty?
|
644
681
|
call_options
|
645
682
|
else
|
@@ -650,6 +687,18 @@ module ActiveSupport
|
|
650
687
|
end
|
651
688
|
end
|
652
689
|
|
690
|
+
# Normalize aliased options to their canonical form
|
691
|
+
def normalize_options(options)
|
692
|
+
options = options.dup
|
693
|
+
OPTION_ALIASES.each do |canonical_name, aliases|
|
694
|
+
alias_key = aliases.detect { |key| options.key?(key) }
|
695
|
+
options[canonical_name] ||= options[alias_key] if alias_key
|
696
|
+
options.except!(*aliases)
|
697
|
+
end
|
698
|
+
|
699
|
+
options
|
700
|
+
end
|
701
|
+
|
653
702
|
# Expands and namespaces the cache key. May be overridden by
|
654
703
|
# cache stores to do additional normalization.
|
655
704
|
def normalize_key(key, options = nil)
|
@@ -732,7 +781,7 @@ module ActiveSupport
|
|
732
781
|
if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
|
733
782
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
734
783
|
# for a brief period while the entry is being recalculated.
|
735
|
-
entry.expires_at = Time.now + race_ttl
|
784
|
+
entry.expires_at = Time.now.to_f + race_ttl
|
736
785
|
write_entry(key, entry, expires_in: race_ttl * 2)
|
737
786
|
else
|
738
787
|
delete_entry(key, **options)
|
@@ -758,13 +807,93 @@ module ActiveSupport
|
|
758
807
|
end
|
759
808
|
|
760
809
|
module NullCoder # :nodoc:
|
810
|
+
extend self
|
811
|
+
|
812
|
+
def dump(entry)
|
813
|
+
entry
|
814
|
+
end
|
815
|
+
|
816
|
+
def dump_compressed(entry, threshold)
|
817
|
+
entry.compressed(threshold)
|
818
|
+
end
|
819
|
+
|
820
|
+
def load(payload)
|
821
|
+
payload
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
module Coders # :nodoc:
|
826
|
+
MARK_61 = "\x04\b".b.freeze # The one set by Marshal.
|
827
|
+
MARK_70_UNCOMPRESSED = "\x00".b.freeze
|
828
|
+
MARK_70_COMPRESSED = "\x01".b.freeze
|
829
|
+
|
761
830
|
class << self
|
831
|
+
def [](version)
|
832
|
+
case version
|
833
|
+
when 6.1
|
834
|
+
Rails61Coder
|
835
|
+
when 7.0
|
836
|
+
Rails70Coder
|
837
|
+
else
|
838
|
+
raise ArgumentError, "Unknown ActiveSupport::Cache.format_version #{Cache.format_version.inspect}"
|
839
|
+
end
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
module Loader
|
844
|
+
extend self
|
845
|
+
|
762
846
|
def load(payload)
|
763
|
-
payload
|
847
|
+
if !payload.is_a?(String)
|
848
|
+
ActiveSupport::Cache::Store.logger&.warn %{Payload wasn't a string, was #{payload.class.name} - couldn't unmarshal, so returning nil."}
|
849
|
+
|
850
|
+
return nil
|
851
|
+
elsif payload.start_with?(MARK_70_UNCOMPRESSED)
|
852
|
+
members = Marshal.load(payload.byteslice(1..-1))
|
853
|
+
elsif payload.start_with?(MARK_70_COMPRESSED)
|
854
|
+
members = Marshal.load(Zlib::Inflate.inflate(payload.byteslice(1..-1)))
|
855
|
+
elsif payload.start_with?(MARK_61)
|
856
|
+
return Marshal.load(payload)
|
857
|
+
else
|
858
|
+
ActiveSupport::Cache::Store.logger&.warn %{Invalid cache prefix: #{payload.byteslice(0).inspect}, expected "\\x00" or "\\x01"}
|
859
|
+
|
860
|
+
return nil
|
861
|
+
end
|
862
|
+
Entry.unpack(members)
|
764
863
|
end
|
864
|
+
end
|
865
|
+
|
866
|
+
module Rails61Coder
|
867
|
+
include Loader
|
868
|
+
extend self
|
765
869
|
|
766
870
|
def dump(entry)
|
767
|
-
entry
|
871
|
+
Marshal.dump(entry)
|
872
|
+
end
|
873
|
+
|
874
|
+
def dump_compressed(entry, threshold)
|
875
|
+
Marshal.dump(entry.compressed(threshold))
|
876
|
+
end
|
877
|
+
end
|
878
|
+
|
879
|
+
module Rails70Coder
|
880
|
+
include Loader
|
881
|
+
extend self
|
882
|
+
|
883
|
+
def dump(entry)
|
884
|
+
MARK_70_UNCOMPRESSED + Marshal.dump(entry.pack)
|
885
|
+
end
|
886
|
+
|
887
|
+
def dump_compressed(entry, threshold)
|
888
|
+
payload = Marshal.dump(entry.pack)
|
889
|
+
if payload.bytesize >= threshold
|
890
|
+
compressed_payload = Zlib::Deflate.deflate(payload)
|
891
|
+
if compressed_payload.bytesize < payload.bytesize
|
892
|
+
return MARK_70_COMPRESSED + compressed_payload
|
893
|
+
end
|
894
|
+
end
|
895
|
+
|
896
|
+
MARK_70_UNCOMPRESSED + payload
|
768
897
|
end
|
769
898
|
end
|
770
899
|
end
|
@@ -777,19 +906,22 @@ module ActiveSupport
|
|
777
906
|
# Since cache entries in most instances will be serialized, the internals of this class are highly optimized
|
778
907
|
# using short instance variable names that are lazily defined.
|
779
908
|
class Entry # :nodoc:
|
780
|
-
|
909
|
+
class << self
|
910
|
+
def unpack(members)
|
911
|
+
new(members[0], expires_at: members[1], version: members[2])
|
912
|
+
end
|
913
|
+
end
|
781
914
|
|
782
|
-
|
915
|
+
attr_reader :version
|
783
916
|
|
784
917
|
# Creates a new cache entry for the specified value. Options supported are
|
785
|
-
# +:
|
786
|
-
def initialize(value,
|
918
|
+
# +:compressed+, +:version+, +:expires_at+ and +:expires_in+.
|
919
|
+
def initialize(value, compressed: false, version: nil, expires_in: nil, expires_at: nil, **)
|
787
920
|
@value = value
|
788
921
|
@version = version
|
789
|
-
@created_at =
|
790
|
-
@expires_in = expires_in && expires_in.to_f
|
791
|
-
|
792
|
-
compress!(compress_threshold) if compress
|
922
|
+
@created_at = 0.0
|
923
|
+
@expires_in = expires_at&.to_f || expires_in && (expires_in.to_f + Time.now.to_f)
|
924
|
+
@compressed = true if compressed
|
793
925
|
end
|
794
926
|
|
795
927
|
def value
|
@@ -831,6 +963,38 @@ module ActiveSupport
|
|
831
963
|
end
|
832
964
|
end
|
833
965
|
|
966
|
+
def compressed? # :nodoc:
|
967
|
+
defined?(@compressed)
|
968
|
+
end
|
969
|
+
|
970
|
+
def compressed(compress_threshold)
|
971
|
+
return self if compressed?
|
972
|
+
|
973
|
+
case @value
|
974
|
+
when nil, true, false, Numeric
|
975
|
+
uncompressed_size = 0
|
976
|
+
when String
|
977
|
+
uncompressed_size = @value.bytesize
|
978
|
+
else
|
979
|
+
serialized = Marshal.dump(@value)
|
980
|
+
uncompressed_size = serialized.bytesize
|
981
|
+
end
|
982
|
+
|
983
|
+
if uncompressed_size >= compress_threshold
|
984
|
+
serialized ||= Marshal.dump(@value)
|
985
|
+
compressed = Zlib::Deflate.deflate(serialized)
|
986
|
+
|
987
|
+
if compressed.bytesize < uncompressed_size
|
988
|
+
return Entry.new(compressed, compressed: true, expires_at: expires_at, version: version)
|
989
|
+
end
|
990
|
+
end
|
991
|
+
self
|
992
|
+
end
|
993
|
+
|
994
|
+
def local?
|
995
|
+
false
|
996
|
+
end
|
997
|
+
|
834
998
|
# Duplicates the value in a class. This is used by cache implementations that don't natively
|
835
999
|
# serialize entries to protect against accidental cache modifications.
|
836
1000
|
def dup_value!
|
@@ -843,33 +1007,13 @@ module ActiveSupport
|
|
843
1007
|
end
|
844
1008
|
end
|
845
1009
|
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
when String
|
852
|
-
uncompressed_size = @value.bytesize
|
853
|
-
else
|
854
|
-
serialized = Marshal.dump(@value)
|
855
|
-
uncompressed_size = serialized.bytesize
|
856
|
-
end
|
857
|
-
|
858
|
-
if uncompressed_size >= compress_threshold
|
859
|
-
serialized ||= Marshal.dump(@value)
|
860
|
-
compressed = Zlib::Deflate.deflate(serialized)
|
861
|
-
|
862
|
-
if compressed.bytesize < uncompressed_size
|
863
|
-
@value = compressed
|
864
|
-
@compressed = true
|
865
|
-
end
|
866
|
-
end
|
867
|
-
end
|
868
|
-
|
869
|
-
def compressed?
|
870
|
-
defined?(@compressed)
|
871
|
-
end
|
1010
|
+
def pack
|
1011
|
+
members = [value, expires_at, version]
|
1012
|
+
members.pop while !members.empty? && members.last.nil?
|
1013
|
+
members
|
1014
|
+
end
|
872
1015
|
|
1016
|
+
private
|
873
1017
|
def uncompress(value)
|
874
1018
|
Marshal.load(Zlib::Inflate.inflate(value))
|
875
1019
|
end
|
@@ -5,6 +5,7 @@ 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
7
|
require "active_support/core_ext/string/filters"
|
8
|
+
require "active_support/core_ext/object/blank"
|
8
9
|
require "thread"
|
9
10
|
|
10
11
|
module ActiveSupport
|
@@ -276,7 +277,7 @@ module ActiveSupport
|
|
276
277
|
end
|
277
278
|
end
|
278
279
|
|
279
|
-
class Callback
|
280
|
+
class Callback # :nodoc:#
|
280
281
|
def self.build(chain, filter, kind, options)
|
281
282
|
if filter.is_a?(String)
|
282
283
|
raise ArgumentError, <<-MSG.squish
|
@@ -289,21 +290,17 @@ module ActiveSupport
|
|
289
290
|
end
|
290
291
|
|
291
292
|
attr_accessor :kind, :name
|
292
|
-
attr_reader :chain_config
|
293
|
+
attr_reader :chain_config, :filter
|
293
294
|
|
294
295
|
def initialize(name, filter, kind, options, chain_config)
|
295
296
|
@chain_config = chain_config
|
296
297
|
@name = name
|
297
298
|
@kind = kind
|
298
299
|
@filter = filter
|
299
|
-
@key = compute_identifier filter
|
300
300
|
@if = check_conditionals(options[:if])
|
301
301
|
@unless = check_conditionals(options[:unless])
|
302
302
|
end
|
303
303
|
|
304
|
-
def filter; @key; end
|
305
|
-
def raw_filter; @filter; end
|
306
|
-
|
307
304
|
def merge_conditional_options(chain, if_option:, unless_option:)
|
308
305
|
options = {
|
309
306
|
if: @if.dup,
|
@@ -356,7 +353,7 @@ module ActiveSupport
|
|
356
353
|
return EMPTY_ARRAY if conditionals.blank?
|
357
354
|
|
358
355
|
conditionals = Array(conditionals)
|
359
|
-
if conditionals.any?
|
356
|
+
if conditionals.any?(String)
|
360
357
|
raise ArgumentError, <<-MSG.squish
|
361
358
|
Passing string to be evaluated in :if and :unless conditional
|
362
359
|
options is not supported. Pass a symbol for an instance method,
|
@@ -367,15 +364,6 @@ module ActiveSupport
|
|
367
364
|
conditionals.freeze
|
368
365
|
end
|
369
366
|
|
370
|
-
def compute_identifier(filter)
|
371
|
-
case filter
|
372
|
-
when ::Proc
|
373
|
-
filter.object_id
|
374
|
-
else
|
375
|
-
filter
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
367
|
def conditions_lambdas
|
380
368
|
@if.map { |c| CallTemplate.build(c, self).make_lambda } +
|
381
369
|
@unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
|
@@ -517,7 +505,7 @@ module ActiveSupport
|
|
517
505
|
end
|
518
506
|
end
|
519
507
|
|
520
|
-
class CallbackChain
|
508
|
+
class CallbackChain # :nodoc:#
|
521
509
|
include Enumerable
|
522
510
|
|
523
511
|
attr_reader :name, :config
|
@@ -619,7 +607,7 @@ module ActiveSupport
|
|
619
607
|
|
620
608
|
# This is used internally to append, prepend and skip callbacks to the
|
621
609
|
# CallbackChain.
|
622
|
-
def __update_callbacks(name)
|
610
|
+
def __update_callbacks(name) # :nodoc:
|
623
611
|
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target|
|
624
612
|
chain = target.get_callbacks name
|
625
613
|
yield target, chain.dup
|
@@ -688,10 +676,32 @@ module ActiveSupport
|
|
688
676
|
# <tt>:unless</tt> options may be passed in order to control when the
|
689
677
|
# callback is skipped.
|
690
678
|
#
|
691
|
-
# class Writer <
|
692
|
-
#
|
679
|
+
# class Writer < PersonRecord
|
680
|
+
# attr_accessor :age
|
681
|
+
# skip_callback :save, :before, :saving_message, if: -> { age > 18 }
|
693
682
|
# end
|
694
683
|
#
|
684
|
+
# When if option returns true, callback is skipped.
|
685
|
+
#
|
686
|
+
# writer = Writer.new
|
687
|
+
# writer.age = 20
|
688
|
+
# writer.save
|
689
|
+
#
|
690
|
+
# Output:
|
691
|
+
# - save
|
692
|
+
# saved
|
693
|
+
#
|
694
|
+
# When if option returns false, callback is NOT skipped.
|
695
|
+
#
|
696
|
+
# young_writer = Writer.new
|
697
|
+
# young_writer.age = 17
|
698
|
+
# young_writer.save
|
699
|
+
#
|
700
|
+
# Output:
|
701
|
+
# saving...
|
702
|
+
# - save
|
703
|
+
# saved
|
704
|
+
#
|
695
705
|
# An <tt>ArgumentError</tt> will be raised if the callback has not
|
696
706
|
# already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>).
|
697
707
|
def skip_callback(name, *filter_list, &block)
|
@@ -844,18 +854,12 @@ module ActiveSupport
|
|
844
854
|
__callbacks[name.to_sym]
|
845
855
|
end
|
846
856
|
|
847
|
-
|
848
|
-
|
849
|
-
self.__callbacks = __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
|
857
|
+
def set_callbacks(name, callbacks) # :nodoc:
|
858
|
+
unless singleton_class.method_defined?(:__callbacks, false)
|
859
|
+
self.__callbacks = __callbacks.dup
|
858
860
|
end
|
861
|
+
self.__callbacks[name.to_sym] = callbacks
|
862
|
+
self.__callbacks
|
859
863
|
end
|
860
864
|
end
|
861
865
|
end
|
@@ -108,23 +108,23 @@ module ActiveSupport
|
|
108
108
|
#
|
109
109
|
# <tt>prepend</tt> is also used for any dependencies.
|
110
110
|
module Concern
|
111
|
-
class MultipleIncludedBlocks < StandardError
|
111
|
+
class MultipleIncludedBlocks < StandardError # :nodoc:
|
112
112
|
def initialize
|
113
113
|
super "Cannot define multiple 'included' blocks for a Concern"
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
class MultiplePrependBlocks < StandardError
|
117
|
+
class MultiplePrependBlocks < StandardError # :nodoc:
|
118
118
|
def initialize
|
119
119
|
super "Cannot define multiple 'prepended' blocks for a Concern"
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
def self.extended(base)
|
123
|
+
def self.extended(base) # :nodoc:
|
124
124
|
base.instance_variable_set(:@_dependencies, [])
|
125
125
|
end
|
126
126
|
|
127
|
-
def append_features(base)
|
127
|
+
def append_features(base) # :nodoc:
|
128
128
|
if base.instance_variable_defined?(:@_dependencies)
|
129
129
|
base.instance_variable_get(:@_dependencies) << self
|
130
130
|
false
|
@@ -137,7 +137,7 @@ module ActiveSupport
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
-
def prepend_features(base)
|
140
|
+
def prepend_features(base) # :nodoc:
|
141
141
|
if base.instance_variable_defined?(:@_dependencies)
|
142
142
|
base.instance_variable_get(:@_dependencies).unshift self
|
143
143
|
false
|