activesupport 8.0.1 → 8.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4fc487978c855f357de44a7915c8d6d21161a4731bfe676294c1a39f91083d8
4
- data.tar.gz: e0c7577dabe5346cdcaddef70cb94d58d636df12bef5f7b96df8c062f1831d08
3
+ metadata.gz: 7f094945c33f1c6e036f987c0cc7405a0146f0c800635e1fc16d8a1c34910cb7
4
+ data.tar.gz: 9ffe8729fffcae283965435a590eb7db596a43fa39c8565e814abab6e16e0444
5
5
  SHA512:
6
- metadata.gz: 2fc772fb80613c40405114a4cf7a806fe77766ee128c7c308de18eedd73fa6581f95dd072cdf38b13947d91d9df560620b8126b199577b293f2095c4c6d0481e
7
- data.tar.gz: 8aa7beb41005f500c9d4d1287f2f11724f7178aaa9953c089d4afb5523060136da33771f3ac0ee5edf8dc91afcb9bd31272eaeef650c9238c670c6f0c82b18cb
6
+ metadata.gz: a391e85fc1235084e201abc2736139578767397fa4a503573e82c5f7f339e13d13b5702302ff37176a26a8d80203fc914682e40c570d933aa282e2fb92f26e76
7
+ data.tar.gz: 6adf2e0b528f17bcd51373d8e627c4ec77de8967c968fdab89fb2bac11952bf98f5ffb6910cdf372cf57bd7929f539808dc783160b0456a803783264421016ce
data/CHANGELOG.md CHANGED
@@ -1,3 +1,101 @@
1
+ ## Rails 8.0.2 (March 12, 2025) ##
2
+
3
+ * No changes.
4
+
5
+
6
+ ## Rails 8.0.2 (March 12, 2025) ##
7
+
8
+ * Fix setting `to_time_preserves_timezone` from `new_framework_defaults_8_0.rb`.
9
+
10
+ *fatkodima*
11
+
12
+ * Fix Active Support Cache `fetch_multi` when local store is active.
13
+
14
+ `fetch_multi` now properly yield to the provided block for missing entries
15
+ that have been recorded as such in the local store.
16
+
17
+ *Jean Boussier*
18
+
19
+ * Fix execution wrapping to report all exceptions, including `Exception`.
20
+
21
+ If a more serious error like `SystemStackError` or `NoMemoryError` happens,
22
+ the error reporter should be able to report these kinds of exceptions.
23
+
24
+ *Gannon McGibbon*
25
+
26
+ * Fix `RedisCacheStore` and `MemCacheStore` to also handle connection pool related errors.
27
+
28
+ These errors are rescued and reported to `Rails.error`.
29
+
30
+ *Jean Boussier*
31
+
32
+ * Fix `ActiveSupport::Cache#read_multi` to respect version expiry when using local cache.
33
+
34
+ *zzak*
35
+
36
+ * Fix `ActiveSupport::MessageVerifier` and `ActiveSupport::MessageEncryptor` configuration of `on_rotation` callback.
37
+
38
+ ```ruby
39
+ verifier.rotate(old_secret).on_rotation { ... }
40
+ ```
41
+
42
+ Now both work as documented.
43
+
44
+ *Jean Boussier*
45
+
46
+ * Fix `ActiveSupport::MessageVerifier` to always be able to verify both URL-safe and URL-unsafe payloads.
47
+
48
+ This is to allow transitioning seemlessly from either configuration without immediately invalidating
49
+ all previously generated signed messages.
50
+
51
+ *Jean Boussier*, *Florent Beaurain*, *Ali Sepehri*
52
+
53
+ * Fix `cache.fetch` to honor the provided expiry when `:race_condition_ttl` is used.
54
+
55
+ ```ruby
56
+ cache.fetch("key", expires_in: 1.hour, race_condition_ttl: 5.second) do
57
+ "something"
58
+ end
59
+ ```
60
+
61
+ In the above example, the final cache entry would have a 10 seconds TTL instead
62
+ of the requested 1 hour.
63
+
64
+ *Dhia*
65
+
66
+ * Better handle procs with splat arguments in `set_callback`.
67
+
68
+ *Radamés Roriz*
69
+
70
+ * Fix `String#mb_chars` to not mutate the receiver.
71
+
72
+ Previously it would call `force_encoding` on the receiver,
73
+ now it dups the receiver first.
74
+
75
+ *Jean Boussier*
76
+
77
+ * Improve `ErrorSubscriber` to also mark error causes as reported.
78
+
79
+ This avoid some cases of errors being reported twice, notably in views because of how
80
+ errors are wrapped in `ActionView::Template::Error`.
81
+
82
+ *Jean Boussier*
83
+
84
+ * Fix `Module#module_parent_name` to return the correct name after the module has been named.
85
+
86
+ When called on an anonymous module, the return value wouldn't change after the module was given a name
87
+ later by being assigned to a constant.
88
+
89
+ ```ruby
90
+ mod = Module.new
91
+ mod.module_parent_name # => "Object"
92
+ MyModule::Something = mod
93
+ mod.module_parent_name # => "MyModule"
94
+ ```
95
+
96
+ *Jean Boussier*
97
+
98
+
1
99
  ## Rails 8.0.1 (December 13, 2024) ##
