activesupport 8.0.3 → 8.1.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +237 -175
  3. data/lib/active_support/backtrace_cleaner.rb +71 -0
  4. data/lib/active_support/cache/mem_cache_store.rb +13 -13
  5. data/lib/active_support/cache/redis_cache_store.rb +36 -30
  6. data/lib/active_support/cache/strategy/local_cache.rb +16 -7
  7. data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
  8. data/lib/active_support/cache.rb +69 -6
  9. data/lib/active_support/configurable.rb +28 -0
  10. data/lib/active_support/continuous_integration.rb +145 -0
  11. data/lib/active_support/core_ext/benchmark.rb +0 -1
  12. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  13. data/lib/active_support/core_ext/erb/util.rb +3 -3
  14. data/lib/active_support/core_ext/object/json.rb +8 -1
  15. data/lib/active_support/core_ext/object/to_query.rb +5 -0
  16. data/lib/active_support/core_ext/range.rb +0 -1
  17. data/lib/active_support/core_ext/string/multibyte.rb +10 -1
  18. data/lib/active_support/core_ext/string/output_safety.rb +19 -12
  19. data/lib/active_support/current_attributes/test_helper.rb +2 -2
  20. data/lib/active_support/current_attributes.rb +13 -10
  21. data/lib/active_support/deprecation/reporting.rb +4 -2
  22. data/lib/active_support/deprecation.rb +1 -1
  23. data/lib/active_support/editor.rb +70 -0
  24. data/lib/active_support/error_reporter.rb +50 -6
  25. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  26. data/lib/active_support/event_reporter.rb +570 -0
  27. data/lib/active_support/evented_file_update_checker.rb +5 -1
  28. data/lib/active_support/execution_context.rb +64 -7
  29. data/lib/active_support/file_update_checker.rb +8 -6
  30. data/lib/active_support/gem_version.rb +3 -3
  31. data/lib/active_support/gzip.rb +1 -0
  32. data/lib/active_support/hash_with_indifferent_access.rb +27 -7
  33. data/lib/active_support/i18n_railtie.rb +1 -2
  34. data/lib/active_support/inflector/inflections.rb +31 -15
  35. data/lib/active_support/inflector/transliterate.rb +6 -8
  36. data/lib/active_support/isolated_execution_state.rb +7 -13
  37. data/lib/active_support/json/decoding.rb +2 -2
  38. data/lib/active_support/json/encoding.rb +103 -14
  39. data/lib/active_support/log_subscriber.rb +2 -0
  40. data/lib/active_support/message_encryptors.rb +52 -0
  41. data/lib/active_support/message_pack/extensions.rb +5 -0
  42. data/lib/active_support/message_verifiers.rb +52 -0
  43. data/lib/active_support/messages/rotation_coordinator.rb +9 -0
  44. data/lib/active_support/messages/rotator.rb +5 -0
  45. data/lib/active_support/multibyte/chars.rb +8 -1
  46. data/lib/active_support/multibyte.rb +4 -0
  47. data/lib/active_support/railtie.rb +26 -12
  48. data/lib/active_support/syntax_error_proxy.rb +3 -0
  49. data/lib/active_support/test_case.rb +61 -6
  50. data/lib/active_support/testing/assertions.rb +34 -6
  51. data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
  52. data/lib/active_support/testing/event_reporter_assertions.rb +217 -0
  53. data/lib/active_support/testing/notification_assertions.rb +92 -0
  54. data/lib/active_support/testing/parallelization/worker.rb +2 -0
  55. data/lib/active_support/testing/parallelization.rb +13 -0
  56. data/lib/active_support/testing/tests_without_assertions.rb +1 -1
  57. data/lib/active_support/testing/time_helpers.rb +7 -3
  58. data/lib/active_support/time_with_zone.rb +19 -5
  59. data/lib/active_support/values/time_zone.rb +8 -1
  60. data/lib/active_support/xml_mini.rb +1 -2
  61. data/lib/active_support.rb +11 -0
  62. metadata +10 -5
  63. data/lib/active_support/core_ext/range/each.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2cdf9736ba5b94841913f95e5e83f01cc82becad9006ed2d75e18f1cc117c43
