activesupport 7.1.6 → 7.2.3
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 +212 -1122
- data/README.rdoc +1 -1
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +10 -3
- data/lib/active_support/broadcast_logger.rb +65 -78
- data/lib/active_support/cache/file_store.rb +17 -12
- data/lib/active_support/cache/mem_cache_store.rb +29 -89
- data/lib/active_support/cache/memory_store.rb +7 -6
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +17 -14
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache/strategy/local_cache.rb +56 -20
- data/lib/active_support/cache.rb +63 -71
- data/lib/active_support/callbacks.rb +77 -115
- data/lib/active_support/core_ext/array/conversions.rb +0 -2
- data/lib/active_support/core_ext/benchmark.rb +1 -0
- data/lib/active_support/core_ext/class/attribute.rb +2 -1
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +0 -2
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/enumerable.rb +17 -5
- data/lib/active_support/core_ext/erb/util.rb +7 -2
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -163
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +1 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/range/overlap.rb +1 -1
- 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 +4 -4
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +4 -4
- data/lib/active_support/core_ext/string/multibyte.rb +3 -3
- data/lib/active_support/core_ext/string/output_safety.rb +0 -7
- data/lib/active_support/core_ext/time/calculations.rb +18 -28
- data/lib/active_support/core_ext/time/compatibility.rb +24 -0
- data/lib/active_support/core_ext/time/conversions.rb +0 -2
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +45 -40
- data/lib/active_support/delegation.rb +202 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/deprecation/constant_accessor.rb +47 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +7 -2
- data/lib/active_support/deprecation.rb +8 -5
- data/lib/active_support/descendants_tracker.rb +9 -87
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -2
- data/lib/active_support/duration.rb +11 -6
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +46 -5
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +1 -2
- data/lib/active_support/file_update_checker.rb +2 -2
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +26 -24
- data/lib/active_support/html_safe_translation.rb +3 -0
- data/lib/active_support/json/decoding.rb +1 -1
- data/lib/active_support/json/encoding.rb +23 -5
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +0 -12
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +0 -8
- data/lib/active_support/message_encryptors.rb +2 -2
- data/lib/active_support/message_pack/extensions.rb +15 -2
- data/lib/active_support/message_verifier.rb +21 -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 +6 -3
- data/lib/active_support/notifications/fanout.rb +4 -7
- data/lib/active_support/notifications/instrumenter.rb +21 -18
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/proxy_object.rb +8 -5
- data/lib/active_support/railtie.rb +4 -11
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/subscriber.rb +1 -0
- data/lib/active_support/tagged_logging.rb +0 -1
- data/lib/active_support/test_case.rb +3 -1
- data/lib/active_support/testing/assertions.rb +4 -4
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/isolation.rb +20 -8
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/parallelization/server.rb +18 -2
- data/lib/active_support/testing/parallelization/worker.rb +2 -2
- data/lib/active_support/testing/parallelization.rb +12 -1
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +3 -3
- data/lib/active_support/time_with_zone.rb +8 -4
- data/lib/active_support/values/time_zone.rb +7 -7
- data/lib/active_support/xml_mini.rb +13 -2
- data/lib/active_support.rb +2 -1
- metadata +16 -24
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/ruby_features.rb +0 -7
- data/lib/active_support/testing/strict_warnings.rb +0 -39
data/README.rdoc
CHANGED
|
@@ -35,6 +35,6 @@ Bug reports for the Ruby on \Rails project can be filed here:
|
|
|
35
35
|
|
|
36
36
|
* https://github.com/rails/rails/issues
|
|
37
37
|
|
|
38
|
-
Feature requests should be discussed on the
|
|
38
|
+
Feature requests should be discussed on the rubyonrails-core forum here:
|
|
39
39
|
|
|
40
40
|
* https://discuss.rubyonrails.org/c/rubyonrails-core
|
|
@@ -17,7 +17,8 @@ module ActiveSupport
|
|
|
17
17
|
# can focus on the rest.
|
|
18
18
|
#
|
|
19
19
|
# bc = ActiveSupport::BacktraceCleaner.new
|
|
20
|
-
#
|
|
20
|
+
# root = "#{Rails.root}/"
|
|
21
|
+
# bc.add_filter { |line| line.start_with?(root) ? line.from(root.size) : line } # strip the Rails.root prefix
|
|
21
22
|
# bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
|
|
22
23
|
# bc.clean(exception.backtrace) # perform the cleanup
|
|
23
24
|
#
|
|
@@ -76,8 +77,9 @@ module ActiveSupport
|
|
|
76
77
|
# Adds a filter from the block provided. Each line in the backtrace will be
|
|
77
78
|
# mapped against this filter.
|
|
78
79
|
#
|
|
79
|
-
# # Will turn "/my/rails/root/app/models/person.rb" into "
|
|
80
|
-
#
|
|
80
|
+
# # Will turn "/my/rails/root/app/models/person.rb" into "app/models/person.rb"
|
|
81
|
+
# root = "#{Rails.root}/"
|
|
82
|
+
# backtrace_cleaner.add_filter { |line| line.delete_prefix(root) }
|
|
81
83
|
def add_filter(&block)
|
|
82
84
|
@filters << block
|
|
83
85
|
end
|
|
@@ -108,6 +110,11 @@ module ActiveSupport
|
|
|
108
110
|
private
|
|
109
111
|
FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
|
|
110
112
|
|
|
113
|
+
def initialize_copy(_other)
|
|
114
|
+
@filters = @filters.dup
|
|
115
|
+
@silencers = @silencers.dup
|
|
116
|
+
end
|
|
117
|
+
|
|
111
118
|
def add_gem_filter
|
|
112
119
|
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
|
|
113
120
|
return if gems_paths.empty?
|
|
@@ -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,142 +104,130 @@ 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
|
-
def method_missing(name,
|
|
222
|
+
def method_missing(name, ...)
|
|
236
223
|
loggers = @broadcasts.select { |logger| logger.respond_to?(name) }
|
|
237
224
|
|
|
238
225
|
if loggers.none?
|
|
239
|
-
super
|
|
226
|
+
super
|
|
240
227
|
elsif loggers.one?
|
|
241
|
-
loggers.first.send(name,
|
|
228
|
+
loggers.first.send(name, ...)
|
|
242
229
|
else
|
|
243
|
-
loggers.map { |logger| logger.send(name,
|
|
230
|
+
loggers.map { |logger| logger.send(name, ...) }
|
|
244
231
|
end
|
|
245
232
|
end
|
|
246
233
|
|
|
@@ -57,7 +57,7 @@ module ActiveSupport
|
|
|
57
57
|
# cache.write("baz", 5)
|
|
58
58
|
# cache.increment("baz") # => 6
|
|
59
59
|
#
|
|
60
|
-
def increment(name, amount = 1, options
|
|
60
|
+
def increment(name, amount = 1, **options)
|
|
61
61
|
modify_value(name, amount, options)
|
|
62
62
|
end
|
|
63
63
|
|
|
@@ -72,14 +72,15 @@ module ActiveSupport
|
|
|
72
72
|
# cache.write("baz", 5)
|
|
73
73
|
# cache.decrement("baz") # => 4
|
|
74
74
|
#
|
|
75
|
-
def decrement(name, amount = 1, options
|
|
75
|
+
def decrement(name, amount = 1, **options)
|
|
76
76
|
modify_value(name, -amount, options)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def delete_matched(matcher, options = nil)
|
|
80
80
|
options = merged_options(options)
|
|
81
|
+
matcher = key_matcher(matcher, options)
|
|
82
|
+
|
|
81
83
|
instrument(:delete_matched, matcher.inspect) do
|
|
82
|
-
matcher = key_matcher(matcher, options)
|
|
83
84
|
search_dir(cache_path) do |path|
|
|
84
85
|
key = file_path_key(path)
|
|
85
86
|
delete_entry(path, **options) if key.match(matcher)
|
|
@@ -209,18 +210,22 @@ module ActiveSupport
|
|
|
209
210
|
# Modifies the amount of an integer value that is stored in the cache.
|
|
210
211
|
# If the key is not found it is created and set to +amount+.
|
|
211
212
|
def modify_value(name, amount, options)
|
|
212
|
-
|
|
213
|
+
options = merged_options(options)
|
|
214
|
+
key = normalize_key(name, options)
|
|
215
|
+
version = normalize_version(name, options)
|
|
216
|
+
amount = Integer(amount)
|
|
213
217
|
|
|
214
|
-
lock_file(
|
|
215
|
-
|
|
218
|
+
lock_file(key) do
|
|
219
|
+
entry = read_entry(key, **options)
|
|
216
220
|
|
|
217
|
-
if
|
|
218
|
-
|
|
219
|
-
write(name, num, options)
|
|
220
|
-
num
|
|
221
|
-
else
|
|
222
|
-
write(name, Integer(amount), options)
|
|
221
|
+
if !entry || entry.expired? || entry.mismatched?(version)
|
|
222
|
+
write(name, amount, options)
|
|
223
223
|
amount
|
|
224
|
+
else
|
|
225
|
+
num = entry.value.to_i + amount
|
|
226
|
+
entry = Entry.new(num, expires_at: entry.expires_at, version: entry.version)
|
|
227
|
+
write_entry(key, entry)
|
|
228
|
+
num
|
|
224
229
|
end
|
|
225
230
|
end
|
|
226
231
|
end
|
|
@@ -41,46 +41,6 @@ module ActiveSupport
|
|
|
41
41
|
|
|
42
42
|
prepend Strategy::LocalCache
|
|
43
43
|
|
|
44
|
-
module DupLocalCache
|
|
45
|
-
class DupLocalStore < DelegateClass(Strategy::LocalCache::LocalStore)
|
|
46
|
-
def write_entry(_key, entry)
|
|
47
|
-
if entry.is_a?(Entry)
|
|
48
|
-
entry.dup_value!
|
|
49
|
-
end
|
|
50
|
-
super
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def fetch_entry(key)
|
|
54
|
-
entry = super do
|
|
55
|
-
new_entry = yield
|
|
56
|
-
if entry.is_a?(Entry)
|
|
57
|
-
new_entry.dup_value!
|
|
58
|
-
end
|
|
59
|
-
new_entry
|
|
60
|
-
end
|
|
61
|
-
entry = entry.dup
|
|
62
|
-
|
|
63
|
-
if entry.is_a?(Entry)
|
|
64
|
-
entry.dup_value!
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
entry
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
private
|
|
72
|
-
def local_cache
|
|
73
|
-
if ActiveSupport::Cache.format_version == 6.1
|
|
74
|
-
if local_cache = super
|
|
75
|
-
DupLocalStore.new(local_cache)
|
|
76
|
-
end
|
|
77
|
-
else
|
|
78
|
-
super
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
prepend DupLocalCache
|
|
83
|
-
|
|
84
44
|
KEY_MAX_SIZE = 250
|
|
85
45
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
|
86
46
|
|
|
@@ -114,7 +74,6 @@ module ActiveSupport
|
|
|
114
74
|
#
|
|
115
75
|
# If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
|
|
116
76
|
# +MemCacheStore+ will connect to localhost:11211 (the default memcached port).
|
|
117
|
-
# Passing a +Dalli::Client+ instance is deprecated and will be removed. Please pass an address instead.
|
|
118
77
|
def initialize(*addresses)
|
|
119
78
|
addresses = addresses.flatten
|
|
120
79
|
options = addresses.extract_options!
|
|
@@ -126,19 +85,12 @@ module ActiveSupport
|
|
|
126
85
|
unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
|
|
127
86
|
raise ArgumentError, "First argument must be an empty array, address, or array of addresses."
|
|
128
87
|
end
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
else
|
|
136
|
-
@mem_cache_options = options.dup
|
|
137
|
-
# The value "compress: false" prevents duplicate compression within Dalli.
|
|
138
|
-
@mem_cache_options[:compress] = false
|
|
139
|
-
(OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) }
|
|
140
|
-
@data = self.class.build_mem_cache(*(addresses + [@mem_cache_options]))
|
|
141
|
-
end
|
|
88
|
+
|
|
89
|
+
@mem_cache_options = options.dup
|
|
90
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
|
91
|
+
@mem_cache_options[:compress] = false
|
|
92
|
+
(OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) }
|
|
93
|
+
@data = self.class.build_mem_cache(*(addresses + [@mem_cache_options]))
|
|
142
94
|
end
|
|
143
95
|
|
|
144
96
|
def inspect
|
|
@@ -179,9 +131,11 @@ module ActiveSupport
|
|
|
179
131
|
# <tt>raw: true</tt>, will fail and return +nil+.
|
|
180
132
|
def increment(name, amount = 1, options = nil)
|
|
181
133
|
options = merged_options(options)
|
|
182
|
-
|
|
134
|
+
key = normalize_key(name, options)
|
|
135
|
+
|
|
136
|
+
instrument(:increment, key, amount: amount) do
|
|
183
137
|
rescue_error_with nil do
|
|
184
|
-
@data.with { |c| c.incr(
|
|
138
|
+
@data.with { |c| c.incr(key, amount, options[:expires_in], amount) }
|
|
185
139
|
end
|
|
186
140
|
end
|
|
187
141
|
end
|
|
@@ -203,9 +157,11 @@ module ActiveSupport
|
|
|
203
157
|
# <tt>raw: true</tt>, will fail and return +nil+.
|
|
204
158
|
def decrement(name, amount = 1, options = nil)
|
|
205
159
|
options = merged_options(options)
|
|
206
|
-
|
|
160
|
+
key = normalize_key(name, options)
|
|
161
|
+
|
|
162
|
+
instrument(:decrement, key, amount: amount) do
|
|
207
163
|
rescue_error_with nil do
|
|
208
|
-
@data.with { |c| c.decr(
|
|
164
|
+
@data.with { |c| c.decr(key, amount, options[:expires_in], 0) }
|
|
209
165
|
end
|
|
210
166
|
end
|
|
211
167
|
end
|
|
@@ -222,20 +178,6 @@ module ActiveSupport
|
|
|
222
178
|
end
|
|
223
179
|
|
|
224
180
|
private
|
|
225
|
-
def default_serializer
|
|
226
|
-
if Cache.format_version == 6.1
|
|
227
|
-
ActiveSupport.deprecator.warn <<~EOM
|
|
228
|
-
Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.
|
|
229
|
-
|
|
230
|
-
Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
|
|
231
|
-
for more information on how to upgrade.
|
|
232
|
-
EOM
|
|
233
|
-
Cache::SerializerWithFallback[:passthrough]
|
|
234
|
-
else
|
|
235
|
-
super
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
|
|
239
181
|
# Read an entry from the cache.
|
|
240
182
|
def read_entry(key, **options)
|
|
241
183
|
deserialize_entry(read_serialized_entry(key, **options), **options)
|
|
@@ -259,10 +201,10 @@ module ActiveSupport
|
|
|
259
201
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
|
260
202
|
expires_in += 5.minutes
|
|
261
203
|
end
|
|
262
|
-
rescue_error_with
|
|
204
|
+
rescue_error_with nil do
|
|
263
205
|
# Don't pass compress option to Dalli since we are already dealing with compression.
|
|
264
206
|
options.delete(:compress)
|
|
265
|
-
@data.with { |c| c.send(method, key, payload, expires_in, **options) }
|
|
207
|
+
@data.with { |c| !!c.send(method, key, payload, expires_in, **options) }
|
|
266
208
|
end
|
|
267
209
|
end
|
|
268
210
|
|
|
@@ -270,26 +212,24 @@ module ActiveSupport
|
|
|
270
212
|
def read_multi_entries(names, **options)
|
|
271
213
|
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
|
272
214
|
|
|
273
|
-
|
|
274
|
-
@data.with { |c| c.get_multi(keys_to_names.keys) }
|
|
275
|
-
rescue Dalli::UnmarshalError
|
|
276
|
-
{}
|
|
277
|
-
end
|
|
215
|
+
rescue_error_with({}) do
|
|
216
|
+
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
|
278
217
|
|
|
279
|
-
|
|
218
|
+
values = {}
|
|
280
219
|
|
|
281
|
-
|
|
282
|
-
|
|
220
|
+
raw_values.each do |key, value|
|
|
221
|
+
entry = deserialize_entry(value, raw: options[:raw])
|
|
283
222
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
223
|
+
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
|
224
|
+
begin
|
|
225
|
+
values[keys_to_names[key]] = entry.value
|
|
226
|
+
rescue DeserializationError
|
|
227
|
+
end
|
|
288
228
|
end
|
|
289
229
|
end
|
|
290
|
-
end
|
|
291
230
|
|
|
292
|
-
|
|
231
|
+
values
|
|
232
|
+
end
|
|
293
233
|
end
|
|
294
234
|
|
|
295
235
|
# Delete an entry from the cache.
|
|
@@ -334,7 +274,7 @@ module ActiveSupport
|
|
|
334
274
|
|
|
335
275
|
def rescue_error_with(fallback)
|
|
336
276
|
yield
|
|
337
|
-
rescue Dalli::DalliError => error
|
|
277
|
+
rescue Dalli::DalliError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
|
|
338
278
|
logger.error("DalliError (#{error}): #{error.message}") if logger
|
|
339
279
|
ActiveSupport.error_reporter&.report(
|
|
340
280
|
error,
|
|
@@ -146,8 +146,8 @@ module ActiveSupport
|
|
|
146
146
|
# cache.write("baz", 5)
|
|
147
147
|
# cache.increment("baz") # => 6
|
|
148
148
|
#
|
|
149
|
-
def increment(name, amount = 1, options
|
|
150
|
-
modify_value(name, amount, options)
|
|
149
|
+
def increment(name, amount = 1, **options)
|
|
150
|
+
modify_value(name, amount, **options)
|
|
151
151
|
end
|
|
152
152
|
|
|
153
153
|
# Decrement a cached integer value. Returns the updated value.
|
|
@@ -161,15 +161,16 @@ module ActiveSupport
|
|
|
161
161
|
# cache.write("baz", 5)
|
|
162
162
|
# cache.decrement("baz") # => 4
|
|
163
163
|
#
|
|
164
|
-
def decrement(name, amount = 1, options
|
|
165
|
-
modify_value(name, -amount, options)
|
|
164
|
+
def decrement(name, amount = 1, **options)
|
|
165
|
+
modify_value(name, -amount, **options)
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
# Deletes cache entries if the cache key matches a given pattern.
|
|
169
169
|
def delete_matched(matcher, options = nil)
|
|
170
170
|
options = merged_options(options)
|
|
171
|
+
matcher = key_matcher(matcher, options)
|
|
172
|
+
|
|
171
173
|
instrument(:delete_matched, matcher.inspect) do
|
|
172
|
-
matcher = key_matcher(matcher, options)
|
|
173
174
|
keys = synchronize { @data.keys }
|
|
174
175
|
keys.each do |key|
|
|
175
176
|
delete_entry(key, **options) if key.match(matcher)
|
|
@@ -233,7 +234,7 @@ module ActiveSupport
|
|
|
233
234
|
|
|
234
235
|
# Modifies the amount of an integer value that is stored in the cache.
|
|
235
236
|
# If the key is not found it is created and set to +amount+.
|
|
236
|
-
def modify_value(name, amount, options)
|
|
237
|
+
def modify_value(name, amount, **options)
|
|
237
238
|
options = merged_options(options)
|
|
238
239
|
key = normalize_key(name, options)
|
|
239
240
|
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)
|
|
@@ -196,12 +196,13 @@ module ActiveSupport
|
|
|
196
196
|
#
|
|
197
197
|
# Failsafe: Raises errors.
|
|
198
198
|
def delete_matched(matcher, options = nil)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
unless String === matcher
|
|
200
|
+
raise ArgumentError, "Only Redis glob strings are supported: #{matcher.inspect}"
|
|
201
|
+
end
|
|
202
|
+
pattern = namespace_key(matcher, options)
|
|
203
|
+
|
|
204
|
+
instrument :delete_matched, pattern do
|
|
203
205
|
redis.then do |c|
|
|
204
|
-
pattern = namespace_key(matcher, options)
|
|
205
206
|
cursor = "0"
|
|
206
207
|
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
|
|
207
208
|
nodes = c.respond_to?(:nodes) ? c.nodes : [c]
|
|
@@ -234,10 +235,11 @@ module ActiveSupport
|
|
|
234
235
|
#
|
|
235
236
|
# Failsafe: Raises errors.
|
|
236
237
|
def increment(name, amount = 1, options = nil)
|
|
237
|
-
|
|
238
|
+
options = merged_options(options)
|
|
239
|
+
key = normalize_key(name, options)
|
|
240
|
+
|
|
241
|
+
instrument :increment, key, amount: amount do
|
|
238
242
|
failsafe :increment do
|
|
239
|
-
options = merged_options(options)
|
|
240
|
-
key = normalize_key(name, options)
|
|
241
243
|
change_counter(key, amount, options)
|
|
242
244
|
end
|
|
243
245
|
end
|
|
@@ -260,10 +262,11 @@ module ActiveSupport
|
|
|
260
262
|
#
|
|
261
263
|
# Failsafe: Raises errors.
|
|
262
264
|
def decrement(name, amount = 1, options = nil)
|
|
263
|
-
|
|
265
|
+
options = merged_options(options)
|
|
266
|
+
key = normalize_key(name, options)
|
|
267
|
+
|
|
268
|
+
instrument :decrement, key, amount: amount do
|
|
264
269
|
failsafe :decrement do
|
|
265
|
-
options = merged_options(options)
|
|
266
|
-
key = normalize_key(name, options)
|
|
267
270
|
change_counter(key, -amount, options)
|
|
268
271
|
end
|
|
269
272
|
end
|
|
@@ -369,8 +372,8 @@ module ActiveSupport
|
|
|
369
372
|
if pipeline
|
|
370
373
|
pipeline.set(key, payload, **modifiers)
|
|
371
374
|
else
|
|
372
|
-
failsafe :write_entry, returning:
|
|
373
|
-
redis.then { |c| c.set
|
|
375
|
+
failsafe :write_entry, returning: nil do
|
|
376
|
+
redis.then { |c| !!c.set(key, payload, **modifiers) }
|
|
374
377
|
end
|
|
375
378
|
end
|
|
376
379
|
end
|
|
@@ -477,7 +480,7 @@ module ActiveSupport
|
|
|
477
480
|
|
|
478
481
|
def failsafe(method, returning: nil)
|
|
479
482
|
yield
|
|
480
|
-
rescue ::Redis::BaseError => error
|
|
483
|
+
rescue ::Redis::BaseError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
|
|
481
484
|
@error_handler&.call(method: method, exception: error, returning: returning)
|
|
482
485
|
returning
|
|
483
486
|
end
|
|
@@ -63,28 +63,6 @@ module ActiveSupport
|
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
module Marshal61WithFallback
|
|
67
|
-
include SerializerWithFallback
|
|
68
|
-
extend self
|
|
69
|
-
|
|
70
|
-
MARSHAL_SIGNATURE = "\x04\x08".b.freeze
|
|
71
|
-
|
|
72
|
-
def dump(entry)
|
|
73
|
-
Marshal.dump(entry)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def dump_compressed(entry, threshold)
|
|
77
|
-
Marshal.dump(entry.compressed(threshold))
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
alias_method :_load, :marshal_load
|
|
81
|
-
public :_load
|
|
82
|
-
|
|
83
|
-
def dumped?(dumped)
|
|
84
|
-
dumped.start_with?(MARSHAL_SIGNATURE)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
66
|
module Marshal70WithFallback
|
|
89
67
|
include SerializerWithFallback
|
|
90
68
|
extend self
|
|
@@ -165,7 +143,6 @@ module ActiveSupport
|
|
|
165
143
|
|
|
166
144
|
SERIALIZERS = {
|
|
167
145
|
passthrough: PassthroughWithFallback,
|
|
168
|
-
marshal_6_1: Marshal61WithFallback,
|
|
169
146
|
marshal_7_0: Marshal70WithFallback,
|
|
170
147
|
marshal_7_1: Marshal71WithFallback,
|
|
171
148
|
message_pack: MessagePackWithFallback,
|