activesupport 8.0.0 → 8.1.0

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +391 -67
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +72 -1
  5. data/lib/active_support/broadcast_logger.rb +61 -74
  6. data/lib/active_support/cache/file_store.rb +2 -2
  7. data/lib/active_support/cache/mem_cache_store.rb +26 -28
  8. data/lib/active_support/cache/memory_store.rb +5 -5
  9. data/lib/active_support/cache/null_store.rb +2 -2
  10. data/lib/active_support/cache/redis_cache_store.rb +37 -31
  11. data/lib/active_support/cache/strategy/local_cache.rb +72 -27
  12. data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
  13. data/lib/active_support/cache.rb +72 -9
  14. data/lib/active_support/callbacks.rb +27 -11
  15. data/lib/active_support/class_attribute.rb +15 -8
  16. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
  17. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  18. data/lib/active_support/configurable.rb +34 -0
  19. data/lib/active_support/continuous_integration.rb +145 -0
  20. data/lib/active_support/core_ext/array/conversions.rb +3 -3
  21. data/lib/active_support/core_ext/array.rb +7 -7
  22. data/lib/active_support/core_ext/benchmark.rb +4 -11
  23. data/lib/active_support/core_ext/big_decimal.rb +1 -1
  24. data/lib/active_support/core_ext/class/attribute.rb +20 -5
  25. data/lib/active_support/core_ext/class.rb +2 -2
  26. data/lib/active_support/core_ext/date.rb +5 -5
  27. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
  28. data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
  29. data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
  30. data/lib/active_support/core_ext/date_time.rb +5 -5
  31. data/lib/active_support/core_ext/digest.rb +1 -1
  32. data/lib/active_support/core_ext/enumerable.rb +17 -5
  33. data/lib/active_support/core_ext/erb/util.rb +5 -5
  34. data/lib/active_support/core_ext/file.rb +1 -1
  35. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
  36. data/lib/active_support/core_ext/hash.rb +8 -8
  37. data/lib/active_support/core_ext/integer.rb +3 -3
  38. data/lib/active_support/core_ext/kernel.rb +3 -3
  39. data/lib/active_support/core_ext/module/introspection.rb +3 -0
  40. data/lib/active_support/core_ext/module.rb +11 -11
  41. data/lib/active_support/core_ext/numeric.rb +3 -3
  42. data/lib/active_support/core_ext/object/json.rb +8 -1
  43. data/lib/active_support/core_ext/object/to_query.rb +7 -1
  44. data/lib/active_support/core_ext/object/try.rb +2 -2
  45. data/lib/active_support/core_ext/object.rb +13 -13
  46. data/lib/active_support/core_ext/pathname.rb +2 -2
  47. data/lib/active_support/core_ext/range/overlap.rb +3 -3
  48. data/lib/active_support/core_ext/range/sole.rb +17 -0
  49. data/lib/active_support/core_ext/range.rb +4 -4
  50. data/lib/active_support/core_ext/securerandom.rb +24 -8
  51. data/lib/active_support/core_ext/string/filters.rb +3 -3
  52. data/lib/active_support/core_ext/string/multibyte.rb +12 -3
  53. data/lib/active_support/core_ext/string/output_safety.rb +19 -12
  54. data/lib/active_support/core_ext/string.rb +13 -13
  55. data/lib/active_support/core_ext/symbol.rb +1 -1
  56. data/lib/active_support/core_ext/time/calculations.rb +0 -7
  57. data/lib/active_support/core_ext/time/compatibility.rb +2 -27
  58. data/lib/active_support/core_ext/time.rb +5 -5
  59. data/lib/active_support/core_ext.rb +1 -1
  60. data/lib/active_support/current_attributes/test_helper.rb +2 -2
  61. data/lib/active_support/current_attributes.rb +27 -17
  62. data/lib/active_support/dependencies/interlock.rb +11 -5
  63. data/lib/active_support/dependencies.rb +6 -1
  64. data/lib/active_support/deprecation/reporting.rb +4 -2
  65. data/lib/active_support/deprecation.rb +1 -1
  66. data/lib/active_support/editor.rb +70 -0
  67. data/lib/active_support/error_reporter.rb +61 -8
  68. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  69. data/lib/active_support/event_reporter.rb +592 -0
  70. data/lib/active_support/evented_file_update_checker.rb +5 -1
  71. data/lib/active_support/execution_context.rb +64 -7
  72. data/lib/active_support/execution_wrapper.rb +1 -1
  73. data/lib/active_support/file_update_checker.rb +8 -6
  74. data/lib/active_support/gem_version.rb +1 -1
  75. data/lib/active_support/gzip.rb +1 -0
  76. data/lib/active_support/hash_with_indifferent_access.rb +47 -24
  77. data/lib/active_support/i18n_railtie.rb +1 -2
  78. data/lib/active_support/inflector/inflections.rb +31 -15
  79. data/lib/active_support/inflector/transliterate.rb +6 -8
  80. data/lib/active_support/isolated_execution_state.rb +12 -15
  81. data/lib/active_support/json/decoding.rb +6 -4
  82. data/lib/active_support/json/encoding.rb +155 -19
  83. data/lib/active_support/lazy_load_hooks.rb +1 -1
  84. data/lib/active_support/log_subscriber.rb +2 -6
  85. data/lib/active_support/logger_thread_safe_level.rb +6 -3
  86. data/lib/active_support/message_encryptors.rb +54 -2
  87. data/lib/active_support/message_pack/extensions.rb +5 -0
  88. data/lib/active_support/message_verifier.rb +9 -0
  89. data/lib/active_support/message_verifiers.rb +57 -3
  90. data/lib/active_support/messages/rotation_coordinator.rb +9 -0
  91. data/lib/active_support/messages/rotator.rb +10 -0
  92. data/lib/active_support/multibyte/chars.rb +12 -2
  93. data/lib/active_support/multibyte.rb +4 -0
  94. data/lib/active_support/notifications/fanout.rb +64 -42
  95. data/lib/active_support/notifications/instrumenter.rb +1 -1
  96. data/lib/active_support/railtie.rb +32 -13
  97. data/lib/active_support/structured_event_subscriber.rb +99 -0
  98. data/lib/active_support/subscriber.rb +0 -5
  99. data/lib/active_support/syntax_error_proxy.rb +3 -0
  100. data/lib/active_support/test_case.rb +61 -6
  101. data/lib/active_support/testing/assertions.rb +34 -6
  102. data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
  103. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  104. data/lib/active_support/testing/notification_assertions.rb +92 -0
  105. data/lib/active_support/testing/parallelization/server.rb +15 -2
  106. data/lib/active_support/testing/parallelization/worker.rb +4 -2
  107. data/lib/active_support/testing/parallelization.rb +25 -1
  108. data/lib/active_support/testing/tests_without_assertions.rb +1 -1
  109. data/lib/active_support/testing/time_helpers.rb +7 -3
  110. data/lib/active_support/time_with_zone.rb +23 -23
  111. data/lib/active_support/values/time_zone.rb +8 -1
  112. data/lib/active_support/xml_mini.rb +3 -2
  113. data/lib/active_support.rb +20 -15
  114. metadata +27 -23
  115. data/lib/active_support/core_ext/range/each.rb +0 -24
  116. data/lib/active_support/testing/strict_warnings.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d43c6938627c736f544a0a9f0af6f8a538e8dd6c147ff51e368946c4d57d7c4
