activesupport 7.1.1 → 7.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|