activesupport 7.1.4.1 → 7.2.2.1

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -1129
  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 -18
  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 +60 -68
  12. data/lib/active_support/callbacks.rb +74 -113
  13. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  14. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  15. data/lib/active_support/core_ext/date/blank.rb +4 -0
  16. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  17. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  18. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  19. data/lib/active_support/core_ext/date_time/conversions.rb +0 -4
  20. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  21. data/lib/active_support/core_ext/erb/util.rb +5 -0
  22. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  23. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  24. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  25. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  26. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  27. data/lib/active_support/core_ext/object/blank.rb +45 -1
  28. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  29. data/lib/active_support/core_ext/object/json.rb +6 -4
  30. data/lib/active_support/core_ext/object/with.rb +5 -3
  31. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  32. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  33. data/lib/active_support/core_ext/securerandom.rb +8 -24
  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/multibyte.rb +1 -1
  37. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  38. data/lib/active_support/core_ext/time/calculations.rb +18 -28
  39. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  40. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  41. data/lib/active_support/core_ext/time/zones.rb +1 -1
  42. data/lib/active_support/core_ext.rb +0 -1
  43. data/lib/active_support/current_attributes.rb +38 -40
  44. data/lib/active_support/delegation.rb +202 -0
  45. data/lib/active_support/dependencies/autoload.rb +0 -12
  46. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  47. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  48. data/lib/active_support/deprecation/reporting.rb +9 -4
  49. data/lib/active_support/deprecation.rb +8 -5
  50. data/lib/active_support/descendants_tracker.rb +9 -87
  51. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  52. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  53. data/lib/active_support/duration.rb +11 -6
  54. data/lib/active_support/encrypted_file.rb +1 -1
  55. data/lib/active_support/error_reporter.rb +41 -3
  56. data/lib/active_support/evented_file_update_checker.rb +0 -1
  57. data/lib/active_support/execution_wrapper.rb +0 -1
  58. data/lib/active_support/file_update_checker.rb +1 -1
  59. data/lib/active_support/fork_tracker.rb +2 -38
  60. data/lib/active_support/gem_version.rb +2 -2
  61. data/lib/active_support/hash_with_indifferent_access.rb +6 -8
  62. data/lib/active_support/html_safe_translation.rb +3 -0
  63. data/lib/active_support/log_subscriber.rb +0 -12
  64. data/lib/active_support/logger.rb +15 -2
  65. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  66. data/lib/active_support/message_pack/extensions.rb +15 -2
  67. data/lib/active_support/message_verifier.rb +12 -0
  68. data/lib/active_support/multibyte/chars.rb +2 -2
  69. data/lib/active_support/notifications/fanout.rb +4 -7
  70. data/lib/active_support/notifications/instrumenter.rb +21 -18
  71. data/lib/active_support/notifications.rb +28 -27
  72. data/lib/active_support/number_helper/number_converter.rb +2 -2
  73. data/lib/active_support/option_merger.rb +2 -2
  74. data/lib/active_support/ordered_options.rb +53 -15
  75. data/lib/active_support/proxy_object.rb +8 -5
  76. data/lib/active_support/railtie.rb +4 -11
  77. data/lib/active_support/string_inquirer.rb +1 -1
  78. data/lib/active_support/subscriber.rb +1 -0
  79. data/lib/active_support/tagged_logging.rb +0 -1
  80. data/lib/active_support/test_case.rb +3 -1
  81. data/lib/active_support/testing/assertions.rb +4 -4
  82. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  83. data/lib/active_support/testing/deprecation.rb +5 -12
  84. data/lib/active_support/testing/isolation.rb +20 -8
  85. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  86. data/lib/active_support/testing/parallelization/server.rb +3 -0
  87. data/lib/active_support/testing/strict_warnings.rb +8 -4
  88. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  89. data/lib/active_support/testing/time_helpers.rb +3 -3
  90. data/lib/active_support/time_with_zone.rb +8 -4
  91. data/lib/active_support/values/time_zone.rb +7 -7
  92. data/lib/active_support/xml_mini.rb +11 -2
  93. data/lib/active_support.rb +2 -1
  94. metadata +49 -15
  95. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  96. 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(*args, &block)
117
- dispatch { |logger| logger.add(*args, &block) }
116
+ def add(...)
117
+ dispatch { |logger| logger.add(...) }
118
118
  end
119
119
  alias_method :log, :add
120
120
 
121
- def debug(*args, &block)
122
- dispatch { |logger| logger.debug(*args, &block) }
121
+ def debug(...)
122
+ dispatch { |logger| logger.debug(...) }
123
123
  end
124
124
 
125
- def info(*args, &block)
126
- dispatch { |logger| logger.info(*args, &block) }
125
+ def info(...)
126
+ dispatch { |logger| logger.info(...) }
127
127
  end
128
128
 
129
- def warn(*args, &block)
130
- dispatch { |logger| logger.warn(*args, &block) }
129
+ def warn(...)
130
+ dispatch { |logger| logger.warn(...) }
131
131
  end
132
132
 
133
- def error(*args, &block)
134
- dispatch { |logger| logger.error(*args, &block) }
133
+ def error(...)
134
+ dispatch { |logger| logger.error(...) }
135
135
  end
136
136
 
137
- def fatal(*args, &block)
138
- dispatch { |logger| logger.fatal(*args, &block) }
137
+ def fatal(...)
138
+ dispatch { |logger| logger.fatal(...) }
139
139
  end
140
140
 
141
- def unknown(*args, &block)
142
- dispatch { |logger| logger.unknown(*args, &block) }
141
+ def unknown(...)
142
+ dispatch { |logger| logger.unknown(...) }
143
143
  end
144
144
 
145
145
  def formatter=(formatter)
@@ -232,15 +232,15 @@ module ActiveSupport
232
232
  true
233
233
  end
234
234
 
235
- def method_missing(name, *args, **kwargs, &block)
235
+ def method_missing(name, ...)
236
236
  loggers = @broadcasts.select { |logger| logger.respond_to?(name) }
237
237
 
238
238
  if loggers.none?
239
- super(name, *args, **kwargs, &block)
239
+ super
240
240
  elsif loggers.one?
241
- loggers.first.send(name, *args, **kwargs, &block)
241
+ loggers.first.send(name, ...)
242
242
  else
243
- loggers.map { |logger| logger.send(name, *args, **kwargs, &block) }
243
+ loggers.map { |logger| logger.send(name, ...) }
244
244
  end
245
245
  end
246
246
 
@@ -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,