4
- data.tar.gz: 6e57c37c1735b475cb5a2d96c0af1ed0f6f2f2d41a776743bc97cc0b61e4b778
3
+ metadata.gz: 8e2e34de82e59790b784a08b2471fa7427da0b1642763bba5904ad1aa6ad45a8
4
+ data.tar.gz: fadad2b6a958becb7cc187251643463d43127d28af9098631050c4b368079dcc
5
5
  SHA512:
6
- metadata.gz: c01d045e73ab8eb2c3a3494180490bb5fa39a082343d5445593bd591333cd95cca84ad0d79668afe6603389ac675c8cbe3f98a0bb5612bfb5a3ec8d77fa26d9b
7
- data.tar.gz: b5a92add8986b7bb4f73a5e7c4ff82525dfcfb4a1ca0bcedb6364a338f88cb5b411595c1704d508d68ad0ed2df850788132a2270e4f1421d672b1394c49e8306
6
+ metadata.gz: 1d545e02442de9422d3b62f261fdba69bbf9aaa95e2f8138a62493dd090397a163841044b5fb538a1e1be2ab70a464e51a7eb3ee56f12f778ecb7cc681ea6dab
7
+ data.tar.gz: d6de04f518b4802721210693b496f28ac80d16f3d7aa78bedeb007c4c850d0084d532a8b696b079f41412e274e5e29ff3644b95adfbf861f6852cfc0675ac516
data/CHANGELOG.md CHANGED
@@ -1,136 +1,460 @@
1
- ## Rails 8.0.0 (November 07, 2024) ##
1
+ ## Rails 8.1.0 (October 22, 2025) ##
2
2
 