4
- data.tar.gz: 7f8f545780e7ecfece1bdd6af006e504d91e89ad019a1020cd43014a296e7def
3
+ metadata.gz: 961314ec0e1413ca082492acda67d57e19e5011d13725707c3b3d83cb3e88b6c
4
+ data.tar.gz: '0918a0dcb857f0621acf8c0034cc568efceddbaf92991da1d73ea1a3ae892f40'
5
5
  SHA512:
6
- metadata.gz: b23ff4bae6aae8f2e154b478c8f36825d0179152a0591591c240ea2b8d6104dcad0b70598a9b42888ab41448a06bc6b69c4ca537c1e5edb386fa81408f25acde
7
- data.tar.gz: 84fa236c5c86feff0ae2283888ca7266c5f5d9090474b099c2b9142c082e107062bea571d8197f0138a022d7db7fe08e02f3544ade6cd611de68c35b26b90e75
6
+ metadata.gz: d167935a467f95a7dd138a7498328e7f8bb5970ad79e33ea43267fe79d6a40f5515abc768f9aa995d15e8678638e34a4b1ce925797a216bc7b5b26ab8ea97be7
7
+ data.tar.gz: 01edbccd59380207d979f9a504619a862c475217eecd9c8972af5868e4f870e405a511babb6925a7723038c7da395a94ecbaf1a3e3e8fb1f4f07dd7300d0321a
data/CHANGELOG.md CHANGED
@@ -1,309 +1,371 @@
1
- ## Rails 8.0.3 (September 22, 2025) ##
1
+ ## Rails 8.1.0.beta1 (September 04, 2025) ##
2
2
 
3
- * `ActiveSupport::FileUpdateChecker` does not depend on `Time.now` to prevent unnecessary reloads with time travel test helpers
3
+ * Add `ActiveSupport::Cache::Store#namespace=` and `#namespace`.
4
4
 
5
- *Jan Grodowski*
5
+ Can be used as an alternative to `Store#clear` in some situations such as parallel
6
+ testing.
6
7
 
7
- * Fix `ActiveSupport::BroadcastLogger` from executing a block argument for each logger (tagged, info, etc.).
8
-
9
- *Jared Armstrong*
10
-
11
- * Make `ActiveSupport::Logger` `#freeze`-friendly.
12
-
13
- *Joshua Young*
8
+ *Nick Schwaderer*
14
9
 
15
- * Fix `ActiveSupport::HashWithIndifferentAccess#transform_keys!` removing defaults.
10
+ * Create `parallel_worker_id` helper for running parallel tests. This allows users to
11
+ know which worker they are currently running in.
16
12
 
17
- *Hartley McGuire*
13
+ *Nick Schwaderer*
18
14
 
19
- * Fix `ActiveSupport::HashWithIndifferentAccess#tranform_keys!` to handle collisions.
15
+ * Make the cache of `ActiveSupport::Cache::Strategy::LocalCache::Middleware` updatable.
20
16
 
21
- If the transformation would result in a key equal to another not yet transformed one,
22
- it would result in keys being lost.
17
+ If the cache client at `Rails.cache` of a booted application changes, the corresponding
18
+ mounted middleware needs to update in order for request-local caches to be setup properly.
19
+ Otherwise, redundant cache operations will erroneously hit the datastore.
23
20
 
24
- Before:
21
+ *Gannon McGibbon*
25
22
 
26
- ```ruby
27
- >> {a: 1, b: 2}.with_indifferent_access.transform_keys!(&:succ)
28
- => {"c" => 1}
29
- ```
23
+ * Add `assert_events_reported` test helper for `ActiveSupport::EventReporter`.
30
24
 
31
- After:
25
+ This new assertion allows testing multiple events in a single block, regardless of order:
32
26
 
33
27
  ```ruby
34
- >> {a: 1, b: 2}.with_indifferent_access.transform_keys!(&:succ)
35
- => {"c" => 1, "d" => 2}
28
+ assert_events_reported([
29
+ { name: "user.created", payload: { id: 123 } },
30
+ { name: "email.sent", payload: { to: "user@example.com" } }
31
+ ]) do
32
+ create_user_and_send_welcome_email
33
+ end
36
34
  ```
37
35
 