2
100
 
3
101
  * Fix a bug in `ERB::Util.tokenize` that causes incorrect tokenization when ERB tags are preceeded by multibyte characters.
@@ -79,7 +79,7 @@ module ActiveSupport
79
79
  #
80
80
  # # Will turn "/my/rails/root/app/models/person.rb" into "app/models/person.rb"
81
81
  # root = "#{Rails.root}/"
82
- # backtrace_cleaner.add_filter { |line| line.start_with?(root) ? line.from(root.size) : line }
82
+ # backtrace_cleaner.add_filter { |line| line.delete_prefix(root) }
83
83
  def add_filter(&block)
84
84
  @filters << block
85
85
  end
@@ -163,57 +163,57 @@ module ActiveSupport
163
163
  dispatch { |logger| logger.close }
164
164
  end
165
165
 
166
- # +True+ if the log level allows entries with severity Logger::DEBUG to be written
167
- # to at least one broadcast. +False+ otherwise.
166
+ # True if the log level allows entries with severity +Logger::DEBUG+ to be written
167
+ # to at least one broadcast. False otherwise.
168
168
  def debug?
169
169
  @broadcasts.any? { |logger| logger.debug? }
170
170
  end
171
171
 
172
- # Sets the log level to Logger::DEBUG for the whole broadcast.
172
+ # Sets the log level to +Logger::DEBUG+ for the whole broadcast.
173
173
  def debug!
174
174
  dispatch { |logger| logger.debug! }
175
175
  end
176
176
 
177
- # +True+ if the log level allows entries with severity Logger::INFO to be written
178
- # to at least one broadcast. +False+ otherwise.
177
+ # True if the log level allows entries with severity +Logger::INFO+ to be written
178
+ # to at least one broadcast. False otherwise.
179
179
  def info?
180
180
  @broadcasts.any? { |logger| logger.info? }
181
181
  end
182
182
 
183
- # Sets the log level to Logger::INFO for the whole broadcast.
183
+ # Sets the log level to +Logger::INFO+ for the whole broadcast.
184
184
  def info!
185
185
  dispatch { |logger| logger.info! }
186
186
  end
187
187
 
188
- # +True+ if the log level allows entries with severity Logger::WARN to be written
189
- # to at least one broadcast. +False+ otherwise.
188
+ # True if the log level allows entries with severity +Logger::WARN+ to be written
189
+ # to at least one broadcast. False otherwise.
190
190
  def warn?
191
191
  @broadcasts.any? { |logger| logger.warn? }
192
192
  end
193
193
 
194
- # Sets the log level to Logger::WARN for the whole broadcast.
194
+ # Sets the log level to +Logger::WARN+ for the whole broadcast.
195
195
  def warn!
196
196
  dispatch { |logger| logger.warn! }
197
197
  end
198
198
 
199
- # +True+ if the log level allows entries with severity Logger::ERROR to be written
200
- # to at least one broadcast. +False+ otherwise.
199
+ # True if the log level allows entries with severity +Logger::ERROR+ to be written
200
+ # to at least one broadcast. False otherwise.
201
201
  def error?
202
202
  @broadcasts.any? { |logger| logger.error? }
203
203
  end
204
204
 