3
- * No changes.
3
+ * Remove deprecated passing a Time object to `Time#since`.
4
4
 
5
+ *Rafael Mendonça França*
5
6
 
6
- ## Rails 8.0.0.rc2 (October 30, 2024) ##
7
+ * Remove deprecated `Benchmark.ms` method. It is now defined in the `benchmark` gem.
7
8
 
8
- * No changes.
9
+ *Rafael Mendonça França*
9
10
 
11
+ * Remove deprecated addition for `Time` instances with `ActiveSupport::TimeWithZone`.
10
12
 
11
- ## Rails 8.0.0.rc1 (October 19, 2024) ##
13
+ *Rafael Mendonça França*
12
14
 
13
- * Remove deprecated support to passing an array of strings to `ActiveSupport::Deprecation#warn`.
15
+ * Remove deprecated support for `to_time` to preserve the system local time. It will now always preserve the receiver
16
+ timezone.
14
17
 
15
18
  *Rafael Mendonça França*
16
19
 
17
- * Remove deprecated support to setting `attr_internal_naming_format` with a `@` prefix.
20
+ * Deprecate `config.active_support.to_time_preserves_timezone`.
18
21
 
19
22
  *Rafael Mendonça França*
20
23
 
21
- * Remove deprecated `ActiveSupport::ProxyObject`.
24
+ * Standardize event name formatting in `assert_event_reported` error messages.
22
25
 
23
- *Rafael Mendonça França*
26
+ The event name in failure messages now uses `.inspect` (e.g., `name: "user.created"`)
27
+ to match `assert_events_reported` and provide type clarity between strings and symbols.
28
+ This only affects tests that assert on the failure message format itself.
24
29
 
25
- * Don't execute i18n watcher on boot. It shouldn't catch any file changes initially,
26
- and unnecessarily slows down boot of applications with lots of translations.
30
+ *George Ma*
27
31
 
28
- *Gannon McGibbon*, *David Stosik*
32
+ * Fix `Enumerable#sole` to return the full tuple instead of just the first element of the tuple.
29
33
 
30
- * Fix `ActiveSupport::HashWithIndifferentAccess#stringify_keys` to stringify all keys not just symbols.
34
+ *Olivier Bellone*
31
35
 
32
- Previously:
36
+ * Fix parallel tests hanging when worker processes die abruptly.
37
+
38
+ Previously, if a worker process was killed (e.g., OOM killed, `kill -9`) during parallel
39
+ test execution, the test suite would hang forever waiting for the dead worker.
40
+
41
+ *Joshua Young*
42
+
43
+ * Add `config.active_support.escape_js_separators_in_json`.
44
+
45
+ Introduce a new framework default to skip escaping LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029) in JSON.
46
+
47
+ Historically these characters were not valid inside JavaScript literal strings but that changed in ECMAScript 2019.
48
+ As such it's no longer a concern in modern browsers: https://caniuse.com/mdn-javascript_builtins_json_json_superset.
49
+
50
+ *Étienne Barrié*, *Jean Boussier*
51
+
52
+ * Fix `NameError` when `class_attribute` is defined on instance singleton classes.
53
+
54
+ Previously, calling `class_attribute` on an instance's singleton class would raise
55
+ a `NameError` when accessing the attribute through the instance.
33
56
 