38
- *Jason T Johnson*, *Jean Boussier*
39
-
40
- * Fix `ActiveSupport::Cache::MemCacheStore#read_multi` to handle network errors.
41
-
42
- This method specifically wasn't handling network errors like other codepaths.
36
+ *George Ma*
43
37
 
44
- *Alessandro Dal Grande*
38
+ * Add `ActiveSupport::TimeZone#standard_name` method.
45
39
 
46
- * Fix configuring `RedisCacheStore` with `raw: true`.
47
-
48
- *fatkodima*
40
+ ``` ruby
41
+ zone = ActiveSupport::TimeZone['Hawaii']
42
+ # Old way
43
+ ActiveSupport::TimeZone::MAPPING[zone.name]
44
+ # New way
45
+ zone.standard_name # => 'Pacific/Honolulu'
46
+ ```
49
47
 
50
- * Fix `Enumerable#sole` for infinite collections.
48
+ *Bogdan Gusiev*
51
49
 
52
- *fatkodima*
50
+ * Add Structured Event Reporter, accessible via `Rails.event`.
53
51
 
52
+ The Event Reporter provides a unified interface for producing structured events in Rails
53
+ applications:
54
54
 
55
- ## Rails 8.0.2.1 (August 13, 2025) ##
55
+ ```ruby
56
+ Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")
57
+ ```
56
58
 
57
- * No changes.
59
+ It supports adding tags to events:
58
60
 
61
+ ```ruby
62
+ Rails.event.tagged("graphql") do
63
+ # Event includes tags: { graphql: true }
64
+ Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")
65
+ end
66
+ ```
59
67
 
60
- ## Rails 8.0.2 (March 12, 2025) ##
68
+ As well as context:
69
+ ```ruby
70
+ # All events will contain context: {request_id: "abc123", shop_id: 456}
71
+ Rails.event.set_context(request_id: "abc123", shop_id: 456)
72
+ ```
61
73
 
62
- * Fix setting `to_time_preserves_timezone` from `new_framework_defaults_8_0.rb`.
74
+ Events are emitted to subscribers. Applications register subscribers to
75
+ control how events are serialized and emitted. Subscribers must implement
76
+ an `#emit` method, which receives the event hash:
63
77
 
64
- *fatkodima*
78
+ ```ruby
79
+ class LogSubscriber
80
+ def emit(event)
81
+ payload = event[:payload].map { |key, value| "#{key}=#{value}" }.join(" ")
82
+ source_location = event[:source_location]
83
+ log = "[#{event[:name]}] #{payload} at #{source_location[:filepath]}:#{source_location[:lineno]}"
84
+ Rails.logger.info(log)
85
+ end
86
+ end
87
+ ```
65
88
 
66
- * Fix Active Support Cache `fetch_multi` when local store is active.
89
+ *Adrianna Chang*
67
90
 
68
- `fetch_multi` now properly yield to the provided block for missing entries
69
- that have been recorded as such in the local store.
91
+ * Make `ActiveSupport::Logger` `#freeze`-friendly.
70
92
 
71
- *Jean Boussier*
93
+ *Joshua Young*
72
94
 
73
- * Fix execution wrapping to report all exceptions, including `Exception`.
95
+ * Make `ActiveSupport::Gzip.compress` deterministic based on input.
74
96
 
75
- If a more serious error like `SystemStackError` or `NoMemoryError` happens,
76
- the error reporter should be able to report these kinds of exceptions.
97
+ `ActiveSupport::Gzip.compress` used to include a timestamp in the output,
98
+ causing consecutive calls with the same input data to have different output
99
+ if called during different seconds. It now always sets the timestamp to `0`
100
+ so that the output is identical for any given input.
77
101
 
78
- *Gannon McGibbon*
102
+ *Rob Brackett*
79
103
 
80
- * Fix `RedisCacheStore` and `MemCacheStore` to also handle connection pool related errors.
104
+ * Given an array of `Thread::Backtrace::Location` objects, the new method
105
+ `ActiveSupport::BacktraceCleaner#clean_locations` returns an array with the
106
+ clean ones:
81
107
 
82
- These errors are rescued and reported to `Rails.error`.
108
+ ```ruby
109
+ clean_locations = backtrace_cleaner.clean_locations(caller_locations)
110
+ ```
83
111
 
