activesupport 7.2.2.1 → 8.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +277 -151
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +61 -74
- data/lib/active_support/cache/file_store.rb +14 -4
- data/lib/active_support/cache/mem_cache_store.rb +17 -16
- data/lib/active_support/cache/memory_store.rb +9 -5
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +7 -4
- data/lib/active_support/cache/strategy/local_cache.rb +56 -20
- data/lib/active_support/cache.rb +19 -14
- data/lib/active_support/callbacks.rb +8 -5
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/core_ext/array/conversions.rb +3 -3
- data/lib/active_support/core_ext/benchmark.rb +7 -9
- data/lib/active_support/core_ext/class/attribute.rb +26 -20
- data/lib/active_support/core_ext/date/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +2 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/module/attr_internal.rb +3 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/object/json.rb +16 -10
- data/lib/active_support/core_ext/object/to_query.rb +2 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +1 -0
- data/lib/active_support/core_ext/securerandom.rb +24 -8
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +3 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +14 -2
- data/lib/active_support/core_ext/time/compatibility.rb +9 -1
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/current_attributes.rb +14 -7
- data/lib/active_support/delegation.rb +25 -44
- data/lib/active_support/dependencies.rb +0 -1
- data/lib/active_support/deprecation/reporting.rb +0 -19
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration.rb +14 -10
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/error_reporter.rb +36 -3
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +1 -1
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +34 -31
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +2 -1
- data/lib/active_support/inflector/methods.rb +3 -3
- data/lib/active_support/isolated_execution_state.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -2
- data/lib/active_support/json/encoding.rb +25 -7
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- data/lib/active_support/message_encryptors.rb +2 -2
- data/lib/active_support/message_pack/extensions.rb +1 -1
- data/lib/active_support/message_verifier.rb +9 -0
- data/lib/active_support/message_verifiers.rb +5 -3
- data/lib/active_support/messages/rotator.rb +5 -0
- data/lib/active_support/multibyte/chars.rb +4 -1
- data/lib/active_support/notifications/fanout.rb +0 -1
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/railtie.rb +6 -0
- data/lib/active_support/tagged_logging.rb +5 -0
- data/lib/active_support/test_case.rb +6 -0
- data/lib/active_support/testing/assertions.rb +84 -21
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/parallelization/server.rb +15 -2
- data/lib/active_support/testing/parallelization/worker.rb +7 -3
- data/lib/active_support/testing/parallelization.rb +12 -1
- data/lib/active_support/testing/time_helpers.rb +2 -1
- data/lib/active_support/time_with_zone.rb +22 -13
- data/lib/active_support/values/time_zone.rb +11 -9
- data/lib/active_support/xml_mini.rb +2 -0
- data/lib/active_support.rb +10 -3
- metadata +24 -12
- data/lib/active_support/proxy_object.rb +0 -20
- data/lib/active_support/testing/strict_warnings.rb +0 -43
|
@@ -76,7 +76,6 @@ module ActiveSupport
|
|
|
76
76
|
|
|
77
77
|
# Returns all the logger that are part of this broadcast.
|
|
78
78
|
attr_reader :broadcasts
|
|
79
|
-
attr_reader :formatter
|
|
80
79
|
attr_accessor :progname
|
|
81
80
|
|
|
82
81
|
def initialize(*loggers)
|
|
@@ -105,131 +104,119 @@ module ActiveSupport
|
|
|
105
104
|
@broadcasts.delete(logger)
|
|
106
105
|
end
|
|
107
106
|
|
|
108
|
-
def level
|
|
109
|
-
@broadcasts.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def <<(message)
|
|
113
|
-
dispatch { |logger| logger.<<(message) }
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def add(...)
|
|
117
|
-
dispatch { |logger| logger.add(...) }
|
|
118
|
-
end
|
|
119
|
-
alias_method :log, :add
|
|
120
|
-
|
|
121
|
-
def debug(...)
|
|
122
|
-
dispatch { |logger| logger.debug(...) }
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def info(...)
|
|
126
|
-
dispatch { |logger| logger.info(...) }
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def warn(...)
|
|
130
|
-
dispatch { |logger| logger.warn(...) }
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def error(...)
|
|
134
|
-
dispatch { |logger| logger.error(...) }
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def fatal(...)
|
|
138
|
-
dispatch { |logger| logger.fatal(...) }
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def unknown(...)
|
|
142
|
-
dispatch { |logger| logger.unknown(...) }
|
|
107
|
+
def local_level=(level)
|
|
108
|
+
@broadcasts.each do |logger|
|
|
109
|
+
logger.local_level = level if logger.respond_to?(:local_level=)
|
|
110
|
+
end
|
|
143
111
|
end
|
|
144
112
|
|
|
145
|
-
def
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
@formatter = formatter
|
|
149
|
-
end
|
|
113
|
+
def local_level
|
|
114
|
+
loggers = @broadcasts.select { |logger| logger.respond_to?(:local_level) }
|
|
150
115
|
|
|
151
|
-
|
|
152
|
-
|
|
116
|
+
loggers.map do |logger|
|
|
117
|
+
logger.local_level
|
|
118
|
+
end.first
|
|
153
119
|
end
|
|
154
|
-
alias_method :sev_threshold=, :level=
|
|
155
120
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
121
|
+
LOGGER_METHODS = %w[
|
|
122
|
+
<< log add debug info warn error fatal unknown
|
|
123
|
+
level= sev_threshold= close
|
|
124
|
+
formatter formatter=
|
|
125
|
+
] # :nodoc:
|
|
126
|
+
LOGGER_METHODS.each do |method|
|
|
127
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
128
|
+
def #{method}(...)
|
|
129
|
+
dispatch(:#{method}, ...)
|
|
130
|
+
end
|
|
131
|
+
RUBY
|
|
160
132
|
end
|
|
161
133
|
|
|
162
|
-
|
|
163
|
-
|
|
134
|
+
# Returns the lowest level of all the loggers in the broadcast.
|
|
135
|
+
def level
|
|
136
|
+
@broadcasts.map(&:level).min
|
|
164
137
|
end
|
|
165
138
|
|
|
166
|
-
#
|
|
167
|
-
# to at least one broadcast.
|
|
139
|
+
# True if the log level allows entries with severity +Logger::DEBUG+ to be written
|
|
140
|
+
# to at least one broadcast. False otherwise.
|
|
168
141
|
def debug?
|
|
169
142
|
@broadcasts.any? { |logger| logger.debug? }
|
|
170
143
|
end
|
|
171
144
|
|
|
172
|
-
# Sets the log level to Logger::DEBUG for the whole broadcast.
|
|
145
|
+
# Sets the log level to +Logger::DEBUG+ for the whole broadcast.
|
|
173
146
|
def debug!
|
|
174
|
-
dispatch
|
|
147
|
+
dispatch(:debug!)
|
|
175
148
|
end
|
|
176
149
|
|
|
177
|
-
#
|
|
178
|
-
# to at least one broadcast.
|
|
150
|
+
# True if the log level allows entries with severity +Logger::INFO+ to be written
|
|
151
|
+
# to at least one broadcast. False otherwise.
|
|
179
152
|
def info?
|
|
180
153
|
@broadcasts.any? { |logger| logger.info? }
|
|
181
154
|
end
|
|
182
155
|
|
|
183
|
-
# Sets the log level to Logger::INFO for the whole broadcast.
|
|
156
|
+
# Sets the log level to +Logger::INFO+ for the whole broadcast.
|
|
184
157
|
def info!
|
|
185
|
-
dispatch
|
|
158
|
+
dispatch(:info!)
|
|
186
159
|
end
|
|
187
160
|
|
|
188
|
-
#
|
|
189
|
-
# to at least one broadcast.
|
|
161
|
+
# True if the log level allows entries with severity +Logger::WARN+ to be written
|
|
162
|
+
# to at least one broadcast. False otherwise.
|
|
190
163
|
def warn?
|
|
191
164
|
@broadcasts.any? { |logger| logger.warn? }
|
|
192
165
|
end
|
|
193
166
|
|
|
194
|
-
# Sets the log level to Logger::WARN for the whole broadcast.
|
|
167
|
+
# Sets the log level to +Logger::WARN+ for the whole broadcast.
|
|
195
168
|
def warn!
|
|
196
|
-
dispatch
|
|
169
|
+
dispatch(:warn!)
|
|
197
170
|
end
|
|
198
171
|
|
|
199
|
-
#
|
|
200
|
-
# to at least one broadcast.
|
|
172
|
+
# True if the log level allows entries with severity +Logger::ERROR+ to be written
|
|
173
|
+
# to at least one broadcast. False otherwise.
|
|
201
174
|
def error?
|
|
202
175
|
@broadcasts.any? { |logger| logger.error? }
|
|
203
176
|
end
|
|
204
177
|
|
|
205
|
-
# Sets the log level to Logger::ERROR for the whole broadcast.
|
|
178
|
+
# Sets the log level to +Logger::ERROR+ for the whole broadcast.
|
|
206
179
|
def error!
|
|
207
|
-
dispatch
|
|
180
|
+
dispatch(:error!)
|
|
208
181
|
end
|
|
209
182
|
|
|
210
|
-
#
|
|
211
|
-
# to at least one broadcast.
|
|
183
|
+
# True if the log level allows entries with severity +Logger::FATAL+ to be written
|
|
184
|
+
# to at least one broadcast. False otherwise.
|
|
212
185
|
def fatal?
|
|
213
186
|
@broadcasts.any? { |logger| logger.fatal? }
|
|
214
187
|
end
|
|
215
188
|
|
|
216
|
-
# Sets the log level to Logger::FATAL for the whole broadcast.
|
|
189
|
+
# Sets the log level to +Logger::FATAL+ for the whole broadcast.
|
|
217
190
|
def fatal!
|
|
218
|
-
dispatch
|
|
191
|
+
dispatch(:fatal!)
|
|
219
192
|
end
|
|
220
193
|
|
|
221
194
|
def initialize_copy(other)
|
|
222
195
|
@broadcasts = []
|
|
223
196
|
@progname = other.progname.dup
|
|
224
|
-
@formatter = other.formatter.dup
|
|
225
197
|
|
|
226
198
|
broadcast_to(*other.broadcasts.map(&:dup))
|
|
227
199
|
end
|
|
228
200
|
|
|
229
201
|
private
|
|
230
|
-
def dispatch(&block)
|
|
231
|
-
|
|
232
|
-
|
|
202
|
+
def dispatch(method, *args, **kwargs, &block)
|
|
203
|
+
if block_given?
|
|
204
|
+
# Maintain semantics that the first logger yields the block
|
|
205
|
+
# as normal, but subsequent loggers won't re-execute the block.
|
|
206
|
+
# Instead, the initial result is immediately returned.
|
|
207
|
+
called, result = false, nil
|
|
208
|
+
block = proc { |*args, **kwargs|
|
|
209
|
+
if called then result
|
|
210
|
+
else
|
|
211
|
+
called = true
|
|
212
|
+
result = yield(*args, **kwargs)
|
|
213
|
+
end
|
|
214
|
+
}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
@broadcasts.map { |logger|
|
|
218
|
+
logger.send(method, *args, **kwargs, &block)
|
|
219
|
+
}.first
|
|
233
220
|
end
|
|
234
221
|
|
|
235
222
|
def method_missing(name, ...)
|
|
@@ -57,8 +57,13 @@ module ActiveSupport
|
|
|
57
57
|
# cache.write("baz", 5)
|
|
58
58
|
# cache.increment("baz") # => 6
|
|
59
59
|
#
|
|
60
|
-
def increment(name, amount = 1, options
|
|
61
|
-
|
|
60
|
+
def increment(name, amount = 1, **options)
|
|
61
|
+
options = merged_options(options)
|
|
62
|
+
key = normalize_key(name, options)
|
|
63
|
+
|
|
64
|
+
instrument(:increment, key, amount: amount) do
|
|
65
|
+
modify_value(name, amount, options)
|
|
66
|
+
end
|
|
62
67
|
end
|
|
63
68
|
|
|
64
69
|
# Decrement a cached integer value. Returns the updated value.
|
|
@@ -72,8 +77,13 @@ module ActiveSupport
|
|
|
72
77
|
# cache.write("baz", 5)
|
|
73
78
|
# cache.decrement("baz") # => 4
|
|
74
79
|
#
|
|
75
|
-
def decrement(name, amount = 1, options
|
|
76
|
-
|
|
80
|
+
def decrement(name, amount = 1, **options)
|
|
81
|
+
options = merged_options(options)
|
|
82
|
+
key = normalize_key(name, options)
|
|
83
|
+
|
|
84
|
+
instrument(:decrement, key, amount: amount) do
|
|
85
|
+
modify_value(name, -amount, options)
|
|
86
|
+
end
|
|
77
87
|
end
|
|
78
88
|
|
|
79
89
|
def delete_matched(matcher, options = nil)
|
|
@@ -60,7 +60,7 @@ module ActiveSupport
|
|
|
60
60
|
pool_options = retrieve_pool_options(options)
|
|
61
61
|
|
|
62
62
|
if pool_options
|
|
63
|
-
ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
|
63
|
+
ConnectionPool.new(**pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
|
64
64
|
else
|
|
65
65
|
Dalli::Client.new(addresses, options)
|
|
66
66
|
end
|
|
@@ -90,6 +90,9 @@ module ActiveSupport
|
|
|
90
90
|
# The value "compress: false" prevents duplicate compression within Dalli.
|
|
91
91
|
@mem_cache_options[:compress] = false
|
|
92
92
|
(OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) }
|
|
93
|
+
# Set the default serializer for Dalli to prevent warning about
|
|
94
|
+
# inheriting the default serializer.
|
|
95
|
+
@mem_cache_options[:serializer] = Marshal
|
|
93
96
|
@data = self.class.build_mem_cache(*(addresses + [@mem_cache_options]))
|
|
94
97
|
end
|
|
95
98
|
|
|
@@ -212,26 +215,24 @@ module ActiveSupport
|
|
|
212
215
|
def read_multi_entries(names, **options)
|
|
213
216
|
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
|
214
217
|
|
|
215
|
-
|
|
216
|
-
@data.with { |c| c.get_multi(keys_to_names.keys) }
|
|
217
|
-
rescue Dalli::UnmarshalError
|
|
218
|
-
{}
|
|
219
|
-
end
|
|
218
|
+
rescue_error_with({}) do
|
|
219
|
+
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
values = {}
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
raw_values.each do |key, value|
|
|
224
|
+
entry = deserialize_entry(value, raw: options[:raw])
|
|
225
225
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
226
|
+
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
|
227
|
+
begin
|
|
228
|
+
values[keys_to_names[key]] = entry.value
|
|
229
|
+
rescue DeserializationError
|
|
230
|
+
end
|
|
230
231
|
end
|
|
231
232
|
end
|
|
232
|
-
end
|
|
233
233
|
|
|
234
|
-
|
|
234
|
+
values
|
|
235
|
+
end
|
|
235
236
|
end
|
|
236
237
|
|
|
237
238
|
# Delete an entry from the cache.
|
|
@@ -276,7 +277,7 @@ module ActiveSupport
|
|
|
276
277
|
|
|
277
278
|
def rescue_error_with(fallback)
|
|
278
279
|
yield
|
|
279
|
-
rescue Dalli::DalliError => error
|
|
280
|
+
rescue Dalli::DalliError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
|
|
280
281
|
logger.error("DalliError (#{error}): #{error.message}") if logger
|
|
281
282
|
ActiveSupport.error_reporter&.report(
|
|
282
283
|
error,
|
|
@@ -146,8 +146,10 @@ module ActiveSupport
|
|
|
146
146
|
# cache.write("baz", 5)
|
|
147
147
|
# cache.increment("baz") # => 6
|
|
148
148
|
#
|
|
149
|
-
def increment(name, amount = 1, options
|
|
150
|
-
|
|
149
|
+
def increment(name, amount = 1, **options)
|
|
150
|
+
instrument(:increment, name, amount: amount) do
|
|
151
|
+
modify_value(name, amount, **options)
|
|
152
|
+
end
|
|
151
153
|
end
|
|
152
154
|
|
|
153
155
|
# Decrement a cached integer value. Returns the updated value.
|
|
@@ -161,8 +163,10 @@ module ActiveSupport
|
|
|
161
163
|
# cache.write("baz", 5)
|
|
162
164
|
# cache.decrement("baz") # => 4
|
|
163
165
|
#
|
|
164
|
-
def decrement(name, amount = 1, options
|
|
165
|
-
|
|
166
|
+
def decrement(name, amount = 1, **options)
|
|
167
|
+
instrument(:decrement, name, amount: amount) do
|
|
168
|
+
modify_value(name, -amount, **options)
|
|
169
|
+
end
|
|
166
170
|
end
|
|
167
171
|
|
|
168
172
|
# Deletes cache entries if the cache key matches a given pattern.
|
|
@@ -234,7 +238,7 @@ module ActiveSupport
|
|
|
234
238
|
|
|
235
239
|
# Modifies the amount of an integer value that is stored in the cache.
|
|
236
240
|
# If the key is not found it is created and set to +amount+.
|
|
237
|
-
def modify_value(name, amount, options)
|
|
241
|
+
def modify_value(name, amount, **options)
|
|
238
242
|
options = merged_options(options)
|
|
239
243
|
key = normalize_key(name, options)
|
|
240
244
|
version = normalize_version(name, options)
|
|
@@ -25,10 +25,10 @@ module ActiveSupport
|
|
|
25
25
|
def cleanup(options = nil)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def increment(name, amount = 1, options
|
|
28
|
+
def increment(name, amount = 1, **options)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def decrement(name, amount = 1, options
|
|
31
|
+
def decrement(name, amount = 1, **options)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def delete_matched(matcher, options = nil)
|
|
@@ -150,7 +150,7 @@ module ActiveSupport
|
|
|
150
150
|
universal_options = redis_options.extract!(*UNIVERSAL_OPTIONS)
|
|
151
151
|
|
|
152
152
|
if pool_options = self.class.send(:retrieve_pool_options, redis_options)
|
|
153
|
-
@redis = ::ConnectionPool.new(pool_options) { self.class.build_redis(**redis_options) }
|
|
153
|
+
@redis = ::ConnectionPool.new(**pool_options) { self.class.build_redis(**redis_options) }
|
|
154
154
|
else
|
|
155
155
|
@redis = self.class.build_redis(**redis_options)
|
|
156
156
|
end
|
|
@@ -173,9 +173,12 @@ module ActiveSupport
|
|
|
173
173
|
return {} if names.empty?
|
|
174
174
|
|
|
175
175
|
options = names.extract_options!
|
|
176
|
-
|
|
176
|
+
options = merged_options(options)
|
|
177
|
+
keys = names.map { |name| normalize_key(name, options) }
|
|
178
|
+
|
|
179
|
+
instrument_multi(:read_multi, keys, options) do |payload|
|
|
177
180
|
read_multi_entries(names, **options).tap do |results|
|
|
178
|
-
payload[:hits] = results.keys
|
|
181
|
+
payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
|
|
179
182
|
end
|
|
180
183
|
end
|
|
181
184
|
end
|
|
@@ -480,7 +483,7 @@ module ActiveSupport
|
|
|
480
483
|
|
|
481
484
|
def failsafe(method, returning: nil)
|
|
482
485
|
yield
|
|
483
|
-
rescue ::Redis::BaseError => error
|
|
486
|
+
rescue ::Redis::BaseError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
|
|
484
487
|
@error_handler&.call(method: method, exception: error, returning: returning)
|
|
485
488
|
returning
|
|
486
489
|
end
|
|
@@ -94,28 +94,54 @@ module ActiveSupport
|
|
|
94
94
|
super
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
def increment(name, amount = 1, options
|
|
97
|
+
def increment(name, amount = 1, **options) # :nodoc:
|
|
98
98
|
return super unless local_cache
|
|
99
99
|
value = bypass_local_cache { super }
|
|
100
|
-
|
|
101
|
-
write_cache_value(name, value, raw: true, **options)
|
|
102
|
-
else
|
|
103
|
-
write_cache_value(name, value, raw: true)
|
|
104
|
-
end
|
|
100
|
+
write_cache_value(name, value, raw: true, **options)
|
|
105
101
|
value
|
|
106
102
|
end
|
|
107
103
|
|
|
108
|
-
def decrement(name, amount = 1, options
|
|
104
|
+
def decrement(name, amount = 1, **options) # :nodoc:
|
|
109
105
|
return super unless local_cache
|
|
110
106
|
value = bypass_local_cache { super }
|
|
111
|
-
|
|
112
|
-
write_cache_value(name, value, raw: true, **options)
|
|
113
|
-
else
|
|
114
|
-
write_cache_value(name, value, raw: true)
|
|
115
|
-
end
|
|
107
|
+
write_cache_value(name, value, raw: true, **options)
|
|
116
108
|
value
|
|
117
109
|
end
|
|
118
110
|
|
|
111
|
+
def fetch_multi(*names, &block) # :nodoc:
|
|
112
|
+
return super if local_cache.nil? || names.empty?
|
|
113
|
+
|
|
114
|
+
options = names.extract_options!
|
|
115
|
+
options = merged_options(options)
|
|
116
|
+
|
|
117
|
+
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
|
118
|
+
|
|
119
|
+
local_entries = local_cache.read_multi_entries(keys_to_names.keys)
|
|
120
|
+
results = local_entries.each_with_object({}) do |(key, value), result|
|
|
121
|
+
# If we recorded a miss in the local cache, `#fetch_multi` will forward
|
|
122
|
+
# that key to the real store, and the entry will be replaced
|
|
123
|
+
# local_cache.delete_entry(key)
|
|
124
|
+
next if value.nil?
|
|
125
|
+
|
|
126
|
+
entry = deserialize_entry(value, **options)
|
|
127
|
+
|
|
128
|
+
normalized_key = keys_to_names[key]
|
|
129
|
+
if entry.nil?
|
|
130
|
+
result[normalized_key] = nil
|
|
131
|
+
elsif entry.expired? || entry.mismatched?(normalize_version(normalized_key, options))
|
|
132
|
+
local_cache.delete_entry(key)
|
|
133
|
+
else
|
|
134
|
+
result[normalized_key] = entry.value
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
if results.size < names.size
|
|
139
|
+
results.merge!(super(*(names - results.keys), options, &block))
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
results
|
|
143
|
+
end
|
|
144
|
+
|
|
119
145
|
private
|
|
120
146
|
def read_serialized_entry(key, raw: false, **options)
|
|
121
147
|
if cache = local_cache
|
|
@@ -137,17 +163,27 @@ module ActiveSupport
|
|
|
137
163
|
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
|
138
164
|
|
|
139
165
|
local_entries = local_cache.read_multi_entries(keys_to_names.keys)
|
|
140
|
-
|
|
141
|
-
local_entries.
|
|
142
|
-
|
|
166
|
+
|
|
167
|
+
results = local_entries.each_with_object({}) do |(key, value), result|
|
|
168
|
+
next if value.nil? # recorded cache miss
|
|
169
|
+
|
|
170
|
+
entry = deserialize_entry(value, **options)
|
|
171
|
+
|
|
172
|
+
normalized_key = keys_to_names[key]
|
|
173
|
+
if entry.nil?
|
|
174
|
+
result[normalized_key] = nil
|
|
175
|
+
elsif entry.expired? || entry.mismatched?(normalize_version(normalized_key, options))
|
|
176
|
+
local_cache.delete_entry(key)
|
|
177
|
+
else
|
|
178
|
+
result[normalized_key] = entry.value
|
|
179
|
+
end
|
|
143
180
|
end
|
|
144
|
-
missed_names = names - local_entries.keys
|
|
145
181
|
|
|
146
|
-
if
|
|
147
|
-
|
|
148
|
-
else
|
|
149
|
-
local_entries
|
|
182
|
+
if results.size < names.size
|
|
183
|
+
results.merge!(super(names - results.keys, **options))
|
|
150
184
|
end
|
|
185
|
+
|
|
186
|
+
results
|
|
151
187
|
end
|
|
152
188
|
|
|
153
189
|
def write_serialized_entry(key, payload, **)
|
data/lib/active_support/cache.rb
CHANGED
|
@@ -35,6 +35,7 @@ module ActiveSupport
|
|
|
35
35
|
:race_condition_ttl,
|
|
36
36
|
:serializer,
|
|
37
37
|
:skip_nil,
|
|
38
|
+
:raw,
|
|
38
39
|
]
|
|
39
40
|
|
|
40
41
|
# Mapping of canonical option names to aliases that a store will recognize.
|
|
@@ -286,7 +287,7 @@ module ActiveSupport
|
|
|
286
287
|
# <tt>coder: nil</tt> to avoid the overhead of safeguarding against
|
|
287
288
|
# mutation.
|
|
288
289
|
#
|
|
289
|
-
# The +:coder+ option is
|
|
290
|
+
# The +:coder+ option is mutually exclusive with the +:serializer+ and
|
|
290
291
|
# +:compressor+ options. Specifying them together will raise an
|
|
291
292
|
# +ArgumentError+.
|
|
292
293
|
#
|
|
@@ -386,7 +387,7 @@ module ActiveSupport
|
|
|
386
387
|
# process can try to generate a new value after the extended time window
|
|
387
388
|
# has elapsed.
|
|
388
389
|
#
|
|
389
|
-
# # Set all values to expire after one
|
|
390
|
+
# # Set all values to expire after one second.
|
|
390
391
|
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
|
|
391
392
|
#
|
|
392
393
|
# cache.write("foo", "original value")
|
|
@@ -419,7 +420,7 @@ module ActiveSupport
|
|
|
419
420
|
# t1.join
|
|
420
421
|
#
|
|
421
422
|
# p val_1 # => "new value 1"
|
|
422
|
-
# p val_2 # => "
|
|
423
|
+
# p val_2 # => "original value"
|
|
423
424
|
# p cache.fetch("foo") # => "new value 1"
|
|
424
425
|
#
|
|
425
426
|
# # The entry requires 3 seconds to expire (expires_in + race_condition_ttl)
|
|
@@ -538,10 +539,11 @@ module ActiveSupport
|
|
|
538
539
|
|
|
539
540
|
options = names.extract_options!
|
|
540
541
|
options = merged_options(options)
|
|
542
|
+
keys = names.map { |name| normalize_key(name, options) }
|
|
541
543
|
|
|
542
|
-
instrument_multi :read_multi,
|
|
544
|
+
instrument_multi :read_multi, keys, options do |payload|
|
|
543
545
|
read_multi_entries(names, **options, event: payload).tap do |results|
|
|
544
|
-
payload[:hits] = results.keys
|
|
546
|
+
payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
|
|
545
547
|
end
|
|
546
548
|
end
|
|
547
549
|
end
|
|
@@ -551,8 +553,9 @@ module ActiveSupport
|
|
|
551
553
|
return hash if hash.empty?
|
|
552
554
|
|
|
553
555
|
options = merged_options(options)
|
|
556
|
+
normalized_hash = hash.transform_keys { |key| normalize_key(key, options) }
|
|
554
557
|
|
|
555
|
-
instrument_multi :write_multi,
|
|
558
|
+
instrument_multi :write_multi, normalized_hash, options do |payload|
|
|
556
559
|
entries = hash.each_with_object({}) do |(name, value), memo|
|
|
557
560
|
memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
|
558
561
|
end
|
|
@@ -596,9 +599,9 @@ module ActiveSupport
|
|
|
596
599
|
|
|
597
600
|
options = names.extract_options!
|
|
598
601
|
options = merged_options(options)
|
|
599
|
-
|
|
602
|
+
keys = names.map { |name| normalize_key(name, options) }
|
|
600
603
|
writes = {}
|
|
601
|
-
ordered = instrument_multi :read_multi,
|
|
604
|
+
ordered = instrument_multi :read_multi, keys, options do |payload|
|
|
602
605
|
if options[:force]
|
|
603
606
|
reads = {}
|
|
604
607
|
else
|
|
@@ -610,7 +613,7 @@ module ActiveSupport
|
|
|
610
613
|
end
|
|
611
614
|
writes.compact! if options[:skip_nil]
|
|
612
615
|
|
|
613
|
-
payload[:hits] = reads.keys
|
|
616
|
+
payload[:hits] = reads.keys.map { |name| normalize_key(name, options) }
|
|
614
617
|
payload[:super_operation] = :fetch_multi
|
|
615
618
|
|
|
616
619
|
ordered
|
|
@@ -943,9 +946,12 @@ module ActiveSupport
|
|
|
943
946
|
#
|
|
944
947
|
# namespace_key 'foo', namespace: -> { 'cache' }
|
|
945
948
|
# # => 'cache:foo'
|
|
946
|
-
def namespace_key(key,
|
|
947
|
-
|
|
948
|
-
|
|
949
|
+
def namespace_key(key, call_options = nil)
|
|
950
|
+
namespace = if call_options&.key?(:namespace)
|
|
951
|
+
call_options[:namespace]
|
|
952
|
+
else
|
|
953
|
+
options[:namespace]
|
|
954
|
+
end
|
|
949
955
|
|
|
950
956
|
if namespace.respond_to?(:call)
|
|
951
957
|
namespace = namespace.call
|
|
@@ -1030,8 +1036,7 @@ module ActiveSupport
|
|
|
1030
1036
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
|
1031
1037
|
# for a brief period while the entry is being recalculated.
|
|
1032
1038
|
entry.expires_at = Time.now.to_f + race_ttl
|
|
1033
|
-
options
|
|
1034
|
-
write_entry(key, entry, **options)
|
|
1039
|
+
write_entry(key, entry, **options, expires_in: race_ttl * 2)
|
|
1035
1040
|
else
|
|
1036
1041
|
delete_entry(key, **options)
|
|
1037
1042
|
end
|
|
@@ -6,7 +6,6 @@ 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
8
|
require "active_support/core_ext/object/blank"
|
|
9
|
-
require "thread"
|
|
10
9
|
|
|
11
10
|
module ActiveSupport
|
|
12
11
|
# = Active Support \Callbacks
|
|
@@ -67,7 +66,7 @@ module ActiveSupport
|
|
|
67
66
|
|
|
68
67
|
included do
|
|
69
68
|
extend ActiveSupport::DescendantsTracker
|
|
70
|
-
class_attribute :__callbacks, instance_writer: false, default: {}
|
|
69
|
+
class_attribute :__callbacks, instance_writer: false, instance_predicate: false, default: {}
|
|
71
70
|
end
|
|
72
71
|
|
|
73
72
|
CALLBACK_FILTER_TYPES = [:before, :after, :around].freeze
|
|
@@ -499,9 +498,10 @@ module ActiveSupport
|
|
|
499
498
|
when Conditionals::Value
|
|
500
499
|
ProcCall.new(filter)
|
|
501
500
|
when ::Proc
|
|
502
|
-
|
|
501
|
+
case filter.arity
|
|
502
|
+
when 2
|
|
503
503
|
InstanceExec2.new(filter)
|
|
504
|
-
|
|
504
|
+
when 1, -2
|
|
505
505
|
InstanceExec1.new(filter)
|
|
506
506
|
else
|
|
507
507
|
InstanceExec0.new(filter)
|
|
@@ -934,7 +934,10 @@ module ActiveSupport
|
|
|
934
934
|
end
|
|
935
935
|
|
|
936
936
|
def set_callbacks(name, callbacks) # :nodoc:
|
|
937
|
-
|
|
937
|
+
# HACK: We're making assumption on how `class_attribute` is implemented
|
|
938
|
+
# to save constantly duping the callback hash. If this desync with class_attribute
|
|
939
|
+
# we'll lose the optimization, but won't cause an actual behavior bug.
|
|
940
|
+
unless singleton_class.private_method_defined?(:__class_attr__callbacks, false)
|
|
938
941
|
self.__callbacks = __callbacks.dup
|
|
939
942
|
end
|
|
940
943
|
self.__callbacks[name.to_sym] = callbacks
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module ClassAttribute # :nodoc:
|
|
5
|
+
class << self
|
|
6
|
+
def redefine(owner, name, namespaced_name, value)
|
|
7
|
+
if owner.singleton_class?
|
|
8
|
+
if owner.attached_object.is_a?(Module)
|
|
9
|
+
redefine_method(owner, namespaced_name, private: true) { value }
|
|
10
|
+
else
|
|
11
|
+
redefine_method(owner, name) { value }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
redefine_method(owner.singleton_class, namespaced_name, private: true) { value }
|
|
16
|
+
|
|
17
|
+
redefine_method(owner.singleton_class, "#{namespaced_name}=", private: true) do |new_value|
|
|
18
|
+
if owner.equal?(self)
|
|
19
|
+
value = new_value
|
|
20
|
+
else
|
|
21
|
+
::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, new_value)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def redefine_method(owner, name, private: false, &block)
|
|
27
|
+
owner.silence_redefinition_of_method(name)
|
|
28
|
+
owner.define_method(name, &block)
|
|
29
|
+
owner.send(:private, name) if private
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|