activesupport 6.0.3 → 6.1.0.rc1
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 +341 -455
- data/MIT-LICENSE +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 +80 -39
- data/lib/active_support/cache/file_store.rb +4 -3
- data/lib/active_support/cache/mem_cache_store.rb +20 -23
- data/lib/active_support/cache/memory_store.rb +38 -26
- data/lib/active_support/cache/redis_cache_store.rb +31 -26
- data/lib/active_support/cache/strategy/local_cache.rb +14 -5
- 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/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 +6 -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/string/access.rb +5 -24
- 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 +2 -3
- 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 +19 -1
- data/lib/active_support/core_ext/time/conversions.rb +1 -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 +37 -18
- 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 +58 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +35 -22
- 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 +31 -4
- 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 +15 -10
- 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/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 +66 -42
- data/lib/active_support/values/time_zone.rb +20 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- metadata +36 -38
- 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
@@ -18,11 +18,27 @@ module ActiveSupport
|
|
18
18
|
#
|
19
19
|
# MemoryStore is thread-safe.
|
20
20
|
class MemoryStore < Store
|
21
|
+
module DupCoder # :nodoc:
|
22
|
+
class << self
|
23
|
+
def load(entry)
|
24
|
+
entry = entry.dup
|
25
|
+
entry.dup_value!
|
26
|
+
entry
|
27
|
+
end
|
28
|
+
|
29
|
+
def dump(entry)
|
30
|
+
entry.dup_value!
|
31
|
+
entry
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
DEFAULT_CODER = DupCoder
|
37
|
+
|
21
38
|
def initialize(options = nil)
|
22
39
|
options ||= {}
|
23
40
|
super(options)
|
24
41
|
@data = {}
|
25
|
-
@key_access = {}
|
26
42
|
@max_size = options[:size] || 32.megabytes
|
27
43
|
@max_prune_time = options[:max_prune_time] || 2
|
28
44
|
@cache_size = 0
|
@@ -39,7 +55,6 @@ module ActiveSupport
|
|
39
55
|
def clear(options = nil)
|
40
56
|
synchronize do
|
41
57
|
@data.clear
|
42
|
-
@key_access.clear
|
43
58
|
@cache_size = 0
|
44
59
|
end
|
45
60
|
end
|
@@ -65,7 +80,7 @@ module ActiveSupport
|
|
65
80
|
start_time = Concurrent.monotonic_time
|
66
81
|
cleanup
|
67
82
|
instrument(:prune, target_size, from: @cache_size) do
|
68
|
-
keys = synchronize { @
|
83
|
+
keys = synchronize { @data.keys }
|
69
84
|
keys.each do |key|
|
70
85
|
delete_entry(key, **options)
|
71
86
|
return if @cache_size <= target_size || (max_time && Concurrent.monotonic_time - start_time > max_time)
|
@@ -104,7 +119,7 @@ module ActiveSupport
|
|
104
119
|
end
|
105
120
|
|
106
121
|
def inspect # :nodoc:
|
107
|
-
"
|
122
|
+
"#<#{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
|
108
123
|
end
|
109
124
|
|
110
125
|
# Synchronize calls to the cache. This should be called wherever the underlying cache implementation
|
@@ -116,36 +131,34 @@ module ActiveSupport
|
|
116
131
|
private
|
117
132
|
PER_ENTRY_OVERHEAD = 240
|
118
133
|
|
119
|
-
def cached_size(key,
|
120
|
-
key.to_s.bytesize +
|
134
|
+
def cached_size(key, payload)
|
135
|
+
key.to_s.bytesize + payload.bytesize + PER_ENTRY_OVERHEAD
|
121
136
|
end
|
122
137
|
|
123
138
|
def read_entry(key, **options)
|
124
|
-
entry =
|
139
|
+
entry = nil
|
125
140
|
synchronize do
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
else
|
131
|
-
@key_access.delete(key)
|
141
|
+
payload = @data.delete(key)
|
142
|
+
if payload
|
143
|
+
@data[key] = payload
|
144
|
+
entry = deserialize_entry(payload)
|
132
145
|
end
|
133
146
|
end
|
134
147
|
entry
|
135
148
|
end
|
136
149
|
|
137
150
|
def write_entry(key, entry, **options)
|
138
|
-
entry
|
151
|
+
payload = serialize_entry(entry)
|
139
152
|
synchronize do
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
153
|
+
return false if options[:unless_exist] && @data.key?(key)
|
154
|
+
|
155
|
+
old_payload = @data[key]
|
156
|
+
if old_payload
|
157
|
+
@cache_size -= (old_payload.bytesize - payload.bytesize)
|
144
158
|
else
|
145
|
-
@cache_size += cached_size(key,
|
159
|
+
@cache_size += cached_size(key, payload)
|
146
160
|
end
|
147
|
-
@
|
148
|
-
@data[key] = entry
|
161
|
+
@data[key] = payload
|
149
162
|
prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
|
150
163
|
true
|
151
164
|
end
|
@@ -153,16 +166,15 @@ module ActiveSupport
|
|
153
166
|
|
154
167
|
def delete_entry(key, **options)
|
155
168
|
synchronize do
|
156
|
-
@
|
157
|
-
|
158
|
-
|
159
|
-
!!entry
|
169
|
+
payload = @data.delete(key)
|
170
|
+
@cache_size -= cached_size(key, payload) if payload
|
171
|
+
!!payload
|
160
172
|
end
|
161
173
|
end
|
162
174
|
|
163
175
|
def modify_value(name, amount, options)
|
176
|
+
options = merged_options(options)
|
164
177
|
synchronize do
|
165
|
-
options = merged_options(options)
|
166
178
|
if num = read(name, options)
|
167
179
|
num = num.to_i + amount
|
168
180
|
write(name, num, options)
|
@@ -74,14 +74,6 @@ module ActiveSupport
|
|
74
74
|
# Support raw values in the local cache strategy.
|
75
75
|
module LocalCacheWithRaw # :nodoc:
|
76
76
|
private
|
77
|
-
def read_entry(key, **options)
|
78
|
-
entry = super
|
79
|
-
if options[:raw] && local_cache && entry
|
80
|
-
entry = deserialize_entry(entry.value)
|
81
|
-
end
|
82
|
-
entry
|
83
|
-
end
|
84
|
-
|
85
77
|
def write_entry(key, entry, **options)
|
86
78
|
if options[:raw] && local_cache
|
87
79
|
raw_entry = Entry.new(serialize_entry(entry, raw: true))
|
@@ -177,7 +169,7 @@ module ActiveSupport
|
|
177
169
|
# Race condition TTL is not set by default. This can be used to avoid
|
178
170
|
# "thundering herd" cache writes when hot cache entries are expired.
|
179
171
|
# See <tt>ActiveSupport::Cache::Store#fetch</tt> for more.
|
180
|
-
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)
|
181
173
|
@redis_options = redis_options
|
182
174
|
|
183
175
|
@max_key_bytesize = MAX_KEY_BYTESIZE
|
@@ -185,7 +177,8 @@ module ActiveSupport
|
|
185
177
|
|
186
178
|
super namespace: namespace,
|
187
179
|
compress: compress, compress_threshold: compress_threshold,
|
188
|
-
expires_in: expires_in, race_condition_ttl: race_condition_ttl
|
180
|
+
expires_in: expires_in, race_condition_ttl: race_condition_ttl,
|
181
|
+
coder: coder
|
189
182
|
end
|
190
183
|
|
191
184
|
def redis
|
@@ -203,7 +196,7 @@ module ActiveSupport
|
|
203
196
|
|
204
197
|
def inspect
|
205
198
|
instance = @redis || @redis_options
|
206
|
-
"
|
199
|
+
"#<#{self.class} options=#{options.inspect} redis=#{instance.inspect}>"
|
207
200
|
end
|
208
201
|
|
209
202
|
# Cache Store API implementation.
|
@@ -246,10 +239,14 @@ module ActiveSupport
|
|
246
239
|
pattern = namespace_key(matcher, options)
|
247
240
|
cursor = "0"
|
248
241
|
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
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
|
253
250
|
end
|
254
251
|
end
|
255
252
|
end
|
@@ -348,13 +345,14 @@ module ActiveSupport
|
|
348
345
|
# Read an entry from the cache.
|
349
346
|
def read_entry(key, **options)
|
350
347
|
failsafe :read_entry do
|
351
|
-
|
348
|
+
raw = options&.fetch(:raw, false)
|
349
|
+
deserialize_entry(redis.with { |c| c.get(key) }, raw: raw)
|
352
350
|
end
|
353
351
|
end
|
354
352
|
|
355
353
|
def read_multi_entries(names, **options)
|
356
354
|
if mget_capable?
|
357
|
-
read_multi_mget(*names)
|
355
|
+
read_multi_mget(*names, **options)
|
358
356
|
else
|
359
357
|
super
|
360
358
|
end
|
@@ -364,6 +362,7 @@ module ActiveSupport
|
|
364
362
|
options = names.extract_options!
|
365
363
|
options = merged_options(options)
|
366
364
|
return {} if names == []
|
365
|
+
raw = options&.fetch(:raw, false)
|
367
366
|
|
368
367
|
keys = names.map { |name| normalize_key(name, options) }
|
369
368
|
|
@@ -373,7 +372,7 @@ module ActiveSupport
|
|
373
372
|
|
374
373
|
names.zip(values).each_with_object({}) do |(name, value), results|
|
375
374
|
if value
|
376
|
-
entry = deserialize_entry(value)
|
375
|
+
entry = deserialize_entry(value, raw: raw)
|
377
376
|
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(name, options))
|
378
377
|
results[name] = entry.value
|
379
378
|
end
|
@@ -400,7 +399,7 @@ module ActiveSupport
|
|
400
399
|
modifiers[:nx] = unless_exist
|
401
400
|
modifiers[:px] = (1000 * expires_in.to_f).ceil if expires_in
|
402
401
|
|
403
|
-
redis.with { |c| c.set key, serialized_entry, modifiers }
|
402
|
+
redis.with { |c| c.set key, serialized_entry, **modifiers }
|
404
403
|
else
|
405
404
|
redis.with { |c| c.set key, serialized_entry }
|
406
405
|
end
|
@@ -420,6 +419,11 @@ module ActiveSupport
|
|
420
419
|
end
|
421
420
|
end
|
422
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
|
+
|
423
427
|
# Nonstandard store provider API to write multiple values at once.
|
424
428
|
def write_multi_entries(entries, expires_in: nil, **options)
|
425
429
|
if entries.any?
|
@@ -435,11 +439,11 @@ module ActiveSupport
|
|
435
439
|
|
436
440
|
# Truncate keys that exceed 1kB.
|
437
441
|
def normalize_key(key, options)
|
438
|
-
truncate_key super
|
442
|
+
truncate_key super&.b
|
439
443
|
end
|
440
444
|
|
441
445
|
def truncate_key(key)
|
442
|
-
if key.bytesize > max_key_bytesize
|
446
|
+
if key && key.bytesize > max_key_bytesize
|
443
447
|
suffix = ":sha2:#{::Digest::SHA2.hexdigest(key)}"
|
444
448
|
truncate_at = max_key_bytesize - suffix.bytesize
|
445
449
|
"#{key.byteslice(0, truncate_at)}#{suffix}"
|
@@ -448,10 +452,11 @@ module ActiveSupport
|
|
448
452
|
end
|
449
453
|
end
|
450
454
|
|
451
|
-
def deserialize_entry(
|
452
|
-
if
|
453
|
-
|
454
|
-
|
455
|
+
def deserialize_entry(payload, raw:)
|
456
|
+
if payload && raw
|
457
|
+
Entry.new(payload, compress: false)
|
458
|
+
else
|
459
|
+
super(payload)
|
455
460
|
end
|
456
461
|
end
|
457
462
|
|
@@ -459,7 +464,7 @@ module ActiveSupport
|
|
459
464
|
if raw
|
460
465
|
entry.value.to_s
|
461
466
|
else
|
462
|
-
|
467
|
+
super(entry)
|
463
468
|
end
|
464
469
|
end
|
465
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 }
|
@@ -160,7 +169,7 @@ module ActiveSupport
|
|
160
169
|
cache = local_cache
|
161
170
|
cache.mute do
|
162
171
|
if value
|
163
|
-
cache.write(name, value,
|
172
|
+
cache.write(name, value, options)
|
164
173
|
else
|
165
174
|
cache.delete(name, **options)
|
166
175
|
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
|