activesupport 7.1.5.1 → 7.2.0.beta1

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +113 -1178
  3. data/lib/active_support/array_inquirer.rb +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +10 -3
  5. data/lib/active_support/broadcast_logger.rb +18 -19
  6. data/lib/active_support/cache/file_store.rb +15 -10
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -74
  8. data/lib/active_support/cache/memory_store.rb +2 -1
  9. data/lib/active_support/cache/redis_cache_store.rb +16 -13
  10. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  11. data/lib/active_support/cache.rb +59 -67
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/code_generator.rb +10 -15
  14. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  15. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  16. data/lib/active_support/core_ext/date/blank.rb +4 -0
  17. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  18. data/lib/active_support/core_ext/date_and_time/compatibility.rb +12 -9
  19. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  20. data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
  21. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  22. data/lib/active_support/core_ext/erb/util.rb +5 -0
  23. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  24. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  25. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  26. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  27. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  28. data/lib/active_support/core_ext/object/blank.rb +45 -1
  29. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  30. data/lib/active_support/core_ext/object/json.rb +4 -6
  31. data/lib/active_support/core_ext/object/with.rb +5 -3
  32. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  33. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  34. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/string/filters.rb +1 -1
  36. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  37. data/lib/active_support/core_ext/time/calculations.rb +12 -27
  38. data/lib/active_support/core_ext/time/compatibility.rb +2 -3
  39. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  40. data/lib/active_support/core_ext.rb +0 -1
  41. data/lib/active_support/current_attributes.rb +33 -40
  42. data/lib/active_support/delegation.rb +188 -0
  43. data/lib/active_support/dependencies/autoload.rb +0 -12
  44. data/lib/active_support/deprecation/constant_accessor.rb +1 -3
  45. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  46. data/lib/active_support/deprecation/reporting.rb +9 -4
  47. data/lib/active_support/deprecation.rb +8 -5
  48. data/lib/active_support/descendants_tracker.rb +9 -87
  49. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  50. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  51. data/lib/active_support/duration.rb +11 -6
  52. data/lib/active_support/error_reporter.rb +41 -3
  53. data/lib/active_support/evented_file_update_checker.rb +0 -1
  54. data/lib/active_support/execution_wrapper.rb +0 -1
  55. data/lib/active_support/file_update_checker.rb +1 -1
  56. data/lib/active_support/fork_tracker.rb +2 -38
  57. data/lib/active_support/gem_version.rb +3 -3
  58. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  59. data/lib/active_support/html_safe_translation.rb +3 -0
  60. data/lib/active_support/log_subscriber.rb +0 -12
  61. data/lib/active_support/logger.rb +15 -2
  62. data/lib/active_support/message_pack/extensions.rb +15 -2
  63. data/lib/active_support/multibyte/chars.rb +2 -2
  64. data/lib/active_support/notifications/fanout.rb +4 -7
  65. data/lib/active_support/notifications/instrumenter.rb +21 -18
  66. data/lib/active_support/notifications.rb +28 -27
  67. data/lib/active_support/number_helper/number_converter.rb +2 -2
  68. data/lib/active_support/option_merger.rb +2 -2
  69. data/lib/active_support/ordered_options.rb +53 -15
  70. data/lib/active_support/proxy_object.rb +8 -5
  71. data/lib/active_support/railtie.rb +4 -11
  72. data/lib/active_support/string_inquirer.rb +1 -1
  73. data/lib/active_support/syntax_error_proxy.rb +11 -1
  74. data/lib/active_support/test_case.rb +3 -1
  75. data/lib/active_support/testing/assertions.rb +4 -4
  76. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  77. data/lib/active_support/testing/deprecation.rb +5 -12
  78. data/lib/active_support/testing/isolation.rb +18 -8
  79. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  80. data/lib/active_support/testing/strict_warnings.rb +5 -4
  81. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  82. data/lib/active_support/time_with_zone.rb +9 -10
  83. data/lib/active_support/values/time_zone.rb +1 -1
  84. data/lib/active_support/xml_mini.rb +11 -2
  85. data/lib/active_support.rb +7 -8
  86. metadata +20 -70
  87. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  88. data/lib/active_support/ruby_features.rb +0 -7
@@ -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.start_with?(root) ? line.from(root.size) : line }
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?
@@ -113,33 +113,33 @@ module ActiveSupport
113
113
  dispatch { |logger| logger.<<(message) }
114
114
  end
115
115
 