34
57
  ```ruby
35
- { 1 => 2 }.with_indifferent_access.stringify_keys[1] # => 2
58
+ object = MyClass.new
59
+ object.singleton_class.class_attribute :foo, default: "bar"
60
+ object.foo # previously raised NameError, now returns "bar"
36
61
  ```
37
62
 
38
- After this change:
63
+ *Joshua Young*
64
+
65
+ * Introduce `ActiveSupport::Testing::EventReporterAssertions#with_debug_event_reporting`
66
+ to enable event reporter debug mode in tests.
67
+
68
+ The previous way to enable debug mode is by using `#with_debug` on the
69
+ event reporter itself, which is too verbose. This new helper will help
70
+ clear up any confusion on how to test debug events.
71
+
72
+ *Gannon McGibbon*
73
+
74
+ * Add `ActiveSupport::StructuredEventSubscriber` for consuming notifications and
75
+ emitting structured event logs. Events may be emitted with the `#emit_event`
76
+ or `#emit_debug_event` methods.
39
77
 
40
78
  ```ruby
41
- { 1 => 2 }.with_indifferent_access.stringify_keys["1"] # => 2
79
+ class MyStructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber
80
+ def notification(event)
81
+ emit_event("my.notification", data: 1)
82
+ end
83
+ end
42
84
  ```
43
85
 
44
- This change can be seen as a bug fix, but since it behaved like this for a very long time, we're deciding
45
- to not backport the fix and to make the change in a major release.
86
+ *Adrianna Chang*
46
87
 
47
- *Jean Boussier*
88
+ * `ActiveSupport::FileUpdateChecker` does not depend on `Time.now` to prevent unecessary reloads with time travel test helpers
48
89
 
49
- ## Rails 8.0.0.beta1 (September 26, 2024) ##
90
+ *Jan Grodowski*
50
91
 
51
- * Include options when instrumenting `ActiveSupport::Cache::Store#delete` and `ActiveSupport::Cache::Store#delete_multi`.
92
+ * Add `ActiveSupport::Cache::Store#namespace=` and `#namespace`.
52
93
 
53
- *Adam Renberg Tamm*
94
+ Can be used as an alternative to `Store#clear` in some situations such as parallel
95
+ testing.
54
96
 
55
- * Print test names when running `rails test -v` for parallel tests.
97
+ *Nick Schwaderer*
98
+
99
+ * Create `parallel_worker_id` helper for running parallel tests. This allows users to
100
+ know which worker they are currently running in.
101
+
102
+ *Nick Schwaderer*
103
+
104
+ * Make the cache of `ActiveSupport::Cache::Strategy::LocalCache::Middleware` updatable.
56
105
 
57
- *John Hawthorn*, *Abeid Ahmed*
106
+ If the cache client at `Rails.cache` of a booted application changes, the corresponding
107
+ mounted middleware needs to update in order for request-local caches to be setup properly.
108
+ Otherwise, redundant cache operations will erroneously hit the datastore.
58
109
 
59
- * Deprecate `Benchmark.ms` core extension.
110
+ *Gannon McGibbon*
60
111
 
61
- The `benchmark` gem will become bundled in Ruby 3.5
112
+ * Add `assert_events_reported` test helper for `ActiveSupport::EventReporter`.
62
113
 
63
- *Earlopain*
114
+ This new assertion allows testing multiple events in a single block, regardless of order:
64
115
 
65
- * `ActiveSupport::TimeWithZone#inspect` now uses ISO 8601 style time like `Time#inspect`
116
+ ```ruby
117
+ assert_events_reported([
118
+ { name: "user.created", payload: { id: 123 } },
119
+ { name: "email.sent", payload: { to: "user@example.com" } }
120
+ ]) do
121
+ create_user_and_send_welcome_email
122
+ end
123
+ ```
66
124
 