84
- *Jean Boussier*
112
+ Filters and silencers receive strings as usual. However, the `path`
113
+ attributes of the locations in the returned array are the original,
114
+ unfiltered ones, since locations are immutable.
85
115
 
86
- * Fix `ActiveSupport::Cache#read_multi` to respect version expiry when using local cache.
116
+ *Xavier Noria*
87
117
 
88
- *zzak*
118
+ * Improve `CurrentAttributes` and `ExecutionContext` state managment in test cases.
89
119
 
90
- * Fix `ActiveSupport::MessageVerifier` and `ActiveSupport::MessageEncryptor` configuration of `on_rotation` callback.
120
+ Previously these two global state would be entirely cleared out whenever calling
121
+ into code that is wrapped by the Rails executor, typically Action Controller or
122
+ Active Job helpers:
91
123
 
92
124
  ```ruby
93
- verifier.rotate(old_secret).on_rotation { ... }
125
+ test "#index works" do
126
+ CurrentUser.id = 42
127
+ get :index
128
+ CurrentUser.id == nil
129
+ end
94
130
  ```
95
131
 
96
- Now both work as documented.
132
+ Now re-entering the executor properly save and restore that state.
97
133
 
98
134
  *Jean Boussier*
99
135
 
100
- * Fix `ActiveSupport::MessageVerifier` to always be able to verify both URL-safe and URL-unsafe payloads.
101
-
102
- This is to allow transitioning seemlessly from either configuration without immediately invalidating
103
- all previously generated signed messages.
104
-
105
- *Jean Boussier*, *Florent Beaurain*, *Ali Sepehri*
106
-
107
- * Fix `cache.fetch` to honor the provided expiry when `:race_condition_ttl` is used.
108
-
109
- ```ruby
110
- cache.fetch("key", expires_in: 1.hour, race_condition_ttl: 5.second) do
111
- "something"
112
- end
113
- ```
136
+ * The new method `ActiveSupport::BacktraceCleaner#first_clean_location`
137
+ returns the first clean location of the caller's call stack, or `nil`.
138
+ Locations are `Thread::Backtrace::Location` objects. Useful when you want to
139
+ report the application-level location where something happened as an object.
114
140
 
115
- In the above example, the final cache entry would have a 10 seconds TTL instead
116
- of the requested 1 hour.
141
+ *Xavier Noria*
117
142
 
118
- *Dhia*
143
+ * FileUpdateChecker and EventedFileUpdateChecker ignore changes in Gem.path now.
119
144
 
120
- * Better handle procs with splat arguments in `set_callback`.
145
+ *Ermolaev Andrey*, *zzak*
121
146
 
122
- *Radamés Roriz*
147
+ * The new method `ActiveSupport::BacktraceCleaner#first_clean_frame` returns
148
+ the first clean frame of the caller's backtrace, or `nil`. Useful when you
149
+ want to report the application-level frame where something happened as a
150
+ string.
123
151
 
124
- * Fix `String#mb_chars` to not mutate the receiver.
152
+ *Xavier Noria*
125
153
 
126
- Previously it would call `force_encoding` on the receiver,
127
- now it dups the receiver first.
154
+ * Always clear `CurrentAttributes` instances.
128
155
 
129
- *Jean Boussier*
156
+ Previously `CurrentAttributes` instance would be reset at the end of requests.
157
+ Meaning its attributes would be re-initialized.
130
158
 
131
- * Improve `ErrorSubscriber` to also mark error causes as reported.
159
+ This is problematic because it assume these objects don't hold any state
160
+ other than their declared attribute, which isn't always the case, and
161
+ can lead to state leak across request.
132
162
 
133
- This avoid some cases of errors being reported twice, notably in views because of how
134
- errors are wrapped in `ActionView::Template::Error`.
163
+ Now `CurrentAttributes` instances are abandoned at the end of a request,
164
+ and a new instance is created at the start of the next request.
135
165
 
136
- *Jean Boussier*
166
+ *Jean Boussier*, *Janko Marohnić*
137
167
 
138
- * Fix `Module#module_parent_name` to return the correct name after the module has been named.
168
+ * Add public API for `before_fork_hook` in parallel testing.
139
169
 