116
- def add(...)
117
- dispatch { |logger| logger.add(...) }
116
+ def add(*args, &block)
117
+ dispatch { |logger| logger.add(*args, &block) }
118
118
  end
119
119
  alias_method :log, :add
120
120
 
121
- def debug(...)
122
- dispatch { |logger| logger.debug(...) }
121
+ def debug(*args, &block)
122
+ dispatch { |logger| logger.debug(*args, &block) }
123
123
  end
124
124
 
125
- def info(...)
126
- dispatch { |logger| logger.info(...) }
125
+ def info(*args, &block)
126
+ dispatch { |logger| logger.info(*args, &block) }
127
127
  end
128
128
 
129
- def warn(...)
130
- dispatch { |logger| logger.warn(...) }
129
+ def warn(*args, &block)
130
+ dispatch { |logger| logger.warn(*args, &block) }
131
131
  end
132
132
 
133
- def error(...)
134
- dispatch { |logger| logger.error(...) }
133
+ def error(*args, &block)
134
+ dispatch { |logger| logger.error(*args, &block) }
135
135
  end
136
136
 
137
- def fatal(...)
138
- dispatch { |logger| logger.fatal(...) }
137
+ def fatal(*args, &block)
138
+ dispatch { |logger| logger.fatal(*args, &block) }
139
139
  end
140
140
 
141
- def unknown(...)
142
- dispatch { |logger| logger.unknown(...) }
141
+ def unknown(*args, &block)
142
+ dispatch { |logger| logger.unknown(*args, &block) }
143
143
  end
144
144
 
145
145
  def formatter=(formatter)
@@ -229,18 +229,17 @@ module ActiveSupport
229
229
  private
230
230
  def dispatch(&block)
231
231
  @broadcasts.each { |logger| block.call(logger) }
232
- true
233
232
  end
234
233
 
235
- def method_missing(name, *args, **kwargs, &block)
234
+ def method_missing(name, ...)
236
235
  loggers = @broadcasts.select { |logger| logger.respond_to?(name) }
237
236
 
238
237
  if loggers.none?
239
- super(name, *args, **kwargs, &block)
238
+ super
240
239
  elsif loggers.one?
241
- loggers.first.send(name, *args, **kwargs, &block)
240
+ loggers.first.send(name, ...)
242
241
  else
243
- loggers.map { |logger| logger.send(name, *args, **kwargs, &block) }
242
+ loggers.map { |logger| logger.send(name, ...) }
244
243
  end
245
244
  end
246
245
 
@@ -78,8 +78,9 @@ module ActiveSupport
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
 
@@ -168,8 +168,9 @@ module ActiveSupport
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)
@@ -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
@@ -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,
@@ -52,7 +52,7 @@ module ActiveSupport
52
52
  autoload :LocalCache, "active_support/cache/strategy/local_cache"
53
53
  end
54
54
 
55
- @format_version = 6.1
55
+ @format_version = 7.0
56
56
 
57
57
  class << self
58
58
  attr_accessor :format_version
@@ -86,13 +86,7 @@ module ActiveSupport
86
86
  case store
87
87
  when Symbol
88
88
  options = parameters.extract_options!
89
- # clean this up once Ruby 2.7 support is dropped
90
- # see https://github.com/rails/rails/pull/41522#discussion_r581186602
91
- if options.empty?
92
- retrieve_store_class(store).new(*parameters)
93
- else
94
- retrieve_store_class(store).new(*parameters, **options)
95
- end
89
+ retrieve_store_class(store).new(*parameters, **options)
96
90
  when Array
97
91
  lookup_store(*store)
98
92
  when nil
@@ -166,7 +160,7 @@ module ActiveSupport
166
160
  # cache = ActiveSupport::Cache::MemoryStore.new
167
161
  #
168
162
  # cache.read('city') # => nil
169
- # cache.write('city', "Duckburgh")
163
+ # cache.write('city', "Duckburgh") # => true
170
164
  # cache.read('city') # => "Duckburgh"
171
165
  #
172
166
  # cache.write('not serializable', Proc.new {}) # => TypeError
@@ -206,24 +200,6 @@ module ActiveSupport
206
200
  def retrieve_pool_options(options)
207
201
  if options.key?(:pool)
208
202
  pool_options = options.delete(:pool)