67
- *John Hawthorn*
125
+ *George Ma*
68
126
 
69
- * `ActiveSupport::ErrorReporter#report` now assigns a backtrace to unraised exceptions.
127
+ * Add `ActiveSupport::TimeZone#standard_name` method.
70
128
 
71
- Previously reporting an un-raised exception would result in an error report without
72
- a backtrace. Now it automatically generates one.
129
+ ``` ruby
130
+ zone = ActiveSupport::TimeZone['Hawaii']
131
+ # Old way
132
+ ActiveSupport::TimeZone::MAPPING[zone.name]
133
+ # New way
134
+ zone.standard_name # => 'Pacific/Honolulu'
135
+ ```
73
136
 
74
- *Jean Boussier*
137
+ *Bogdan Gusiev*
75
138
 
76
- * Add `escape_html_entities` option to `ActiveSupport::JSON.encode`.
139
+ * Add Structured Event Reporter, accessible via `Rails.event`.
77
140
 
78
- This allows for overriding the global configuration found at
79
- `ActiveSupport.escape_html_entities_in_json` for specific calls to `to_json`.
141
+ The Event Reporter provides a unified interface for producing structured events in Rails
142
+ applications:
80
143
 
81
- This should be usable from controllers in the following manner:
82
144
  ```ruby
83
- class MyController < ApplicationController
84
- def index
85
- render json: { hello: "world" }, escape_html_entities: false
145
+ Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")
146
+ ```
147
+
148
+ It supports adding tags to events:
149
+
150
+ ```ruby
151
+ Rails.event.tagged("graphql") do
152
+ # Event includes tags: { graphql: true }
153
+ Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")
154
+ end
155
+ ```
156
+
157
+ As well as context:
158
+ ```ruby
159
+ # All events will contain context: {request_id: "abc123", shop_id: 456}
160
+ Rails.event.set_context(request_id: "abc123", shop_id: 456)
161
+ ```
162
+
163
+ Events are emitted to subscribers. Applications register subscribers to
164
+ control how events are serialized and emitted. Subscribers must implement
165
+ an `#emit` method, which receives the event hash:
166
+
167
+ ```ruby
168
+ class LogSubscriber
169
+ def emit(event)
170
+ payload = event[:payload].map { |key, value| "#{key}=#{value}" }.join(" ")
171
+ source_location = event[:source_location]
172
+ log = "[#{event[:name]}] #{payload} at #{source_location[:filepath]}:#{source_location[:lineno]}"
173
+ Rails.logger.info(log)
86
174
  end
87
175
  end
88
176
  ```
89
177
 
90
- *Nigel Baillie*
178
+ *Adrianna Chang*
91
179
 
92
- * Raise when using key which can't respond to `#to_sym` in `EncryptedConfiguration`.
180
+ * Make `ActiveSupport::Logger` `#freeze`-friendly.
93
181
 
94
- As is the case when trying to use an Integer or Float as a key, which is unsupported.
182
+ *Joshua Young*
95
183
 
96
- *zzak*
184
+ * Make `ActiveSupport::Gzip.compress` deterministic based on input.
97
185
 
98
- * Deprecate addition and since between two `Time` and `ActiveSupport::TimeWithZone`.
186
+ `ActiveSupport::Gzip.compress` used to include a timestamp in the output,
187
+ causing consecutive calls with the same input data to have different output
188
+ if called during different seconds. It now always sets the timestamp to `0`
189
+ so that the output is identical for any given input.
99
190
 
100
- 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.
191
+ *Rob Brackett*
101
192
 
102
- *Nick Schwaderer*
193
+ * Given an array of `Thread::Backtrace::Location` objects, the new method
194
+ `ActiveSupport::BacktraceCleaner#clean_locations` returns an array with the
195
+ clean ones:
196
+
197
+ ```ruby
198
+ clean_locations = backtrace_cleaner.clean_locations(caller_locations)
199
+ ```
103
200
 