140
- When called on an anonymous module, the return value wouldn't change after the module was given a name
141
- later by being assigned to a constant.
170
+ Introduces a public API for calling the before fork hooks implemented by parallel testing.
142
171
 
143
172
  ```ruby
144
- mod = Module.new
145
- mod.module_parent_name # => "Object"
146
- MyModule::Something = mod
147
- mod.module_parent_name # => "MyModule"
173
+ parallelize_before_fork do
174
+ # perform an action before test processes are forked
175
+ end
148
176
  ```
149
177
 
150
- *Jean Boussier*
178
+ *Eileen M. Uchitelle*
151
179
 
180
+ * Implement ability to skip creating parallel testing databases.
152
181
 
153
- ## Rails 8.0.1 (December 13, 2024) ##
182
+ With parallel testing, Rails will create a database per process. If this isn't
183
+ desirable or you would like to implement databases handling on your own, you can
184
+ now turn off this default behavior.
154
185
 
155
- * Fix a bug in `ERB::Util.tokenize` that causes incorrect tokenization when ERB tags are preceeded by multibyte characters.
186
+ To skip creating a database per process, you can change it via the
187
+ `parallelize` method:
156
188
 
157
- *Martin Emde*
189
+ ```ruby
190
+ parallelize(workers: 10, parallelize_databases: false)
191
+ ```
158
192
 
159
- * Restore the ability to decorate methods generated by `class_attribute`.
193
+ or via the application configuration:
160
194
 
161
- It always has been complicated to use Module#prepend or an alias method chain
162
- to decorate methods defined by `class_attribute`, but became even harder in 8.0.
195
+ ```ruby
196
+ config.active_support.parallelize_databases = false
197
+ ```
163
198
 
164
- This capability is now supported for both reader and writer methods.
199
+ *Eileen M. Uchitelle*
165
200
 
166
- *Jean Boussier*
201
+ * Allow to configure maximum cache key sizes
167
202
 
203
+ When the key exceeds the configured limit (250 bytes by default), it will be truncated and
204
+ the digest of the rest of the key appended to it.
168
205
 
169
- ## Rails 8.0.0.1 (December 10, 2024) ##
206
+ Note that previously `ActiveSupport::Cache::RedisCacheStore` allowed up to 1kb cache keys before
207
+ truncation, which is now reduced to 250 bytes.
170
208
 
171
- * No changes.
209
+ ```ruby
210
+ config.cache_store = :redis_cache_store, { max_key_size: 64 }
211
+ ```
172
212
 
213
+ *fatkodima*
173
214
 
174
- ## Rails 8.0.0 (November 07, 2024) ##
215
+ * Use `UNLINK` command instead of `DEL` in `ActiveSupport::Cache::RedisCacheStore` for non-blocking deletion.
175
216
 
176
- * No changes.
217
+ *Aron Roh*
177
218
 
219
+ * Add `Cache#read_counter` and `Cache#write_counter`
178
220
 
179
- ## Rails 8.0.0.rc2 (October 30, 2024) ##
221
+ ```ruby
222
+ Rails.cache.write_counter("foo", 1)
223
+ Rails.cache.read_counter("foo") # => 1
224
+ Rails.cache.increment("foo")
225
+ Rails.cache.read_counter("foo") # => 2
226
+ ```
180
227
 
181
- * No changes.
228
+ *Alex Ghiculescu*
182
229
 
230
+ * Introduce ActiveSupport::Testing::ErrorReporterAssertions#capture_error_reports
183
231
 
184
- ## Rails 8.0.0.rc1 (October 19, 2024) ##
232
+ Captures all reported errors from within the block that match the given
233
+ error class.
185
234
 
186
- * Remove deprecated support to passing an array of strings to `ActiveSupport::Deprecation#warn`.
235
+ ```ruby
236
+ reports = capture_error_reports(IOError) do
237
+ Rails.error.report(IOError.new("Oops"))
238
+ Rails.error.report(IOError.new("Oh no"))
239
+ Rails.error.report(StandardError.new)
240
+ end
187
241
 
188
- *Rafael Mendonça França*
242
+ assert_equal 2, reports.size
243
+ assert_equal "Oops", reports.first.error.message
244
+ assert_equal "Oh no", reports.last.error.message
245
+ ```
189
246
 