209
- elsif options.key?(:pool_size) || options.key?(:pool_timeout)
210
- pool_options = {}
211
-
212
- if options.key?(:pool_size)
213
- ActiveSupport.deprecator.warn(<<~MSG)
214
- Using :pool_size is deprecated and will be removed in Rails 7.2.
215
- Use `pool: { size: #{options[:pool_size].inspect} }` instead.
216
- MSG
217
- pool_options[:size] = options.delete(:pool_size)
218
- end
219
-
220
- if options.key?(:pool_timeout)
221
- ActiveSupport.deprecator.warn(<<~MSG)
222
- Using :pool_timeout is deprecated and will be removed in Rails 7.2.
223
- Use `pool: { timeout: #{options[:pool_timeout].inspect} }` instead.
224
- MSG
225
- pool_options[:timeout] = options.delete(:pool_timeout)
226
- end
227
203
  else
228
204
  pool_options = true
229
205
  end
@@ -344,7 +320,7 @@ module ActiveSupport
344
320
 
345
321
  # Silences the logger within a block.
346
322
  def mute
347
- previous_silence, @silence = defined?(@silence) && @silence, true
323
+ previous_silence, @silence = @silence, true
348
324
  yield
349
325
  ensure
350
326
  @silence = previous_silence
@@ -411,31 +387,47 @@ module ActiveSupport
411
387
  # has elapsed.
412
388
  #
413
389
  # # Set all values to expire after one minute.
414
- # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
390
+ # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
415
391
  #
416
- # cache.write('foo', 'original value')
392
+ # cache.write("foo", "original value")
417
393
  # val_1 = nil
418
394
  # val_2 = nil
419
- # sleep 60
395
+ # p cache.read("foo") # => "original value"
420
396
  #
421
- # Thread.new do
422
- # val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
397
+ # sleep 1 # wait until the cache expires
398
+ #
399
+ # t1 = Thread.new do
400
+ # # fetch does the following:
401
+ # # 1. gets an recent expired entry
402
+ # # 2. extends the expiry by 2 seconds (race_condition_ttl)
403
+ # # 3. regenerates the new value
404
+ # val_1 = cache.fetch("foo", race_condition_ttl: 2) do
423
405
  # sleep 1
424
- # 'new value 1'
406
+ # "new value 1"
425
407
  # end
426
408
  # end
427
409
  #
428
- # Thread.new do
429
- # val_2 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
430
- # 'new value 2'
431
- # end
410
+ # # Wait until t1 extends the expiry of the entry
411
+ # # but before generating the new value
412
+ # sleep 0.1
413
+ #
414
+ # val_2 = cache.fetch("foo", race_condition_ttl: 2) do
415
+ # # This block won't be executed because t1 extended the expiry
416
+ # "new value 2"
432
417
  # end
433
418
  #
434
- # cache.fetch('foo') # => "original value"
435
- # sleep 10 # First thread extended the life of cache by another 10 seconds
436
- # cache.fetch('foo') # => "new value 1"
437
- # val_1 # => "new value 1"
438
- # val_2 # => "original value"
419
+ # t1.join
420
+ #
421
+ # p val_1 # => "new value 1"
422
+ # p val_2 # => "oritinal value"
423
+ # p cache.fetch("foo") # => "new value 1"
424
+ #
425
+ # # The entry requires 3 seconds to expire (expires_in + race_condition_ttl)
426
+ # # We have waited 2 seconds already (sleep(1) + t1.join) thus we need to wait 1
427
+ # # more second to see the entry expire.
428
+ # sleep 1
429
+ #
430
+ # p cache.fetch("foo") # => nil
439
431
  #
440
432
  # ==== Dynamic Options
441
433
  #
@@ -456,7 +448,7 @@ module ActiveSupport
456
448
 
457
449
  entry = nil
458
450
  unless options[:force]
459
- instrument(:read, name, options) do |payload|
451
+ instrument(:read, key, options) do |payload|
460
452
  cached_entry = read_entry(key, **options, event: payload)
461
453
  entry = handle_expired_entry(cached_entry, key, options)
462
454
  if entry
@@ -478,7 +470,7 @@ module ActiveSupport
478
470
  if entry
479
471
  get_entry_value(entry, name, options)
480
472
  else
481
- save_block_result_to_cache(name, options, &block)
473
+ save_block_result_to_cache(name, key, options, &block)
482
474
  end
483
475
  elsif options && options[:force]
484
476
  raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
@@ -508,7 +500,7 @@ module ActiveSupport
508
500
  key = normalize_key(name, options)
509
501
  version = normalize_version(name, options)
510
502
 
511
- instrument(:read, name, options) do |payload|
503
+ instrument(:read, key, options) do |payload|
512
504
  entry = read_entry(key, **options, event: payload)
513
505
 
514
506
  if entry
