activesupport 6.0.3.4 → 6.1.3
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 +371 -448
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support.rb +13 -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.rb +85 -44
- data/lib/active_support/cache/file_store.rb +4 -3
- data/lib/active_support/cache/mem_cache_store.rb +29 -18
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +27 -27
- data/lib/active_support/cache/strategy/local_cache.rb +21 -6
- 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 +46 -0
- data/lib/active_support/core_ext.rb +1 -1
- 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/except.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 +13 -2
- 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 +10 -10
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/time/calculations.rb +27 -3
- 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/current_attributes.rb +7 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/dependencies.rb +43 -19
- data/lib/active_support/deprecation.rb +6 -1
- 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 +3 -3
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/duration.rb +71 -22
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- 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 +62 -0
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +43 -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/metadata.rb +9 -1
- 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.rb +32 -5
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -7
- 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 +3 -3
- data/lib/active_support/number_helper/rounding_helper.rb +12 -28
- data/lib/active_support/option_merger.rb +3 -2
- 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.rb +12 -95
- 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/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
- 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
@@ -7,6 +7,8 @@ rescue LoadError => e
|
|
7
7
|
raise e
|
8
8
|
end
|
9
9
|
|
10
|
+
require "active_support/core_ext/enumerable"
|
11
|
+
require "active_support/core_ext/marshal"
|
10
12
|
require "active_support/core_ext/array/extract_options"
|
11
13
|
|
12
14
|
module ActiveSupport
|
@@ -24,6 +26,8 @@ module ActiveSupport
|
|
24
26
|
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
25
27
|
# an in-memory cache inside of a block.
|
26
28
|
class MemCacheStore < Store
|
29
|
+
DEFAULT_CODER = NullCoder # Dalli automatically Marshal values
|
30
|
+
|
27
31
|
# Provide support for raw values in the local cache strategy.
|
28
32
|
module LocalCacheWithRaw # :nodoc:
|
29
33
|
private
|
@@ -49,16 +53,18 @@ module ActiveSupport
|
|
49
53
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
50
54
|
|
51
55
|
# Creates a new Dalli::Client instance with specified addresses and options.
|
52
|
-
#
|
56
|
+
# If no addresses are provided, we give nil to Dalli::Client, so it uses its fallbacks:
|
57
|
+
# - ENV["MEMCACHE_SERVERS"] (if defined)
|
58
|
+
# - "127.0.0.1:11211" (otherwise)
|
53
59
|
#
|
54
60
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache
|
55
|
-
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["
|
61
|
+
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
|
56
62
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
|
57
63
|
# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
|
58
64
|
def self.build_mem_cache(*addresses) # :nodoc:
|
59
65
|
addresses = addresses.flatten
|
60
66
|
options = addresses.extract_options!
|
61
|
-
addresses =
|
67
|
+
addresses = nil if addresses.compact.empty?
|
62
68
|
pool_options = retrieve_pool_options(options)
|
63
69
|
|
64
70
|
if pool_options.empty?
|
@@ -75,8 +81,8 @@ module ActiveSupport
|
|
75
81
|
#
|
76
82
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
77
83
|
#
|
78
|
-
# If no addresses are
|
79
|
-
#
|
84
|
+
# If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
|
85
|
+
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
80
86
|
def initialize(*addresses)
|
81
87
|
addresses = addresses.flatten
|
82
88
|
options = addresses.extract_options!
|
@@ -139,21 +145,22 @@ module ActiveSupport
|
|
139
145
|
|
140
146
|
# Write an entry to the cache.
|
141
147
|
def write_entry(key, entry, **options)
|
142
|
-
method = options
|
143
|
-
value = options[:raw] ? entry.value.to_s : entry
|
148
|
+
method = options[:unless_exist] ? :add : :set
|
149
|
+
value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
|
144
150
|
expires_in = options[:expires_in].to_i
|
145
|
-
if expires_in > 0 && !options[:raw]
|
151
|
+
if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
|
146
152
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
147
153
|
expires_in += 5.minutes
|
148
154
|
end
|
149
155
|
rescue_error_with false do
|
150
|
-
|
156
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
157
|
+
@data.with { |c| c.send(method, key, value, expires_in, **options, compress: false) }
|
151
158
|
end
|
152
159
|
end
|
153
160
|
|
154
161
|
# Reads multiple entries from the cache implementation.
|
155
162
|
def read_multi_entries(names, **options)
|
156
|
-
keys_to_names =
|
163
|
+
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
157
164
|
|
158
165
|
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
159
166
|
values = {}
|
@@ -178,17 +185,21 @@ module ActiveSupport
|
|
178
185
|
# before applying the regular expression to ensure we are escaping all
|
179
186
|
# characters properly.
|
180
187
|
def normalize_key(key, options)
|
181
|
-
key = super
|
182
|
-
|
183
|
-
|
184
|
-
|
188
|
+
key = super
|
189
|
+
|
190
|
+
if key
|
191
|
+
key = key.dup.force_encoding(Encoding::ASCII_8BIT)
|
192
|
+
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
193
|
+
key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
|
194
|
+
end
|
195
|
+
|
185
196
|
key
|
186
197
|
end
|
187
198
|
|
188
|
-
def deserialize_entry(
|
189
|
-
|
190
|
-
|
191
|
-
|
199
|
+
def deserialize_entry(payload)
|
200
|
+
entry = super
|
201
|
+
entry = Entry.new(entry, compress: false) if entry && !entry.is_a?(Entry)
|
202
|
+
entry
|
192
203
|
end
|
193
204
|
|
194
205
|
def rescue_error_with(fallback)
|
@@ -16,13 +16,37 @@ module ActiveSupport
|
|
16
16
|
# a cleanup will occur which tries to prune the cache down to three quarters
|
17
17
|
# of the maximum size by removing the least recently used entries.
|
18
18
|
#
|
19
|
+
# Unlike other Cache store implementations, MemoryStore does not compress
|
20
|
+
# values by default. MemoryStore does not benefit from compression as much
|
21
|
+
# as other Store implementations, as it does not send data over a network.
|
22
|
+
# However, when compression is enabled, it still pays the full cost of
|
23
|
+
# compression in terms of cpu use.
|
24
|
+
#
|
19
25
|
# MemoryStore is thread-safe.
|
20
26
|
class MemoryStore < Store
|
27
|
+
module DupCoder # :nodoc:
|
28
|
+
class << self
|
29
|
+
def load(entry)
|
30
|
+
entry = entry.dup
|
31
|
+
entry.dup_value!
|
32
|
+
entry
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump(entry)
|
36
|
+
entry.dup_value!
|
37
|
+
entry
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
DEFAULT_CODER = DupCoder
|
43
|
+
|
21
44
|
def initialize(options = nil)
|
22
45
|
options ||= {}
|
46
|
+
# Disable compression by default.
|
47
|
+
options[:compress] ||= false
|
23
48
|
super(options)
|
24
49
|
@data = {}
|
25
|
-
@key_access = {}
|
26
50
|
@max_size = options[:size] || 32.megabytes
|
27
51
|
@max_prune_time = options[:max_prune_time] || 2
|
28
52
|
@cache_size = 0
|
@@ -39,7 +63,6 @@ module ActiveSupport
|
|
39
63
|
def clear(options = nil)
|
40
64
|
synchronize do
|
41
65
|
@data.clear
|
42
|
-
@key_access.clear
|
43
66
|
@cache_size = 0
|
44
67
|
end
|
45
68
|
end
|
@@ -65,7 +88,7 @@ module ActiveSupport
|
|
65
88
|
start_time = Concurrent.monotonic_time
|
66
89
|
cleanup
|
67
90
|
instrument(:prune, target_size, from: @cache_size) do
|
68
|
-
keys = synchronize { @
|
91
|
+
keys = synchronize { @data.keys }
|
69
92
|
keys.each do |key|
|
70
93
|
delete_entry(key, **options)
|
71
94
|
return if @cache_size <= target_size || (max_time && Concurrent.monotonic_time - start_time > max_time)
|
@@ -104,7 +127,7 @@ module ActiveSupport
|
|
104
127
|
end
|
105
128
|
|
106
129
|
def inspect # :nodoc:
|
107
|
-
"
|
130
|
+
"#<#{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
|
108
131
|
end
|
109
132
|
|
110
133
|
# Synchronize calls to the cache. This should be called wherever the underlying cache implementation
|
@@ -116,36 +139,34 @@ module ActiveSupport
|
|
116
139
|
private
|
117
140
|
PER_ENTRY_OVERHEAD = 240
|
118
141
|
|
119
|
-
def cached_size(key,
|
120
|
-
key.to_s.bytesize +
|
142
|
+
def cached_size(key, payload)
|
143
|
+
key.to_s.bytesize + payload.bytesize + PER_ENTRY_OVERHEAD
|
121
144
|
end
|
122
145
|
|
123
146
|
def read_entry(key, **options)
|
124
|
-
entry =
|
147
|
+
entry = nil
|
125
148
|
synchronize do
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
else
|
131
|
-
@key_access.delete(key)
|
149
|
+
payload = @data.delete(key)
|
150
|
+
if payload
|
151
|
+
@data[key] = payload
|
152
|
+
entry = deserialize_entry(payload)
|
132
153
|
end
|
133
154
|
end
|
134
155
|
entry
|
135
156
|
end
|
136
157
|
|
137
158
|
def write_entry(key, entry, **options)
|
138
|
-
entry
|
159
|
+
payload = serialize_entry(entry)
|
139
160
|
synchronize do
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
161
|
+
return false if options[:unless_exist] && @data.key?(key)
|
162
|
+
|
163
|
+
old_payload = @data[key]
|
164
|
+
if old_payload
|
165
|
+
@cache_size -= (old_payload.bytesize - payload.bytesize)
|
144
166
|
else
|
145
|
-
@cache_size += cached_size(key,
|
167
|
+
@cache_size += cached_size(key, payload)
|
146
168
|
end
|
147
|
-
@
|
148
|
-
@data[key] = entry
|
169
|
+
@data[key] = payload
|
149
170
|
prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
|
150
171
|
true
|
151
172
|
end
|
@@ -153,16 +174,15 @@ module ActiveSupport
|
|
153
174
|
|
154
175
|
def delete_entry(key, **options)
|
155
176
|
synchronize do
|
156
|
-
@
|
157
|
-
|
158
|
-
|
159
|
-
!!entry
|
177
|
+
payload = @data.delete(key)
|
178
|
+
@cache_size -= cached_size(key, payload) if payload
|
179
|
+
!!payload
|
160
180
|
end
|
161
181
|
end
|
162
182
|
|
163
183
|
def modify_value(name, amount, options)
|
184
|
+
options = merged_options(options)
|
164
185
|
synchronize do
|
165
|
-
options = merged_options(options)
|
166
186
|
if num = read(name, options)
|
167
187
|
num = num.to_i + amount
|
168
188
|
write(name, num, options)
|
@@ -169,7 +169,7 @@ module ActiveSupport
|
|
169
169
|
# Race condition TTL is not set by default. This can be used to avoid
|
170
170
|
# "thundering herd" cache writes when hot cache entries are expired.
|
171
171
|
# See <tt>ActiveSupport::Cache::Store#fetch</tt> for more.
|
172
|
-
def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
|
172
|
+
def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, coder: DEFAULT_CODER, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
|
173
173
|
@redis_options = redis_options
|
174
174
|
|
175
175
|
@max_key_bytesize = MAX_KEY_BYTESIZE
|
@@ -177,7 +177,8 @@ module ActiveSupport
|
|
177
177
|
|
178
178
|
super namespace: namespace,
|
179
179
|
compress: compress, compress_threshold: compress_threshold,
|
180
|
-
expires_in: expires_in, race_condition_ttl: race_condition_ttl
|
180
|
+
expires_in: expires_in, race_condition_ttl: race_condition_ttl,
|
181
|
+
coder: coder
|
181
182
|
end
|
182
183
|
|
183
184
|
def redis
|
@@ -195,7 +196,7 @@ module ActiveSupport
|
|
195
196
|
|
196
197
|
def inspect
|
197
198
|
instance = @redis || @redis_options
|
198
|
-
"
|
199
|
+
"#<#{self.class} options=#{options.inspect} redis=#{instance.inspect}>"
|
199
200
|
end
|
200
201
|
|
201
202
|
# Cache Store API implementation.
|
@@ -238,10 +239,14 @@ module ActiveSupport
|
|
238
239
|
pattern = namespace_key(matcher, options)
|
239
240
|
cursor = "0"
|
240
241
|
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
242
|
+
nodes = c.respond_to?(:nodes) ? c.nodes : [c]
|
243
|
+
|
244
|
+
nodes.each do |node|
|
245
|
+
begin
|
246
|
+
cursor, keys = node.scan(cursor, match: pattern, count: SCAN_BATCH_SIZE)
|
247
|
+
node.del(*keys) unless keys.empty?
|
248
|
+
end until cursor == "0"
|
249
|
+
end
|
245
250
|
end
|
246
251
|
end
|
247
252
|
end
|
@@ -347,7 +352,7 @@ module ActiveSupport
|
|
347
352
|
|
348
353
|
def read_multi_entries(names, **options)
|
349
354
|
if mget_capable?
|
350
|
-
read_multi_mget(*names)
|
355
|
+
read_multi_mget(*names, **options)
|
351
356
|
else
|
352
357
|
super
|
353
358
|
end
|
@@ -394,7 +399,7 @@ module ActiveSupport
|
|
394
399
|
modifiers[:nx] = unless_exist
|
395
400
|
modifiers[:px] = (1000 * expires_in.to_f).ceil if expires_in
|
396
401
|
|
397
|
-
redis.with { |c| c.set key, serialized_entry, modifiers }
|
402
|
+
redis.with { |c| c.set key, serialized_entry, **modifiers }
|
398
403
|
else
|
399
404
|
redis.with { |c| c.set key, serialized_entry }
|
400
405
|
end
|
@@ -414,6 +419,11 @@ module ActiveSupport
|
|
414
419
|
end
|
415
420
|
end
|
416
421
|
|
422
|
+
# Deletes multiple entries in the cache. Returns the number of entries deleted.
|
423
|
+
def delete_multi_entries(entries, **_options)
|
424
|
+
redis.with { |c| c.del(entries) }
|
425
|
+
end
|
426
|
+
|
417
427
|
# Nonstandard store provider API to write multiple values at once.
|
418
428
|
def write_multi_entries(entries, expires_in: nil, **options)
|
419
429
|
if entries.any?
|
@@ -429,11 +439,11 @@ module ActiveSupport
|
|
429
439
|
|
430
440
|
# Truncate keys that exceed 1kB.
|
431
441
|
def normalize_key(key, options)
|
432
|
-
truncate_key super
|
442
|
+
truncate_key super&.b
|
433
443
|
end
|
434
444
|
|
435
445
|
def truncate_key(key)
|
436
|
-
if key.bytesize > max_key_bytesize
|
446
|
+
if key && key.bytesize > max_key_bytesize
|
437
447
|
suffix = ":sha2:#{::Digest::SHA2.hexdigest(key)}"
|
438
448
|
truncate_at = max_key_bytesize - suffix.bytesize
|
439
449
|
"#{key.byteslice(0, truncate_at)}#{suffix}"
|
@@ -442,21 +452,11 @@ module ActiveSupport
|
|
442
452
|
end
|
443
453
|
end
|
444
454
|
|
445
|
-
def deserialize_entry(
|
446
|
-
if
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
if raw != written_raw
|
451
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
452
|
-
Using a different value for the raw option when reading and writing
|
453
|
-
to a cache key is deprecated for :redis_cache_store and Rails 6.0
|
454
|
-
will stop automatically detecting the format when reading to avoid
|
455
|
-
marshal loading untrusted raw strings.
|
456
|
-
MSG
|
457
|
-
end
|
458
|
-
|
459
|
-
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
455
|
+
def deserialize_entry(payload, raw:)
|
456
|
+
if payload && raw
|
457
|
+
Entry.new(payload, compress: false)
|
458
|
+
else
|
459
|
+
super(payload)
|
460
460
|
end
|
461
461
|
end
|
462
462
|
|
@@ -464,7 +464,7 @@ module ActiveSupport
|
|
464
464
|
if raw
|
465
465
|
entry.value.to_s
|
466
466
|
else
|
467
|
-
|
467
|
+
super(entry)
|
468
468
|
end
|
469
469
|
end
|
470
470
|
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/object/duplicable"
|
4
3
|
require "active_support/core_ext/string/inflections"
|
5
4
|
require "active_support/per_thread_registry"
|
6
5
|
|
@@ -65,8 +64,9 @@ module ActiveSupport
|
|
65
64
|
values
|
66
65
|
end
|
67
66
|
|
68
|
-
def write_entry(key,
|
69
|
-
|
67
|
+
def write_entry(key, entry, **options)
|
68
|
+
entry.dup_value!
|
69
|
+
@data[key] = entry
|
70
70
|
true
|
71
71
|
end
|
72
72
|
|
@@ -75,7 +75,10 @@ module ActiveSupport
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def fetch_entry(key, options = nil) # :nodoc:
|
78
|
-
@data.fetch(key) { @data[key] = yield }
|
78
|
+
entry = @data.fetch(key) { @data[key] = yield }
|
79
|
+
dup_entry = entry.dup
|
80
|
+
dup_entry&.dup_value!
|
81
|
+
dup_entry
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
@@ -104,6 +107,12 @@ module ActiveSupport
|
|
104
107
|
super
|
105
108
|
end
|
106
109
|
|
110
|
+
def delete_matched(matcher, options = nil) # :nodoc:
|
111
|
+
return super unless cache = local_cache
|
112
|
+
cache.clear
|
113
|
+
super
|
114
|
+
end
|
115
|
+
|
107
116
|
def increment(name, amount = 1, **options) # :nodoc:
|
108
117
|
return super unless local_cache
|
109
118
|
value = bypass_local_cache { super }
|
@@ -121,7 +130,13 @@ module ActiveSupport
|
|
121
130
|
private
|
122
131
|
def read_entry(key, **options)
|
123
132
|
if cache = local_cache
|
124
|
-
|
133
|
+
hit = true
|
134
|
+
value = cache.fetch_entry(key) do
|
135
|
+
hit = false
|
136
|
+
super
|
137
|
+
end
|
138
|
+
options[:event][:store] = cache.class.name if hit && options[:event]
|
139
|
+
value
|
125
140
|
else
|
126
141
|
super
|
127
142
|
end
|
@@ -160,7 +175,7 @@ module ActiveSupport
|
|
160
175
|
cache = local_cache
|
161
176
|
cache.mute do
|
162
177
|
if value
|
163
|
-
cache.write(name, value,
|
178
|
+
cache.write(name, value, options)
|
164
179
|
else
|
165
180
|
cache.delete(name, **options)
|
166
181
|
end
|
@@ -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
|