190
- * Remove deprecated support to setting `attr_internal_naming_format` with a `@` prefix.
247
+ *Andrew Novoselac*
191
248
 
192
- *Rafael Mendonça França*
249
+ * Introduce ActiveSupport::ErrorReporter#add_middleware
193
250
 
194
- * Remove deprecated `ActiveSupport::ProxyObject`.
251
+ When reporting an error, the error context middleware will be called with the reported error
252
+ and base execution context. The stack may mutate the context hash. The mutated context will
253
+ then be passed to error subscribers. Middleware receives the same parameters as `ErrorReporter#report`.
195
254
 
196
- *Rafael Mendonça França*
255
+ *Andrew Novoselac*, *Sam Schmidt*
197
256
 
198
- * Don't execute i18n watcher on boot. It shouldn't catch any file changes initially,
199
- and unnecessarily slows down boot of applications with lots of translations.
257
+ * Change execution wrapping to report all exceptions, including `Exception`.
200
258
 
201
- *Gannon McGibbon*, *David Stosik*
259
+ If a more serious error like `SystemStackError` or `NoMemoryError` happens,
260
+ the error reporter should be able to report these kinds of exceptions.
202
261
 
203
- * Fix `ActiveSupport::HashWithIndifferentAccess#stringify_keys` to stringify all keys not just symbols.
262
+ *Gannon McGibbon*
204
263
 
205
- Previously:
264
+ * `ActiveSupport::Testing::Parallelization.before_fork_hook` allows declaration of callbacks that
265
+ are invoked immediately before forking test workers.
206
266
 
207
- ```ruby
208
- { 1 => 2 }.with_indifferent_access.stringify_keys[1] # => 2
209
- ```
267
+ *Mike Dalessio*
210
268
 
211
- After this change:
269
+ * Allow the `#freeze_time` testing helper to accept a date or time argument.
212
270
 
213
271
  ```ruby
214
- { 1 => 2 }.with_indifferent_access.stringify_keys["1"] # => 2
272
+ Time.current # => Sun, 09 Jul 2024 15:34:49 EST -05:00
273
+ freeze_time Time.current + 1.day
274
+ sleep 1
275
+ Time.current # => Mon, 10 Jul 2024 15:34:49 EST -05:00
215
276
  ```
216
277
 
217
- This change can be seen as a bug fix, but since it behaved like this for a very long time, we're deciding
218
- to not backport the fix and to make the change in a major release.
219
-
220
- *Jean Boussier*
278
+ *Joshua Young*
221
279
 
222
- ## Rails 8.0.0.beta1 (September 26, 2024) ##
280
+ * `ActiveSupport::JSON` now accepts options
223
281
 
224
- * Include options when instrumenting `ActiveSupport::Cache::Store#delete` and `ActiveSupport::Cache::Store#delete_multi`.
282
+ It is now possible to pass options to `ActiveSupport::JSON`:
283
+ ```ruby
284
+ ActiveSupport::JSON.decode('{"key": "value"}', symbolize_names: true) # => { key: "value" }
285
+ ```
225
286
 
226
- *Adam Renberg Tamm*
287
+ *matthaigh27*
227
288
 
228
- * Print test names when running `rails test -v` for parallel tests.
289
+ * `ActiveSupport::Testing::NotificationAssertions`'s `assert_notification` now matches against payload subsets by default.
229
290
 
230
- *John Hawthorn*, *Abeid Ahmed*
291
+ Previously the following assertion would fail due to excess key vals in the notification payload. Now with payload subset matching, it will pass.
231
292
 
232
- * Deprecate `Benchmark.ms` core extension.
293
+ ```ruby
294
+ assert_notification("post.submitted", title: "Cool Post") do
295
+ ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: "Cool Body")
296
+ end
297
+ ```
233
298
 
234
- The `benchmark` gem will become bundled in Ruby 3.5
299
+ Additionally, you can now persist a matched notification for more customized assertions.
235
300
 