@@ -605,14 +597,14 @@ module ActiveSupport
605
597
  options = names.extract_options!
606
598
  options = merged_options(options)
607
599
 
608
- instrument_multi :read_multi, names, options do |payload|
600
+ writes = {}
601
+ ordered = instrument_multi :read_multi, names, options do |payload|
609
602
  if options[:force]
610
603
  reads = {}
611
604
  else
612
605
  reads = read_multi_entries(names, **options)
613
606
  end
614
607
 
615
- writes = {}
616
608
  ordered = names.index_with do |name|
617
609
  reads.fetch(name) { writes[name] = yield(name) }
618
610
  end
@@ -621,15 +613,20 @@ module ActiveSupport
621
613
  payload[:hits] = reads.keys
622
614
  payload[:super_operation] = :fetch_multi
623
615
 
624
- write_multi(writes, options)
625
-
626
616
  ordered
627
617
  end
618
+
619
+ write_multi(writes, options)
620
+
621
+ ordered
628
622
  end
629
623
 
630
624
  # Writes the value to the cache with the key. The value must be supported
631
625
  # by the +coder+'s +dump+ and +load+ methods.
632
626
  #
627
+ # Returns +true+ if the write succeeded, +nil+ if there was an error talking
628
+ # to the cache backend, or +false+ if the write failed for another reason.
629
+ #
633
630
  # By default, cache entries larger than 1kB are compressed. Compression
634
631
  # allows more data to be stored in the same memory footprint, leading to
635
632
  # fewer cache evictions and higher hit rates.
@@ -662,10 +659,11 @@ module ActiveSupport
662
659
  # Other options will be handled by the specific cache store implementation.
663
660
  def write(name, value, options = nil)
664
661
  options = merged_options(options)
662
+ key = normalize_key(name, options)
665
663
 
666
- instrument(:write, name, options) do
664
+ instrument(:write, key, options) do
667
665
  entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
668
- write_entry(normalize_key(name, options), entry, **options)
666
+ write_entry(key, entry, **options)
669
667
  end
670
668
  end
671
669
 
@@ -675,9 +673,10 @@ module ActiveSupport
675
673
  # Options are passed to the underlying cache implementation.
676
674
  def delete(name, options = nil)
677
675
  options = merged_options(options)
676
+ key = normalize_key(name, options)
678
677
 
679
- instrument(:delete, name) do
680
- delete_entry(normalize_key(name, options), **options)
678
+ instrument(:delete, key) do
679
+ delete_entry(key, **options)
681
680
  end
682
681
  end
683
682
 
@@ -701,9 +700,10 @@ module ActiveSupport
701
700
  # Options are passed to the underlying cache implementation.
702
701
  def exist?(name, options = nil)
703
702
  options = merged_options(options)
703
+ key = normalize_key(name, options)
704
704
 
705
- instrument(:exist?, name) do |payload|
706
- entry = read_entry(normalize_key(name, options), **options, event: payload)
705
+ instrument(:exist?, key) do |payload|
706
+ entry = read_entry(key, **options, event: payload)
707
707
  (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
708
708
  end
709
709
  end
@@ -761,14 +761,6 @@ module ActiveSupport
761
761
  private
762
762
  def default_serializer
763
763
  case Cache.format_version
764
- when 6.1
765
- ActiveSupport.deprecator.warn <<~EOM
766
- Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.
767
-
768
- Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
769
- for more information on how to upgrade.
770
- EOM
771
- Cache::SerializerWithFallback[:marshal_6_1]
772
764
  when 7.0
773
765
  Cache::SerializerWithFallback[:marshal_7_0]
774
766
  when 7.1
@@ -1016,7 +1008,7 @@ module ActiveSupport
1016
1008
  if multi
1017
1009
  ": #{payload[:key].size} key(s) specified"
1018
1010
  elsif payload[:key]
1019
- ": #{normalize_key(payload[:key], options)}"
1011
+ ": #{payload[:key]}"
1020
1012
  end
1021
1013
 
1022
1014
  debug_options = " (#{options.inspect})" unless options.blank?
@@ -1053,10 +1045,10 @@ module ActiveSupport
1053
1045
  entry.value
1054
1046
  end
1055
1047
 
1056
- def save_block_result_to_cache(name, options)
1048
+ def save_block_result_to_cache(name, key, options)
1057
1049
  options = options.dup
1058
1050
 
1059
- result = instrument(:generate, name, options) do
1051
+ result = instrument(:generate, key, options) do
1060
1052
  yield(name, WriteOptions.new(options))
1061
1053
  end
1062
1054