104
- * Support rfc2822 format for Time#to_fs & Date#to_fs.
201
+ Filters and silencers receive strings as usual. However, the `path`
202
+ attributes of the locations in the returned array are the original,
203
+ unfiltered ones, since locations are immutable.
105
204
 
106
- *Akshay Birajdar*
205
+ *Xavier Noria*
107
206
 
108
- * Optimize load time for `Railtie#initialize_i18n`. Filter `I18n.load_path`s passed to the file watcher to only those
109
- under `Rails.root`. Previously the watcher would grab all available locales, including those in gems
110
- which do not require a watcher because they won't change.
207
+ * Improve `CurrentAttributes` and `ExecutionContext` state managment in test cases.
111
208
 
112
- *Nick Schwaderer*
209
+ Previously these two global state would be entirely cleared out whenever calling
210
+ into code that is wrapped by the Rails executor, typically Action Controller or
211
+ Active Job helpers:
212
+
213
+ ```ruby
214
+ test "#index works" do
215
+ CurrentUser.id = 42
216
+ get :index
217
+ CurrentUser.id == nil
218
+ end
219
+ ```
220
+
221
+ Now re-entering the executor properly save and restore that state.
222
+
223
+ *Jean Boussier*
224
+
225
+ * The new method `ActiveSupport::BacktraceCleaner#first_clean_location`
226
+ returns the first clean location of the caller's call stack, or `nil`.
227
+ Locations are `Thread::Backtrace::Location` objects. Useful when you want to
228
+ report the application-level location where something happened as an object.
229
+
230
+ *Xavier Noria*
231
+
232
+ * FileUpdateChecker and EventedFileUpdateChecker ignore changes in Gem.path now.
233
+
234
+ *Ermolaev Andrey*, *zzak*
235
+
236
+ * The new method `ActiveSupport::BacktraceCleaner#first_clean_frame` returns
237
+ the first clean frame of the caller's backtrace, or `nil`. Useful when you
238
+ want to report the application-level frame where something happened as a
239
+ string.
240
+
241
+ *Xavier Noria*
113
242
 
114
- * Add a `filter` option to `in_order_of` to prioritize certain values in the sorting without filtering the results
115
- by these values.
243
+ * Always clear `CurrentAttributes` instances.
116
244
 
117
- *Igor Depolli*
245
+ Previously `CurrentAttributes` instance would be reset at the end of requests.
246
+ Meaning its attributes would be re-initialized.
247
+
248
+ This is problematic because it assume these objects don't hold any state
249
+ other than their declared attribute, which isn't always the case, and
250
+ can lead to state leak across request.
251
+
252
+ Now `CurrentAttributes` instances are abandoned at the end of a request,
253
+ and a new instance is created at the start of the next request.
254
+
255
+ *Jean Boussier*, *Janko Marohnić*
256
+
257
+ * Add public API for `before_fork_hook` in parallel testing.
258
+
259
+ Introduces a public API for calling the before fork hooks implemented by parallel testing.
260
+
261
+ ```ruby
262
+ parallelize_before_fork do
263
+ # perform an action before test processes are forked
264
+ end
265
+ ```
266
+
267
+ *Eileen M. Uchitelle*
268
+
269
+ * Implement ability to skip creating parallel testing databases.
270
+
271
+ With parallel testing, Rails will create a database per process. If this isn't
272
+ desirable or you would like to implement databases handling on your own, you can
273
+ now turn off this default behavior.
274
+
275
+ To skip creating a database per process, you can change it via the
276
+ `parallelize` method:
277
+
278
+ ```ruby
279
+ parallelize(workers: 10, parallelize_databases: false)
280
+ ```
281
+
282
+ or via the application configuration:
283
+
284
+ ```ruby
285
+ config.active_support.parallelize_databases = false
286
+ ```
118
287
 
119
- * Improve error message when using `assert_difference` or `assert_changes` with a
120
- proc by printing the proc's source code (MRI only).
288
+ *Eileen M. Uchitelle*
121
289
 
122
- *Richard Böhme*, *Jean Boussier*
290
+ * Allow to configure maximum cache key sizes
123
291
 
