activesupport 7.1.1 → 7.1.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 +4 -4
- data/CHANGELOG.md +67 -0
- data/lib/active_support/broadcast_logger.rb +8 -0
- data/lib/active_support/cache/entry.rb +7 -1
- data/lib/active_support/cache/file_store.rb +1 -1
- data/lib/active_support/cache/mem_cache_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +5 -2
- data/lib/active_support/cache.rb +19 -2
- data/lib/active_support/core_ext/date/conversions.rb +1 -1
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/inflector/methods.rb +2 -2
- data/lib/active_support/log_subscriber.rb +8 -2
- data/lib/active_support/messages/metadata.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +25 -19
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/ordered_options.rb +2 -2
- data/lib/active_support/testing/strict_warnings.rb +1 -0
- data/lib/active_support/testing/time_helpers.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6db71966858e675d32617069b0df8dc17b1c5dfe8123c87ae96a28fdb6e2f5e6
|
4
|
+
data.tar.gz: 81ffe410567130147cd0c6f74943d40404a4031b2cf30f12bfaa2ee698cd5a57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99a9131ff9f97e739719621df9ba0a33d3b2fad9b1315397382235f29d33ee130f701d0c0ed767eacf01ccb31607eb26d7f5bb95f37ad86ac57f18817cd9b253
|
7
|
+
data.tar.gz: ffa6a0ffe90b88c87f65d85ddb32390d20f8c34ab2517f797c34d325839cbf434a0202650cdd54f118bee9a299cf478f83af4222c313f2746e267bbd19003914
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,70 @@
|
|
1
|
+
## Rails 7.1.2 (November 10, 2023) ##
|
2
|
+
|
3
|
+
* Fix `:expires_in` option for `RedisCacheStore#write_multi`.
|
4
|
+
|
5
|
+
*fatkodima*
|
6
|
+
|
7
|
+
* Fix deserialization of non-string "purpose" field in Message serializer
|
8
|
+
|
9
|
+
*Jacopo Beschi*
|
10
|
+
|
11
|
+
* Prevent global cache options being overwritten when setting dynamic options
|
12
|
+
inside a `ActiveSupport::Cache::Store#fetch` block.
|
13
|
+
|
14
|
+
*Yasha Krasnou*
|
15
|
+
|
16
|
+
* Fix missing `require` resulting in `NoMethodError` when running
|
17
|
+
`bin/rails secrets:show` or `bin/rails secrets:edit`.
|
18
|
+
|
19
|
+
*Stephen Ierodiaconou*
|
20
|
+
|
21
|
+
* Ensure `{down,up}case_first` returns non-frozen string.
|
22
|
+
|
23
|
+
*Jonathan Hefner*
|
24
|
+
|
25
|
+
* Fix `#to_fs(:human_size)` to correctly work with negative numbers.
|
26
|
+
|
27
|
+
*Earlopain*
|
28
|
+
|
29
|
+
* Fix `BroadcastLogger#dup` so that it duplicates the logger's `broadcasts`.
|
30
|
+
|
31
|
+
*Andrew Novoselac*
|
32
|
+
|
33
|
+
* Fix issue where `bootstrap.rb` overwrites the `level` of a `BroadcastLogger`'s `broadcasts`.
|
34
|
+
|
35
|
+
*Andrew Novoselac*
|
36
|
+
|
37
|
+
* Fix `ActiveSupport::Cache` to handle outdated Marshal payload from Rails 6.1 format.
|
38
|
+
|
39
|
+
Active Support's Cache is supposed to treat a Marshal payload that can no longer be
|
40
|
+
deserialized as a cache miss. It fail to do so for compressed payload in the Rails 6.1
|
41
|
+
legacy format.
|
42
|
+
|
43
|
+
*Jean Boussier*
|
44
|
+
|
45
|
+
* Fix `OrderedOptions#dig` for array indexes.
|
46
|
+
|
47
|
+
*fatkodima*
|
48
|
+
|
49
|
+
* Fix time travel helpers to work when nested using with separate classes.
|
50
|
+
|
51
|
+
*fatkodima*
|
52
|
+
|
53
|
+
* Fix `delete_matched` for file cache store to work with keys longer than the
|
54
|
+
max filename size.
|
55
|
+
|
56
|
+
*fatkodima* and *Jonathan Hefner*
|
57
|
+
|
58
|
+
* Fix compatibility with the `semantic_logger` gem.
|
59
|
+
|
60
|
+
The `semantic_logger` gem doesn't behave exactly like stdlib logger in that
|
61
|
+
`SemanticLogger#level` returns a Symbol while stdlib `Logger#level` returns an Integer.
|
62
|
+
|
63
|
+
This caused the various `LogSubscriber` classes in Rails to break when assigned a
|
64
|
+
`SemanticLogger` instance.
|
65
|
+
|
66
|
+
*Jean Boussier*, *ojab*
|
67
|
+
|
1
68
|
## Rails 7.1.1 (October 11, 2023) ##
|
2
69
|
|
3
70
|
* Add support for keyword arguments when delegating calls to custom loggers from `ActiveSupport::BroadcastLogger`.
|
@@ -218,6 +218,14 @@ module ActiveSupport
|
|
218
218
|
dispatch { |logger| logger.fatal! }
|
219
219
|
end
|
220
220
|
|
221
|
+
def initialize_copy(other)
|
222
|
+
@broadcasts = []
|
223
|
+
@progname = other.progname.dup
|
224
|
+
@formatter = other.formatter.dup
|
225
|
+
|
226
|
+
broadcast_to(*other.broadcasts.map(&:dup))
|
227
|
+
end
|
228
|
+
|
221
229
|
private
|
222
230
|
def dispatch(&block)
|
223
231
|
@broadcasts.each { |logger| block.call(logger) }
|
@@ -121,7 +121,13 @@ module ActiveSupport
|
|
121
121
|
|
122
122
|
private
|
123
123
|
def uncompress(value)
|
124
|
-
|
124
|
+
marshal_load(Zlib::Inflate.inflate(value))
|
125
|
+
end
|
126
|
+
|
127
|
+
def marshal_load(payload)
|
128
|
+
Marshal.load(payload)
|
129
|
+
rescue ArgumentError => error
|
130
|
+
raise Cache::DeserializationError, error.message
|
125
131
|
end
|
126
132
|
end
|
127
133
|
end
|
@@ -176,7 +176,7 @@ module ActiveSupport
|
|
176
176
|
|
177
177
|
# Translate a file path into a key.
|
178
178
|
def file_path_key(path)
|
179
|
-
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
|
179
|
+
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last.delete(File::SEPARATOR)
|
180
180
|
URI.decode_www_form_component(fname, Encoding::UTF_8)
|
181
181
|
end
|
182
182
|
|
@@ -270,14 +270,22 @@ module ActiveSupport
|
|
270
270
|
def read_multi_entries(names, **options)
|
271
271
|
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
272
272
|
|
273
|
-
raw_values =
|
273
|
+
raw_values = begin
|
274
|
+
@data.with { |c| c.get_multi(keys_to_names.keys) }
|
275
|
+
rescue Dalli::UnmarshalError
|
276
|
+
{}
|
277
|
+
end
|
278
|
+
|
274
279
|
values = {}
|
275
280
|
|
276
281
|
raw_values.each do |key, value|
|
277
282
|
entry = deserialize_entry(value, raw: options[:raw])
|
278
283
|
|
279
284
|
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
280
|
-
|
285
|
+
begin
|
286
|
+
values[keys_to_names[key]] = entry.value
|
287
|
+
rescue DeserializationError
|
288
|
+
end
|
281
289
|
end
|
282
290
|
end
|
283
291
|
|
@@ -332,7 +332,10 @@ module ActiveSupport
|
|
332
332
|
if value
|
333
333
|
entry = deserialize_entry(value, raw: raw)
|
334
334
|
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(name, options))
|
335
|
-
|
335
|
+
begin
|
336
|
+
results[name] = entry.value
|
337
|
+
rescue DeserializationError
|
338
|
+
end
|
336
339
|
end
|
337
340
|
end
|
338
341
|
end
|
@@ -383,7 +386,7 @@ module ActiveSupport
|
|
383
386
|
end
|
384
387
|
|
385
388
|
# Nonstandard store provider API to write multiple values at once.
|
386
|
-
def write_multi_entries(entries,
|
389
|
+
def write_multi_entries(entries, **options)
|
387
390
|
return if entries.empty?
|
388
391
|
|
389
392
|
failsafe :write_multi_entries do
|
data/lib/active_support/cache.rb
CHANGED
@@ -459,7 +459,17 @@ module ActiveSupport
|
|
459
459
|
instrument(:read, name, options) do |payload|
|
460
460
|
cached_entry = read_entry(key, **options, event: payload)
|
461
461
|
entry = handle_expired_entry(cached_entry, key, options)
|
462
|
-
|
462
|
+
if entry
|
463
|
+
if entry.mismatched?(normalize_version(name, options))
|
464
|
+
entry = nil
|
465
|
+
else
|
466
|
+
begin
|
467
|
+
entry.value
|
468
|
+
rescue DeserializationError
|
469
|
+
entry = nil
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
463
473
|
payload[:super_operation] = :fetch if payload
|
464
474
|
payload[:hit] = !!entry if payload
|
465
475
|
end
|
@@ -511,7 +521,12 @@ module ActiveSupport
|
|
511
521
|
nil
|
512
522
|
else
|
513
523
|
payload[:hit] = true if payload
|
514
|
-
|
524
|
+
begin
|
525
|
+
entry.value
|
526
|
+
rescue DeserializationError
|
527
|
+
payload[:hit] = false
|
528
|
+
nil
|
529
|
+
end
|
515
530
|
end
|
516
531
|
else
|
517
532
|
payload[:hit] = false if payload
|
@@ -1038,6 +1053,8 @@ module ActiveSupport
|
|
1038
1053
|
end
|
1039
1054
|
|
1040
1055
|
def save_block_result_to_cache(name, options)
|
1056
|
+
options = options.dup
|
1057
|
+
|
1041
1058
|
result = instrument(:generate, name, options) do
|
1042
1059
|
yield(name, WriteOptions.new(options))
|
1043
1060
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/concern"
|
4
4
|
|
5
5
|
class Module
|
6
|
-
#
|
6
|
+
# == Bite-sized separation of concerns
|
7
7
|
#
|
8
8
|
# We often find ourselves with a medium-sized chunk of behavior that we'd
|
9
9
|
# like to extract, but only mix in to a single class.
|
@@ -18,9 +18,9 @@ class Module
|
|
18
18
|
# with a comment, as a least-bad alternative. Using modules in separate files
|
19
19
|
# means tedious sifting to get a big-picture view.
|
20
20
|
#
|
21
|
-
#
|
21
|
+
# == Dissatisfying ways to separate small concerns
|
22
22
|
#
|
23
|
-
#
|
23
|
+
# === Using comments:
|
24
24
|
#
|
25
25
|
# class Todo < ApplicationRecord
|
26
26
|
# # Other todo implementation
|
@@ -37,7 +37,7 @@ class Module
|
|
37
37
|
# end
|
38
38
|
# end
|
39
39
|
#
|
40
|
-
#
|
40
|
+
# === With an inline module:
|
41
41
|
#
|
42
42
|
# Noisy syntax.
|
43
43
|
#
|
@@ -61,7 +61,7 @@ class Module
|
|
61
61
|
# include EventTracking
|
62
62
|
# end
|
63
63
|
#
|
64
|
-
#
|
64
|
+
# === Mix-in noise exiled to its own file:
|
65
65
|
#
|
66
66
|
# Once our chunk of behavior starts pushing the scroll-to-understand-it
|
67
67
|
# boundary, we give in and move it to a separate file. At this size, the
|
@@ -75,7 +75,7 @@ class Module
|
|
75
75
|
# include TodoEventTracking
|
76
76
|
# end
|
77
77
|
#
|
78
|
-
#
|
78
|
+
# == Introducing Module#concerning
|
79
79
|
#
|
80
80
|
# By quieting the mix-in noise, we arrive at a natural, low-ceremony way to
|
81
81
|
# separate bite-sized concerns.
|
@@ -164,7 +164,7 @@ module ActiveSupport
|
|
164
164
|
# upcase_first('w') # => "W"
|
165
165
|
# upcase_first('') # => ""
|
166
166
|
def upcase_first(string)
|
167
|
-
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
|
167
|
+
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +""
|
168
168
|
end
|
169
169
|
|
170
170
|
# Converts the first character in the string to lowercase.
|
@@ -173,7 +173,7 @@ module ActiveSupport
|
|
173
173
|
# downcase_first('I') # => "i"
|
174
174
|
# downcase_first('') # => ""
|
175
175
|
def downcase_first(string)
|
176
|
-
string.length > 0 ? string[0].downcase.concat(string[1..-1]) : ""
|
176
|
+
string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
|
177
177
|
end
|
178
178
|
|
179
179
|
# Capitalizes all the words and replaces some characters in the string to
|
@@ -86,6 +86,12 @@ module ActiveSupport
|
|
86
86
|
mattr_accessor :colorize_logging, default: true
|
87
87
|
class_attribute :log_levels, instance_accessor: false, default: {} # :nodoc:
|
88
88
|
|
89
|
+
LEVEL_CHECKS = {
|
90
|
+
debug: -> (logger) { !logger.debug? },
|
91
|
+
info: -> (logger) { !logger.info? },
|
92
|
+
error: -> (logger) { !logger.error? },
|
93
|
+
}
|
94
|
+
|
89
95
|
class << self
|
90
96
|
def logger
|
91
97
|
@logger ||= if defined?(Rails) && Rails.respond_to?(:logger)
|
@@ -122,7 +128,7 @@ module ActiveSupport
|
|
122
128
|
end
|
123
129
|
|
124
130
|
def subscribe_log_level(method, level)
|
125
|
-
self.log_levels = log_levels.merge(method =>
|
131
|
+
self.log_levels = log_levels.merge(method => LEVEL_CHECKS.fetch(level))
|
126
132
|
set_event_levels
|
127
133
|
end
|
128
134
|
end
|
@@ -137,7 +143,7 @@ module ActiveSupport
|
|
137
143
|
end
|
138
144
|
|
139
145
|
def silenced?(event)
|
140
|
-
logger.nil? ||
|
146
|
+
logger.nil? || @event_levels[event]&.call(logger)
|
141
147
|
end
|
142
148
|
|
143
149
|
def call(event)
|
@@ -18,26 +18,30 @@ module ActiveSupport
|
|
18
18
|
end
|
19
19
|
|
20
20
|
module FanoutIteration # :nodoc:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
listeners.each do |s|
|
25
|
-
yield s
|
26
|
-
rescue Exception => e
|
27
|
-
exceptions ||= []
|
28
|
-
exceptions << e
|
29
|
-
end
|
21
|
+
private
|
22
|
+
def iterate_guarding_exceptions(collection)
|
23
|
+
exceptions = nil
|
30
24
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
collection.each do |s|
|
26
|
+
yield s
|
27
|
+
rescue Exception => e
|
28
|
+
exceptions ||= []
|
29
|
+
exceptions << e
|
36
30
|
end
|
37
|
-
end
|
38
31
|
|
39
|
-
|
40
|
-
|
32
|
+
if exceptions
|
33
|
+
exceptions = exceptions.flat_map do |exception|
|
34
|
+
exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception]
|
35
|
+
end
|
36
|
+
if exceptions.size == 1
|
37
|
+
raise exceptions.first
|
38
|
+
else
|
39
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
collection
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
43
47
|
# This is a default queue implementation that ships with Notifications.
|
@@ -225,6 +229,8 @@ module ActiveSupport
|
|
225
229
|
# handle.finish
|
226
230
|
# end
|
227
231
|
class Handle
|
232
|
+
include FanoutIteration
|
233
|
+
|
228
234
|
def initialize(notifier, name, id, payload) # :nodoc:
|
229
235
|
@name = name
|
230
236
|
@id = id
|
@@ -239,7 +245,7 @@ module ActiveSupport
|
|
239
245
|
ensure_state! :initialized
|
240
246
|
@state = :started
|
241
247
|
|
242
|
-
@groups
|
248
|
+
iterate_guarding_exceptions(@groups) do |group|
|
243
249
|
group.start(@name, @id, @payload)
|
244
250
|
end
|
245
251
|
end
|
@@ -252,7 +258,7 @@ module ActiveSupport
|
|
252
258
|
ensure_state! :started
|
253
259
|
@state = :finished
|
254
260
|
|
255
|
-
@groups
|
261
|
+
iterate_guarding_exceptions(@groups) do |group|
|
256
262
|
group.finish(name, id, payload)
|
257
263
|
end
|
258
264
|
end
|
@@ -43,13 +43,13 @@ module ActiveSupport
|
|
43
43
|
|
44
44
|
def exponent
|
45
45
|
max = STORAGE_UNITS.size - 1
|
46
|
-
exp = (Math.log(number) / Math.log(base)).to_i
|
46
|
+
exp = (Math.log(number.abs) / Math.log(base)).to_i
|
47
47
|
exp = max if exp > max # avoid overflow for the highest unit
|
48
48
|
exp
|
49
49
|
end
|
50
50
|
|
51
51
|
def smaller_than_base?
|
52
|
-
number.to_i < base
|
52
|
+
number.to_i.abs < base
|
53
53
|
end
|
54
54
|
|
55
55
|
def base
|
@@ -17,6 +17,7 @@ module ActiveSupport
|
|
17
17
|
SUPPRESSED_WARNINGS = Regexp.union(
|
18
18
|
# TODO: remove if https://github.com/mikel/mail/pull/1557 or similar fix
|
19
19
|
%r{/lib/mail/parsers/.*statement not reached},
|
20
|
+
%r{/lib/mail/parsers/.*assigned but unused variable - disp_type_s},
|
20
21
|
%r{/lib/mail/parsers/.*assigned but unused variable - testEof}
|
21
22
|
)
|
22
23
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activesupport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.1.
|
4
|
+
version: 7.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10
|
11
|
+
date: 2023-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -446,10 +446,10 @@ licenses:
|
|
446
446
|
- MIT
|
447
447
|
metadata:
|
448
448
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
449
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.1.
|
450
|
-
documentation_uri: https://api.rubyonrails.org/v7.1.
|
449
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.1.2/activesupport/CHANGELOG.md
|
450
|
+
documentation_uri: https://api.rubyonrails.org/v7.1.2/
|
451
451
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
452
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.1.
|
452
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.1.2/activesupport
|
453
453
|
rubygems_mfa_required: 'true'
|
454
454
|
post_install_message:
|
455
455
|
rdoc_options:
|