236
- *Earlopain*
301
+ ```ruby
302
+ notification = assert_notification("post.submitted", title: "Cool Post") do
303
+ ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: Body.new("Cool Body"))
304
+ end
237
305
 
238
- * `ActiveSupport::TimeWithZone#inspect` now uses ISO 8601 style time like `Time#inspect`
306
+ assert_instance_of(Body, notification.payload[:body])
307
+ ```
239
308
 
240
- *John Hawthorn*
309
+ *Nicholas La Roux*
241
310
 
242
- * `ActiveSupport::ErrorReporter#report` now assigns a backtrace to unraised exceptions.
311
+ * Deprecate `String#mb_chars` and `ActiveSupport::Multibyte::Chars`.
243
312
 
244
- Previously reporting an un-raised exception would result in an error report without
245
- a backtrace. Now it automatically generates one.
313
+ These APIs are a relic of the Ruby 1.8 days when Ruby strings weren't encoding
314
+ aware. There is no legitimate reasons to need these APIs today.
246
315
 
247
316
  *Jean Boussier*
248
317
 
249
- * Add `escape_html_entities` option to `ActiveSupport::JSON.encode`.
318
+ * Deprecate `ActiveSupport::Configurable`
250
319
 
251
- This allows for overriding the global configuration found at
252
- `ActiveSupport.escape_html_entities_in_json` for specific calls to `to_json`.
320
+ *Sean Doyle*
253
321
 
254
- This should be usable from controllers in the following manner:
255
- ```ruby
256
- class MyController < ApplicationController
257
- def index
258
- render json: { hello: "world" }, escape_html_entities: false
259
- end
260
- end
261
- ```
322
+ * `nil.to_query("key")` now returns `key`.
262
323
 
263
- *Nigel Baillie*
324
+ Previously it would return `key=`, preventing round tripping with `Rack::Utils.parse_nested_query`.
264
325
 
265
- * Raise when using key which can't respond to `#to_sym` in `EncryptedConfiguration`.
326
+ *Erol Fornoles*
266
327
 
267
- As is the case when trying to use an Integer or Float as a key, which is unsupported.
328
+ * Avoid wrapping redis in a `ConnectionPool` when using `ActiveSupport::Cache::RedisCacheStore` if the `:redis`
329
+ option is already a `ConnectionPool`.
268
330
 
269
- *zzak*
331
+ *Joshua Young*
270
332
 
271
- * Deprecate addition and since between two `Time` and `ActiveSupport::TimeWithZone`.
333
+ * Alter `ERB::Util.tokenize` to return :PLAIN token with full input string when string doesn't contain ERB tags.
272
334
 
273
- Previously adding time instances together such as `10.days.ago + 10.days.ago` or `10.days.ago.since(10.days.ago)` produced a nonsensical future date. This behavior is deprecated and will be removed in Rails 8.1.
335
+ *Martin Emde*
274
336
 
275
- *Nick Schwaderer*
337
+ * Fix a bug in `ERB::Util.tokenize` that causes incorrect tokenization when ERB tags are preceded by multibyte characters.
276
338
 
277
- * Support rfc2822 format for Time#to_fs & Date#to_fs.
339
+ *Martin Emde*
278
340
 
279
- *Akshay Birajdar*
341
+ * Add `ActiveSupport::Testing::NotificationAssertions` module to help with testing `ActiveSupport::Notifications`.
280
342
 
281
- * Optimize load time for `Railtie#initialize_i18n`. Filter `I18n.load_path`s passed to the file watcher to only those
282
- under `Rails.root`. Previously the watcher would grab all available locales, including those in gems
283
- which do not require a watcher because they won't change.
343
+ *Nicholas La Roux*, *Yishu See*, *Sean Doyle*
284
344
 
285
- *Nick Schwaderer*
345
+ * `ActiveSupport::CurrentAttributes#attributes` now will return a new hash object on each call.
286
346
 
287
- * Add a `filter` option to `in_order_of` to prioritize certain values in the sorting without filtering the results
288
- by these values.
347
+ Previously, the same hash object was returned each time that method was called.
289
348
 
290
- *Igor Depolli*
349
+ *fatkodima*
291
350
 
292
- * Improve error message when using `assert_difference` or `assert_changes` with a
293
- proc by printing the proc's source code (MRI only).
351
+ * `ActiveSupport::JSON.encode` supports CIDR notation.
294
352
 
295
- *Richard Böhme*, *Jean Boussier*
353
+ Previously:
296
354
 