124
- * 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`.
292
+ When the key exceeds the configured limit (250 bytes by default), it will be truncated and
293
+ the digest of the rest of the key appended to it.
125
294
 
126
- *Jason Kim*, *John Hawthorn*
295
+ Note that previously `ActiveSupport::Cache::RedisCacheStore` allowed up to 1kb cache keys before
296
+ truncation, which is now reduced to 250 bytes.
127
297
 
128
- * Align instrumentation `payload[:key]` in ActiveSupport::Cache to follow the same pattern, with namespaced and normalized keys.
298
+ ```ruby
299
+ config.cache_store = :redis_cache_store, { max_key_size: 64 }
300
+ ```
301
+
302
+ *fatkodima*
303
+
304
+ * Use `UNLINK` command instead of `DEL` in `ActiveSupport::Cache::RedisCacheStore` for non-blocking deletion.
305
+
306
+ *Aron Roh*
307
+
308
+ * Add `Cache#read_counter` and `Cache#write_counter`
309
+
310
+ ```ruby
311
+ Rails.cache.write_counter("foo", 1)
312
+ Rails.cache.read_counter("foo") # => 1
313
+ Rails.cache.increment("foo")
314
+ Rails.cache.read_counter("foo") # => 2
315
+ ```
316
+
317
+ *Alex Ghiculescu*
318
+
319
+ * Introduce ActiveSupport::Testing::ErrorReporterAssertions#capture_error_reports
320
+
321
+ Captures all reported errors from within the block that match the given
322
+ error class.
323
+
324
+ ```ruby
325
+ reports = capture_error_reports(IOError) do
326
+ Rails.error.report(IOError.new("Oops"))
327
+ Rails.error.report(IOError.new("Oh no"))
328
+ Rails.error.report(StandardError.new)
329
+ end
330
+
331
+ assert_equal 2, reports.size
332
+ assert_equal "Oops", reports.first.error.message
333
+ assert_equal "Oh no", reports.last.error.message
334
+ ```
335
+
336
+ *Andrew Novoselac*
337
+
338
+ * Introduce ActiveSupport::ErrorReporter#add_middleware
339
+
340
+ When reporting an error, the error context middleware will be called with the reported error
341
+ and base execution context. The stack may mutate the context hash. The mutated context will
342
+ then be passed to error subscribers. Middleware receives the same parameters as `ErrorReporter#report`.
343
+
344
+ *Andrew Novoselac*, *Sam Schmidt*
345
+
346
+ * Change execution wrapping to report all exceptions, including `Exception`.
347
+
348
+ If a more serious error like `SystemStackError` or `NoMemoryError` happens,
349
+ the error reporter should be able to report these kinds of exceptions.
350
+
351
+ *Gannon McGibbon*
352
+
353
+ * `ActiveSupport::Testing::Parallelization.before_fork_hook` allows declaration of callbacks that
354
+ are invoked immediately before forking test workers.
355
+
356
+ *Mike Dalessio*
357
+
358
+ * Allow the `#freeze_time` testing helper to accept a date or time argument.
359
+
360
+ ```ruby
361
+ Time.current # => Sun, 09 Jul 2024 15:34:49 EST -05:00
362
+ freeze_time Time.current + 1.day
363
+ sleep 1
364
+ Time.current # => Mon, 10 Jul 2024 15:34:49 EST -05:00
365
+ ```
366
+
367
+ *Joshua Young*
368
+
369
+ * `ActiveSupport::JSON` now accepts options
370
+
371
+ It is now possible to pass options to `ActiveSupport::JSON`:
372
+ ```ruby
373
+ ActiveSupport::JSON.decode('{"key": "value"}', symbolize_names: true) # => { key: "value" }
374
+ ```
375
+
376
+ *matthaigh27*
377
+
378
+ * `ActiveSupport::Testing::NotificationAssertions`'s `assert_notification` now matches against payload subsets by default.
379
+
380
+ Previously the following assertion would fail due to excess key vals in the notification payload. Now with payload subset matching, it will pass.
381
+
382
+ ```ruby
383
+ assert_notification("post.submitted", title: "Cool Post") do
384
+ ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: "Cool Body")
385
+ end
386
+ ```
387
+
388
+ Additionally, you can now persist a matched notification for more customized assertions.
389
+
390
+ ```ruby
391
+ notification = assert_notification("post.submitted", title: "Cool Post") do
392
+ ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: Body.new("Cool Body"))
393
+ end
394
+
395
+ assert_instance_of(Body, notification.payload[:body])
396
+ ```
397
+
398
+ *Nicholas La Roux*
399
+
400
+ * Deprecate `String#mb_chars` and `ActiveSupport::Multibyte::Chars`.
401
+
402
+ These APIs are a relic of the Ruby 1.8 days when Ruby strings weren't encoding
403
+ aware. There is no legitimate reasons to need these APIs today.
404
+
405
+ *Jean Boussier*
406
+
407
+ * Deprecate `ActiveSupport::Configurable`
408
+
409
+ *Sean Doyle*
410
+
411
+ * `nil.to_query("key")` now returns `key`.
412
+
413
+ Previously it would return `key=`, preventing round tripping with `Rack::Utils.parse_nested_query`.
414
+
415
+ *Erol Fornoles*
416
+
417
+ * Avoid wrapping redis in a `ConnectionPool` when using `ActiveSupport::Cache::RedisCacheStore` if the `:redis`
418
+ option is already a `ConnectionPool`.
419
+
420
+ *Joshua Young*
421
+
422
+ * Alter `ERB::Util.tokenize` to return :PLAIN token with full input string when string doesn't contain ERB tags.
423
+
424
+ *Martin Emde*
425
+
426
+ * Fix a bug in `ERB::Util.tokenize` that causes incorrect tokenization when ERB tags are preceded by multibyte characters.
427
+
428
+ *Martin Emde*
429
+
430
+ * Add `ActiveSupport::Testing::NotificationAssertions` module to help with testing `ActiveSupport::Notifications`.
431
+
432
+ *Nicholas La Roux*, *Yishu See*, *Sean Doyle*
433
+
434
+ * `ActiveSupport::CurrentAttributes#attributes` now will return a new hash object on each call.
435
+
436
+ Previously, the same hash object was returned each time that method was called.
437
+
438
+ *fatkodima*
439
+
440
+ * `ActiveSupport::JSON.encode` supports CIDR notation.
441
+
442
+ Previously:
443
+
444
+ ```ruby
445
+ ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0\""
446
+ ```
447
+
448
+ After this change:
449
+
450
+ ```ruby
451
+ ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0/24\""
452
+ ```
129
453
 