205
- # Sets the log level to Logger::ERROR for the whole broadcast.
205
+ # Sets the log level to +Logger::ERROR+ for the whole broadcast.
206
206
  def error!
207
207
  dispatch { |logger| logger.error! }
208
208
  end
209
209
 
210
- # +True+ if the log level allows entries with severity Logger::FATAL to be written
211
- # to at least one broadcast. +False+ otherwise.
210
+ # True if the log level allows entries with severity +Logger::FATAL+ to be written
211
+ # to at least one broadcast. False otherwise.
212
212
  def fatal?
213
213
  @broadcasts.any? { |logger| logger.fatal? }
214
214
  end
215
215
 
216
- # Sets the log level to Logger::FATAL for the whole broadcast.
216
+ # Sets the log level to +Logger::FATAL+ for the whole broadcast.
217
217
  def fatal!
218
218
  dispatch { |logger| logger.fatal! }
219
219
  end
@@ -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
  options = merged_options(options)
62
62
  key = normalize_key(name, options)
63
63
 
@@ -77,7 +77,7 @@ module ActiveSupport
77
77
  # cache.write("baz", 5)
78
78
  # cache.decrement("baz") # => 4
79
79
  #
80
- def decrement(name, amount = 1, options = nil)
80
+ def decrement(name, amount = 1, **options)
81
81
  options = merged_options(options)
82
82
  key = normalize_key(name, options)
83
83
 
@@ -276,7 +276,7 @@ module ActiveSupport
276
276
 
277
277
  def rescue_error_with(fallback)
278
278
  yield
279
- rescue Dalli::DalliError => error
279
+ rescue Dalli::DalliError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
280
280
  logger.error("DalliError (#{error}): #{error.message}") if logger