297
- * Add a new configuration value `:zone` for `ActiveSupport.to_time_preserves_timezone` and rename the previous `true` value to `:offset`. The new default value is `:zone`.
355
+ ```ruby
356
+ ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0\""
357
+ ```
298
358
 
299
- *Jason Kim*, *John Hawthorn*
359
+ After this change:
300
360
 
301
- * Align instrumentation `payload[:key]` in ActiveSupport::Cache to follow the same pattern, with namespaced and normalized keys.
361
+ ```ruby
362
+ ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0/24\""
363
+ ```
302
364
 
303
- *Frederik Erbs Spang Thomsen*
365
+ *Taketo Takashima*
304
366
 
305
- * Fix `travel_to` to set usec 0 when `with_usec` is `false` and the given argument String or DateTime.
367
+ * Make `ActiveSupport::FileUpdateChecker` faster when checking many file-extensions.
306
368
 
307
- *mopp*
369
+ *Jonathan del Strother*
308
370
 
309
- Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/activesupport/CHANGELOG.md) for previous changes.
371
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/activesupport/CHANGELOG.md) for previous changes.
@@ -56,6 +56,18 @@ module ActiveSupport
56
56
  end
57
57
  alias :filter :clean
58
58
 
59
+ # Given an array of Thread::Backtrace::Location objects, returns an array
60
+ # with the clean ones:
61
+ #
62
+ # clean_locations = backtrace_cleaner.clean_locations(caller_locations)
63
+ #
64
+ # Filters and silencers receive strings as usual. However, the +path+
65
+ # attributes of the locations in the returned array are the original,
66
+ # unfiltered ones, since locations are immutable.
67
+ def clean_locations(locations, kind = :silent)
68
+ locations.select { |location| clean_frame(location, kind) }
69
+ end
70
+
59
71
  # Returns the frame with all filters applied.
60
72
  # returns +nil+ if the frame was silenced.
61
73
  def clean_frame(frame, kind = :silent)
@@ -74,6 +86,65 @@ module ActiveSupport
74
86
  end
75
87
  end
76
88
 
89
+ # Thread.each_caller_location does not accept a start in Ruby < 3.4.
90
+ if Thread.method(:each_caller_location).arity == 0
91
+ # Returns the first clean frame of the caller's backtrace, or +nil+.
92
+ #
93
+ # Frames are strings.
94
+ def first_clean_frame(kind = :silent)
95
+ caller_location_skipped = false
96
+
97
+ Thread.each_caller_location do |location|
98
+ unless caller_location_skipped
99
+ caller_location_skipped = true
100
+ next
101
+ end
102
+
103
+ frame = clean_frame(location, kind)
104
+ return frame if frame
105
+ end
106
+ end
107
+
108
+ # Returns the first clean location of the caller's call stack, or +nil+.
109
+ #
110
+ # Locations are Thread::Backtrace::Location objects. Since they are
111
+ # immutable, their +path+ attributes are the original ones, but filters
112
+ # are applied internally so silencers can still rely on them.
113
+ def first_clean_location(kind = :silent)
114
+ caller_location_skipped = false
115
+
116
+ Thread.each_caller_location do |location|
117
+ unless caller_location_skipped
118
+ caller_location_skipped = true
119
+ next
120
+ end
121
+
122
+ return location if clean_frame(location, kind)
123
+ end
124
+ end
125
+ else
126
+ # Returns the first clean frame of the caller's backtrace, or +nil+.
127
+ #
128
+ # Frames are strings.
129
+ def first_clean_frame(kind = :silent)
130
+ Thread.each_caller_location(2) do |location|
131
+ frame = clean_frame(location, kind)
132
+ return frame if frame
133
+ end
134
+ end
135
+
136
+ # Returns the first clean location of the caller's call stack, or +nil+.
137
+ #
138
+ # Locations are Thread::Backtrace::Location objects. Since they are
139
+ # immutable, their +path+ attributes are the original ones, but filters
140
+ # are applied internally so silencers can still rely on them.
141
+ def first_clean_location(kind = :silent)
142
+ Thread.each_caller_location(2) do |location|
143
+ return location if clean_frame(location, kind)
144
+ end
145
+ end
146
+ end
147
+
77
148
  # Adds a filter from the block provided. Each line in the backtrace will be
78
149
  # mapped against this filter.
79
150
  #