130
- *Frederik Erbs Spang Thomsen*
454
+ *Taketo Takashima*
131
455
 
132
- * Fix `travel_to` to set usec 0 when `with_usec` is `false` and the given argument String or DateTime.
456
+ * Make `ActiveSupport::FileUpdateChecker` faster when checking many file-extensions.
133
457
 
134
- *mopp*
458
+ *Jonathan del Strother*
135
459
 
136
- Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/activesupport/CHANGELOG.md) for previous changes.
460
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/activesupport/CHANGELOG.md) for previous changes.
data/README.rdoc CHANGED
@@ -35,6 +35,6 @@ Bug reports for the Ruby on \Rails project can be filed here:
35
35
 
36
36
  * https://github.com/rails/rails/issues
37
37
 
38
- Feature requests should be discussed on the rails-core mailing list here:
38
+ Feature requests should be discussed on the rubyonrails-core forum here:
39
39
 
40
40
  * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -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,12 +86,71 @@ 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
  #
80
151
  # # Will turn "/my/rails/root/app/models/person.rb" into "app/models/person.rb"
81
152
  # root = "#{Rails.root}/"
82
- # backtrace_cleaner.add_filter { |line| line.start_with?(root) ? line.from(root.size) : line }
153
+ # backtrace_cleaner.add_filter { |line| line.delete_prefix(root) }
83
154
  def add_filter(&block)
84
155
  @filters << block
85
156
  end