activesupport 7.1.5.1 → 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.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +213 -1082
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/array_inquirer.rb +1 -1
  5. data/lib/active_support/backtrace_cleaner.rb +10 -3
  6. data/lib/active_support/broadcast_logger.rb +65 -78
  7. data/lib/active_support/cache/file_store.rb +17 -12
  8. data/lib/active_support/cache/mem_cache_store.rb +29 -89
  9. data/lib/active_support/cache/memory_store.rb +7 -6
  10. data/lib/active_support/cache/null_store.rb +2 -2
  11. data/lib/active_support/cache/redis_cache_store.rb +17 -14
  12. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  13. data/lib/active_support/cache/strategy/local_cache.rb +56 -20
  14. data/lib/active_support/cache.rb +63 -71
  15. data/lib/active_support/callbacks.rb +77 -115
  16. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  17. data/lib/active_support/core_ext/benchmark.rb +1 -0
  18. data/lib/active_support/core_ext/class/attribute.rb +2 -2
  19. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  20. data/lib/active_support/core_ext/date/blank.rb +4 -0
  21. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  22. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  23. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  24. data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
  25. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  26. data/lib/active_support/core_ext/enumerable.rb +17 -5
  27. data/lib/active_support/core_ext/erb/util.rb +7 -2
  28. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  29. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  30. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  31. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  32. data/lib/active_support/core_ext/module/introspection.rb +3 -0
  33. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  34. data/lib/active_support/core_ext/object/blank.rb +45 -1
  35. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  36. data/lib/active_support/core_ext/object/json.rb +1 -1
  37. data/lib/active_support/core_ext/object/try.rb +2 -2
  38. data/lib/active_support/core_ext/object/with.rb +5 -3
  39. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  40. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  41. data/lib/active_support/core_ext/range/sole.rb +17 -0
  42. data/lib/active_support/core_ext/range.rb +1 -0
  43. data/lib/active_support/core_ext/securerandom.rb +4 -4
  44. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  45. data/lib/active_support/core_ext/string/filters.rb +4 -4
  46. data/lib/active_support/core_ext/string/multibyte.rb +3 -3
  47. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  48. data/lib/active_support/core_ext/time/calculations.rb +18 -28
  49. data/lib/active_support/core_ext/time/compatibility.rb +24 -0
  50. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  51. data/lib/active_support/core_ext/time/zones.rb +1 -1
  52. data/lib/active_support/core_ext.rb +0 -1
  53. data/lib/active_support/current_attributes.rb +45 -40
  54. data/lib/active_support/delegation.rb +202 -0
  55. data/lib/active_support/dependencies/autoload.rb +0 -12
  56. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  57. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  58. data/lib/active_support/deprecation/reporting.rb +7 -2
  59. data/lib/active_support/deprecation.rb +8 -5
  60. data/lib/active_support/descendants_tracker.rb +9 -87
  61. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  62. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  63. data/lib/active_support/duration.rb +11 -6
  64. data/lib/active_support/encrypted_file.rb +1 -1
  65. data/lib/active_support/error_reporter.rb +46 -5
  66. data/lib/active_support/evented_file_update_checker.rb +0 -1
  67. data/lib/active_support/execution_wrapper.rb +1 -2
  68. data/lib/active_support/file_update_checker.rb +2 -2
  69. data/lib/active_support/fork_tracker.rb +2 -38
  70. data/lib/active_support/gem_version.rb +3 -3
  71. data/lib/active_support/hash_with_indifferent_access.rb +26 -24
  72. data/lib/active_support/html_safe_translation.rb +3 -0
  73. data/lib/active_support/json/decoding.rb +1 -1
  74. data/lib/active_support/json/encoding.rb +23 -5
  75. data/lib/active_support/lazy_load_hooks.rb +1 -1
  76. data/lib/active_support/log_subscriber.rb +0 -12
  77. data/lib/active_support/logger.rb +15 -2
  78. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  79. data/lib/active_support/message_encryptors.rb +2 -2
  80. data/lib/active_support/message_pack/extensions.rb +15 -2
  81. data/lib/active_support/message_verifier.rb +21 -0
  82. data/lib/active_support/message_verifiers.rb +5 -3
  83. data/lib/active_support/messages/rotator.rb +5 -0
  84. data/lib/active_support/multibyte/chars.rb +6 -3
  85. data/lib/active_support/notifications/fanout.rb +4 -7
  86. data/lib/active_support/notifications/instrumenter.rb +21 -18
  87. data/lib/active_support/notifications.rb +28 -27
  88. data/lib/active_support/number_helper/number_converter.rb +2 -2
  89. data/lib/active_support/option_merger.rb +2 -2
  90. data/lib/active_support/ordered_options.rb +53 -15
  91. data/lib/active_support/proxy_object.rb +8 -5
  92. data/lib/active_support/railtie.rb +4 -11
  93. data/lib/active_support/string_inquirer.rb +1 -1
  94. data/lib/active_support/subscriber.rb +1 -0
  95. data/lib/active_support/tagged_logging.rb +0 -1
  96. data/lib/active_support/test_case.rb +3 -1
  97. data/lib/active_support/testing/assertions.rb +4 -4
  98. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  99. data/lib/active_support/testing/deprecation.rb +5 -12
  100. data/lib/active_support/testing/isolation.rb +20 -8
  101. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  102. data/lib/active_support/testing/parallelization/server.rb +18 -2
  103. data/lib/active_support/testing/parallelization/worker.rb +2 -2
  104. data/lib/active_support/testing/parallelization.rb +12 -1
  105. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  106. data/lib/active_support/testing/time_helpers.rb +3 -3
  107. data/lib/active_support/time_with_zone.rb +8 -4
  108. data/lib/active_support/values/time_zone.rb +7 -7
  109. data/lib/active_support/xml_mini.rb +13 -2
  110. data/lib/active_support.rb +2 -1
  111. metadata +18 -29
  112. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  113. data/lib/active_support/ruby_features.rb +0 -7
  114. 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 rails-core mailing list here:
38
+ Feature requests should be discussed on the rubyonrails-core forum here:
39
39
 
40
40
  * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -39,7 +39,7 @@ module ActiveSupport
39
39
  name.end_with?("?") || super
40
40
  end
41
41
 
42
- def method_missing(name, *args)
42
+ def method_missing(name, ...)
43
43
  if name.end_with?("?")
44
44
  any?(name[0..-2])
45
45
  else
@@ -17,7 +17,8 @@ module ActiveSupport
17
17
  # can focus on the rest.
18
18
  #
19
19
  # bc = ActiveSupport::BacktraceCleaner.new
20
- # bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
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 "/app/models/person.rb"
80
- # backtrace_cleaner.add_filter { |line| line.gsub(Rails.root.to_s, '') }
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.map(&:level).min
110
- end
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 formatter=(formatter)
146
- dispatch { |logger| logger.formatter = formatter }
147
-
148
- @formatter = formatter
149
- end
113
+ def local_level
114
+ loggers = @broadcasts.select { |logger| logger.respond_to?(:local_level) }
150
115
 
151
- def level=(level)
152
- dispatch { |logger| logger.level = level }
116
+ loggers.map do |logger|
117
+ logger.local_level
118
+ end.first
153
119
  end
154
- alias_method :sev_threshold=, :level=
155
120
 
156
- def local_level=(level)
157
- dispatch do |logger|
158
- logger.local_level = level if logger.respond_to?(:local_level=)
159
- end
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
- def close
163
- dispatch { |logger| logger.close }
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
- # +True+ if the log level allows entries with severity Logger::DEBUG to be written
167
- # to at least one broadcast. +False+ otherwise.
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 { |logger| logger.debug! }
147
+ dispatch(:debug!)
175
148
  end
176
149
 
177
- # +True+ if the log level allows entries with severity Logger::INFO to be written
178
- # to at least one broadcast. +False+ otherwise.
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 { |logger| logger.info! }
158
+ dispatch(:info!)
186
159
  end
187
160
 
188
- # +True+ if the log level allows entries with severity Logger::WARN to be written
189
- # to at least one broadcast. +False+ otherwise.
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 { |logger| logger.warn! }
169
+ dispatch(:warn!)
197
170
  end
198
171
 
199
- # +True+ if the log level allows entries with severity Logger::ERROR to be written
200
- # to at least one broadcast. +False+ otherwise.
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 { |logger| logger.error! }
180
+ dispatch(:error!)
208
181
  end
209
182
 
210
- # +True+ if the log level allows entries with severity Logger::FATAL to be written
211
- # to at least one broadcast. +False+ otherwise.
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 { |logger| logger.fatal! }
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
- @broadcasts.each { |logger| block.call(logger) }
232
- true
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, *args, **kwargs, &block)
222
+ def method_missing(name, ...)
236
223
  loggers = @broadcasts.select { |logger| logger.respond_to?(name) }
237
224
 
238
225
  if loggers.none?
239
- super(name, *args, **kwargs, &block)
226
+ super
240
227
  elsif loggers.one?
241
- loggers.first.send(name, *args, **kwargs, &block)
228
+ loggers.first.send(name, ...)
242
229
  else
243
- loggers.map { |logger| logger.send(name, *args, **kwargs, &block) }
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 = nil)
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 = nil)
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
- file_name = normalize_key(name, options)
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(file_name) do
215
- options = merged_options(options)
218
+ lock_file(key) do
219
+ entry = read_entry(key, **options)
216
220
 
217
- if num = read(name, options)
218
- num = num.to_i + amount
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
- if addresses.first.is_a?(Dalli::Client)
130
- ActiveSupport.deprecator.warn(<<~MSG)
131
- Initializing MemCacheStore with a Dalli::Client is deprecated and will be removed in Rails 7.2.
132
- Use memcached server addresses instead.
133
- MSG
134
- @data = addresses.first
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
- instrument(:increment, name, amount: amount) do
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(normalize_key(name, options), amount, options[:expires_in], amount) }
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
- instrument(:decrement, name, amount: amount) do
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(normalize_key(name, options), amount, options[:expires_in], 0) }
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 false do
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
- raw_values = begin
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
- values = {}
218
+ values = {}
280
219
 
281
- raw_values.each do |key, value|
282
- entry = deserialize_entry(value, raw: options[:raw])
220
+ raw_values.each do |key, value|
221
+ entry = deserialize_entry(value, raw: options[:raw])
283
222
 
284
- unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
285
- begin
286
- values[keys_to_names[key]] = entry.value
287
- rescue DeserializationError
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
- values
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 = nil)
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 = nil)
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 = nil)
28
+ def increment(name, amount = 1, **options)
29
29
  end
30
30
 
31
- def decrement(name, amount = 1, options = nil)
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
- instrument :delete_matched, matcher do
200
- unless String === matcher
201
- raise ArgumentError, "Only Redis glob strings are supported: #{matcher.inspect}"
202
- end
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
- instrument :increment, name, amount: amount do
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
- instrument :decrement, name, amount: amount do
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: false do
373
- redis.then { |c| c.set key, payload, **modifiers }
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,