281
281
  ActiveSupport.error_reporter&.report(
282
282
  error,
@@ -146,9 +146,9 @@ module ActiveSupport
146
146
  # cache.write("baz", 5)
147
147
  # cache.increment("baz") # => 6
148
148
  #
149
- def increment(name, amount = 1, options = nil)
149
+ def increment(name, amount = 1, **options)
150
150
  instrument(:increment, name, amount: amount) do
151
- modify_value(name, amount, options)
151
+ modify_value(name, amount, **options)
152
152
  end
153
153
  end
154
154
 
@@ -163,9 +163,9 @@ module ActiveSupport
163
163
  # cache.write("baz", 5)
164
164
  # cache.decrement("baz") # => 4
165
165
  #
166
- def decrement(name, amount = 1, options = nil)
166
+ def decrement(name, amount = 1, **options)
167
167
  instrument(:decrement, name, amount: amount) do
168
- modify_value(name, -amount, options)
168
+ modify_value(name, -amount, **options)
169
169
  end
170
170
  end
171
171
 
@@ -238,7 +238,7 @@ module ActiveSupport
238
238
 
239
239
  # Modifies the amount of an integer value that is stored in the cache.
240
240
  # If the key is not found it is created and set to +amount+.
241
- def modify_value(name, amount, options)
241
+ def modify_value(name, amount, **options)
242
242
  options = merged_options(options)
243
243
  key = normalize_key(name, options)
244
244
  version = normalize_version(name, options)
@@ -25,10 +25,10 @@ module ActiveSupport
25
25
  def cleanup(options = nil)
26
26
  end
27
27
 
28
- def increment(name, amount = 1, options = 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)
@@ -483,7 +483,7 @@ module ActiveSupport
483
483
 
484
484
  def failsafe(method, returning: nil)
485
485
  yield
486
- rescue ::Redis::BaseError => error
486
+ rescue ::Redis::BaseError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
487
487
  @error_handler&.call(method: method, exception: error, returning: returning)
488
488
  returning
489
489
  end
@@ -94,28 +94,54 @@ module ActiveSupport
94
94
  super
95
95
  end
96
96
 
97
- def increment(name, amount = 1, options = nil) # :nodoc:
97
+ def increment(name, amount = 1, **options) # :nodoc:
98
98
  return super unless local_cache
99
99
  value = bypass_local_cache { super }
100
- if options
101
- write_cache_value(name, value, raw: true, **options)
102
- else
103
- write_cache_value(name, value, raw: true)
104
- end
100
+ write_cache_value(name, value, raw: true, **options)
105
101
  value
106
102
  end
107
103
 
108
- def decrement(name, amount = 1, options = nil) # :nodoc:
104
+ def decrement(name, amount = 1, **options) # :nodoc:
109
105
  return super unless local_cache
110
106
  value = bypass_local_cache { super }
111
- if options
112
- write_cache_value(name, value, raw: true, **options)
113
- else
114
- write_cache_value(name, value, raw: true)
115
- end
107
+ write_cache_value(name, value, raw: true, **options)
116
108
  value
117
109
  end
118
110
 
111
+ def fetch_multi(*names, &block) # :nodoc:
112
+ return super if local_cache.nil? || names.empty?
113
+
114
+ options = names.extract_options!
115
+ options = merged_options(options)
116
+
117
+ keys_to_names = names.index_by { |name| normalize_key(name, options) }
118
+
119
+ local_entries = local_cache.read_multi_entries(keys_to_names.keys)
120
+ results = local_entries.each_with_object({}) do |(key, value), result|
121
+ # If we recorded a miss in the local cache, `#fetch_multi` will forward
122
+ # that key to the real store, and the entry will be replaced
123
+ # local_cache.delete_entry(key)
124
+ next if value.nil?
125
+
126
+ entry = deserialize_entry(value, **options)
127
+
128
+ normalized_key = keys_to_names[key]
129
+ if entry.nil?
130
+ result[normalized_key] = nil
131
+ elsif entry.expired? || entry.mismatched?(normalize_version(normalized_key, options))
132
+ local_cache.delete_entry(key)
133
+ else
134
+ result[normalized_key] = entry.value
135
+ end
136
+ end
137
+
138
+ if results.size < names.size
139
+ results.merge!(super(*(names - results.keys), options, &block))
140
+ end
141
+
142
+ results
143
+ end
144
+
119
145
  private
120
146
  def read_serialized_entry(key, raw: false, **options)
121
147
  if cache = local_cache
@@ -137,17 +163,27 @@ module ActiveSupport
137
163
  keys_to_names = names.index_by { |name| normalize_key(name, options) }
138
164
 
139
165
  local_entries = local_cache.read_multi_entries(keys_to_names.keys)
140
- local_entries.transform_keys! { |key| keys_to_names[key] }
141
- local_entries.transform_values! do |payload|
142
- deserialize_entry(payload, **options)&.value
166
+
167
+ results = local_entries.each_with_object({}) do |(key, value), result|
168
+ next if value.nil? # recorded cache miss
169
+
170
+ entry = deserialize_entry(value, **options)
171
+
172
+ normalized_key = keys_to_names[key]
173
+ if entry.nil?
174
+ result[normalized_key] = nil
175
+ elsif entry.expired? || entry.mismatched?(normalize_version(normalized_key, options))
176
+ local_cache.delete_entry(key)
177
+ else
178
+ result[normalized_key] = entry.value
179
+ end
143
180
  end
144
- missed_names = names - local_entries.keys
145
181
 
146
- if missed_names.any?
147
- local_entries.merge!(super(missed_names, **options))
148
- else
149
- local_entries
182
+ if results.size < names.size
183
+ results.merge!(super(names - results.keys, **options))
150
184
  end
185
+
186
+ results
151
187
  end
152
188
 
153
189
  def write_serialized_entry(key, payload, **)
@@ -386,7 +386,7 @@ module ActiveSupport
386
386
  # process can try to generate a new value after the extended time window
387
387
  # has elapsed.
388
388
  #
389
- # # Set all values to expire after one minute.
389
+ # # Set all values to expire after one second.
390
390
  # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
391
391
  #
392
392
  # cache.write("foo", "original value")
@@ -1035,8 +1035,7 @@ module ActiveSupport
1035
1035
  # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
1036
1036
  # for a brief period while the entry is being recalculated.
1037
1037
  entry.expires_at = Time.now.to_f + race_ttl
1038
- options[:expires_in] = race_ttl * 2
1039
- write_entry(key, entry, **options)
1038
+ write_entry(key, entry, **options, expires_in: race_ttl * 2)
1040
1039
  else
1041
1040
  delete_entry(key, **options)
1042
1041
  end
@@ -498,9 +498,10 @@ module ActiveSupport
498
498
  when Conditionals::Value
499
499
  ProcCall.new(filter)
500
500
  when ::Proc
501
- if filter.arity > 1
501
+ case filter.arity
502
+ when 2
502
503
  InstanceExec2.new(filter)
503
- elsif filter.arity > 0
504
+ when 1, -2
504
505
  InstanceExec1.new(filter)
505
506
  else
506
507
  InstanceExec0.new(filter)
@@ -203,7 +203,7 @@ module Enumerable
203
203
  end
204
204
 
205
205
  # Returns the sole item in the enumerable. If there are no items, or more
206
- # than one item, raises +Enumerable::SoleItemExpectedError+.
206
+ # than one item, raises Enumerable::SoleItemExpectedError.
207
207
  #
208
208
  # ["x"].sole # => "x"
209
209
  # Set.new.sole # => Enumerable::SoleItemExpectedError: no item found
@@ -36,6 +36,7 @@ class Hash
36
36
  #--
37
37
  # Implemented by ActiveSupport::DeepMergeable#deep_merge!.
38
38
 
39
+ ##
39
40
  def deep_merge?(other) # :nodoc:
40
41
  other.is_a?(Hash)
41
42
  end
@@ -10,6 +10,9 @@ class Module
10
10
  if defined?(@parent_name)
11
11
  @parent_name
12
12
  else
13
+ name = self.name
14
+ return if name.nil?
15
+
13
16
  parent_name = name =~ /::[^:]+\z/ ? -$` : nil
14
17
  @parent_name = parent_name unless frozen?
15
18
  parent_name
@@ -187,7 +187,7 @@ module ActiveSupport
187
187
  super
188
188
  return if name == :initialize
189
189
  return unless public_method_defined?(name)
190
- return if respond_to?(name, true)
190
+ return if singleton_class.method_defined?(name) || singleton_class.private_method_defined?(name)
191
191
  Delegation.generate(singleton_class, [name], to: :instance, as: self, nilable: false)
192
192
  end
193
193
  end
@@ -207,6 +207,12 @@ module ActiveSupport
207
207
  #
208
208
  # Rails.error.report(error)
209
209
  #
210
+ # The +error+ argument must be an instance of Exception.
211
+ #
212
+ # Rails.error.report(Exception.new("Something went wrong"))
213
+ #
214
+ # Otherwise you can use #unexpected to report an error which does accept a
215
+ # string argument.
210
216
  def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
211
217
  return if error.instance_variable_defined?(:@__rails_error_reported)
212
218
  ensure_backtrace(error)
@@ -232,8 +238,11 @@ module ActiveSupport
232
238
  end
233
239
  end
234
240
 
235
- unless error.frozen?
236
- error.instance_variable_set(:@__rails_error_reported, true)
241
+ while error
242
+ unless error.frozen?
243
+ error.instance_variable_set(:@__rails_error_reported, true)
244
+ end
245
+ error = error.cause
237
246
  end
238
247
 
239
248
  nil
@@ -89,7 +89,7 @@ module ActiveSupport
89
89
  instance = run!
90
90
  begin
91
91
  yield
92
- rescue => error
92
+ rescue Exception => error
93
93
  error_reporter&.report(error, handled: false, source: source)
94
94
  raise
95
95
  ensure
@@ -9,7 +9,7 @@ module ActiveSupport
9
9
  module VERSION
10
10
  MAJOR = 8
11
11
  MINOR = 0
12
- TINY = 1
12
+ TINY = 2
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -13,12 +13,30 @@ module ActiveSupport
13
13
  end
14
14
 
15
15
  module JSON
16
- # Dumps objects in JSON (JavaScript Object Notation).
17
- # See http://www.json.org for more info.
18
- #
19
- # ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
20
- # # => "{\"team\":\"rails\",\"players\":\"36\"}"
21
16
  class << self
17
+ # Dumps objects in JSON (JavaScript Object Notation).
18
+ # See http://www.json.org for more info.
19
+ #
20
+ # ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
21
+ # # => "{\"team\":\"rails\",\"players\":\"36\"}"
22
+ #
23
+ # Generates JSON that is safe to include in JavaScript as it escapes
24
+ # U+2028 (Line Separator) and U+2029 (Paragraph Separator):
25
+ #
26
+ # ActiveSupport::JSON.encode({ key: "\u2028" })
27
+ # # => "{\"key\":\"\\u2028\"}"
28
+ #
29
+ # By default, it also generates JSON that is safe to include in HTML, as
30
+ # it escapes <tt><</tt>, <tt>></tt>, and <tt>&</tt>:
31
+ #
32
+ # ActiveSupport::JSON.encode({ key: "<>&" })
33
+ # # => "{\"key\":\"\\u003c\\u003e\\u0026\"}"
34
+ #
35
+ # This can be changed with the +escape_html_entities+ option, or the
36
+ # global escape_html_entities_in_json configuration option.
37
+ #
38
+ # ActiveSupport::JSON.encode({ key: "<>&" }, escape_html_entities: false)
39
+ # # => "{\"key\":\"<>&\"}"
22
40
  def encode(value, options = nil)
23
41
  Encoding.json_encoder.new(options).encode(value)
24
42
  end
@@ -28,8 +28,8 @@ module ActiveSupport
28
28
  # <tt>transitional = false</tt>.
29
29
 
30
30
  ##
31
- # :method: initialize
32
- # :call-seq: initialize(&secret_generator)
31
+ # :singleton-method: new
32
+ # :call-seq: new(&secret_generator)
33
33
  #
34
34
  # Initializes a new instance. +secret_generator+ must accept a salt and a
35
35
  # +secret_length+ kwarg, and return a suitable secret (string) or secrets
@@ -154,6 +154,8 @@ module ActiveSupport
154
154
  # not URL-safe. In other words, they can contain "+" and "/". If you want to
155
155
  # generate URL-safe strings (in compliance with "Base 64 Encoding with URL
156
156
  # and Filename Safe Alphabet" in RFC 4648), you can pass +true+.
157
+ # Note that MessageVerifier will always accept both URL-safe and URL-unsafe
158
+ # encoded messages, to allow a smooth transition between the two settings.
157
159
  #
158
160
  # [+:force_legacy_metadata_serializer+]
159
161
  # Whether to use the legacy metadata serializer, which serializes the
@@ -318,6 +320,13 @@ module ActiveSupport
318
320
  end
319
321
 
320
322
  private
323
+ def decode(encoded, url_safe: @url_safe)
324
+ catch :invalid_message_format do
325
+ return super
326
+ end
327
+ super(encoded, url_safe: !url_safe)
328
+ end
329
+
321
330
  def sign_encoded(encoded)
322
331
  digest = generate_digest(encoded)
323
332
  encoded << SEPARATOR << digest
@@ -28,8 +28,8 @@ module ActiveSupport
28
28
  # <tt>transitional = false</tt>.
29
29
 
30
30
  ##
31
- # :method: initialize
32
- # :call-seq: initialize(&secret_generator)
31
+ # :singleton-method: new
32
+ # :call-seq: new(&secret_generator)
33
33
  #
34
34
  # Initializes a new instance. +secret_generator+ must accept a salt, and
35
35
  # return a suitable secret (string). +secret_generator+ may also accept
@@ -59,7 +59,9 @@ module ActiveSupport
59
59
 
60
60
  ##
61
61
  # :method: rotate
62
- # :call-seq: rotate(**options)
62
+ # :call-seq:
63
+ # rotate(**options)
64
+ # rotate(&block)
63
65
  #
64
66
  # Adds +options+ to the list of option sets. Messages will be signed using
65
67
  # the first set in the list. When verifying, however, each set will be
@@ -15,6 +15,11 @@ module ActiveSupport
15
15
  fall_back_to build_rotation(*args, **options)
16
16
  end
17
17
 
18
+ def on_rotation(&on_rotation)
19
+ @on_rotation = on_rotation
20
+ self
21
+ end
22
+
18
23
  def fall_back_to(fallback)
19
24
  @rotations << fallback
20
25
  self
@@ -55,7 +55,10 @@ module ActiveSupport # :nodoc:
55
55
  # Creates a new Chars instance by wrapping _string_.
56
56
  def initialize(string)
57
57
  @wrapped_string = string
58
- @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
58
+ if string.encoding != Encoding::UTF_8
59
+ @wrapped_string = @wrapped_string.dup
60
+ @wrapped_string.force_encoding(Encoding::UTF_8)
61
+ end
59
62
  end
60
63
 
61
64
  # Forward all undefined methods to the wrapped string.
@@ -97,7 +97,9 @@ module ActiveSupport
97
97
  end
98
98
 
99
99
  initializer "active_support.to_time_preserves_timezone" do |app|
100
- ActiveSupport.to_time_preserves_timezone = app.config.active_support.to_time_preserves_timezone
100
+ config.after_initialize do
101
+ ActiveSupport.to_time_preserves_timezone = app.config.active_support.to_time_preserves_timezone
102
+ end
101
103
  end
102
104
 
103
105
  # Sets the default week start
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activesupport
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.1
4
+ version: 8.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-12-13 00:00:00.000000000 Z
10
+ date: 2025-03-12 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: i18n
@@ -475,7 +474,6 @@ files:
475
474
  - lib/active_support/testing/parallelize_executor.rb
476
475
  - lib/active_support/testing/setup_and_teardown.rb
477
476
  - lib/active_support/testing/stream.rb
478
- - lib/active_support/testing/strict_warnings.rb
479
477
  - lib/active_support/testing/tagged_logging.rb
480
478
  - lib/active_support/testing/tests_without_assertions.rb
481
479
  - lib/active_support/testing/time_helpers.rb
@@ -495,12 +493,11 @@ licenses:
495
493
  - MIT
496
494
  metadata:
497
495
  bug_tracker_uri: https://github.com/rails/rails/issues
498
- changelog_uri: https://github.com/rails/rails/blob/v8.0.1/activesupport/CHANGELOG.md
499
- documentation_uri: https://api.rubyonrails.org/v8.0.1/
496
+ changelog_uri: https://github.com/rails/rails/blob/v8.0.2/activesupport/CHANGELOG.md
497
+ documentation_uri: https://api.rubyonrails.org/v8.0.2/
500
498
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
501
- source_code_uri: https://github.com/rails/rails/tree/v8.0.1/activesupport
499
+ source_code_uri: https://github.com/rails/rails/tree/v8.0.2/activesupport
502
500
  rubygems_mfa_required: 'true'
503
- post_install_message:
504
501
  rdoc_options:
505
502
  - "--encoding"
506
503
  - UTF-8
@@ -517,8 +514,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
517
514
  - !ruby/object:Gem::Version
518
515
  version: '0'
519
516
  requirements: []
520
- rubygems_version: 3.5.22
521
- signing_key:
517
+ rubygems_version: 3.6.2
522
518
  specification_version: 4
523
519
  summary: A toolkit of support libraries and Ruby core extensions extracted from the
524
520
  Rails framework.
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $VERBOSE = true
4
- Warning[:deprecated] = true
5
-
6
- module ActiveSupport
7
- module RaiseWarnings # :nodoc:
8
- class WarningError < StandardError; end
9
-
10
- PROJECT_ROOT = File.expand_path("../../../../", __dir__)
11
- ALLOWED_WARNINGS = Regexp.union(
12
- /circular require considered harmful.*delayed_job/, # Bug in delayed job.
13
-
14
- # Expected non-verbose warning emitted by Rails.
15
- /Ignoring .*\.yml because it has expired/,
16
- /Failed to validate the schema cache because/,
17
-
18
- # TODO: We need to decide what to do with this.
19
- /Status code :unprocessable_entity is deprecated/,
20
- )
21
-
22
- SUPPRESSED_WARNINGS = Regexp.union(
23
- # TODO: remove if https://github.com/mikel/mail/pull/1557 or similar fix
24
- %r{/lib/mail/parsers/.*statement not reached},
25
- %r{/lib/mail/parsers/.*assigned but unused variable - disp_type_s},
26
- %r{/lib/mail/parsers/.*assigned but unused variable - testEof}
27
- )
28
-
29
- def warn(message, ...)
30
- return if SUPPRESSED_WARNINGS.match?(message)
31
-
32
- super
33
-
34
- return unless message.include?(PROJECT_ROOT)
35
- return if ALLOWED_WARNINGS.match?(message)
36
- return unless ENV["RAILS_STRICT_WARNINGS"] || ENV["BUILDKITE"]
37
-
38
- raise WarningError.new(message)
39
- end
40
- end
41
- end
42
-
43
- Warning.singleton_class.prepend(ActiveSupport::RaiseWarnings)