activesupport 7.1.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82365193f8aa8e04a486a7ed6f82adeb64093abd70569d67c7756b065f754b82
4
- data.tar.gz: ececf5de5e7b69fe11b7edc1007e7b850c2463005ffba7f2763b85636e192d98
3
+ metadata.gz: 6db71966858e675d32617069b0df8dc17b1c5dfe8123c87ae96a28fdb6e2f5e6
4
+ data.tar.gz: 81ffe410567130147cd0c6f74943d40404a4031b2cf30f12bfaa2ee698cd5a57
5
5
  SHA512:
6
- metadata.gz: e6daffabed388ec6412bff231a3d2478f430625d266078fe186c92594353b87026dc22a492e689ea7a716a570eb75a9eb53582a45b33627a06444be1b560da7e
7
- data.tar.gz: 33dc1b13f205838ad773fc7c4bfda5bb6bec704cbdb7ffdaedfe938a91088c2dd98d1ade38514689dbb66d2f5f45e3871973b8981c21cd6deabec0cff41349da
6
+ metadata.gz: 99a9131ff9f97e739719621df9ba0a33d3b2fad9b1315397382235f29d33ee130f701d0c0ed767eacf01ccb31607eb26d7f5bb95f37ad86ac57f18817cd9b253
7
+ data.tar.gz: ffa6a0ffe90b88c87f65d85ddb32390d20f8c34ab2517f797c34d325839cbf434a0202650cdd54f118bee9a299cf478f83af4222c313f2746e267bbd19003914
data/CHANGELOG.md CHANGED
@@ -1,3 +1,91 @@
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
+
68
+ ## Rails 7.1.1 (October 11, 2023) ##
69
+
70
+ * Add support for keyword arguments when delegating calls to custom loggers from `ActiveSupport::BroadcastLogger`.
71
+
72
+ *Edouard Chin*
73
+
74
+ * `NumberHelper`: handle objects responding `to_d`.
75
+
76
+ *fatkodima*
77
+
78
+ * Fix RedisCacheStore to properly set the TTL when incrementing or decrementing.
79
+
80
+ This bug was only impacting Redis server older than 7.0.
81
+
82
+ *Thomas Countz*
83
+
84
+ * Fix MemoryStore to prevent race conditions when incrementing or decrementing.
85
+
86
+ *Pierre Jambet*
87
+
88
+
1
89
  ## Rails 7.1.0 (October 05, 2023) ##
2
90
 
3
91
  * No changes.
@@ -868,7 +956,7 @@
868
956
 
869
957
  *Trevor Turk*
870
958
 
871
- * `ActiveSupport::Cache:Store#fetch` now passes an options accessor to the block.
959
+ * `ActiveSupport::Cache::Store#fetch` now passes an options accessor to the block.
872
960
 
873
961
  It makes possible to override cache options:
874
962
 
@@ -51,6 +51,26 @@ module ActiveSupport
51
51
  #
52
52
  # broadcast = BroadcastLogger.new
53
53
  # broadcast.info("Hello world") # The log message will appear nowhere.
54
+ #
55
+ # If you are adding a custom logger with custom methods to the broadcast,
56
+ # the `BroadcastLogger` will proxy them and return the raw value, or an array
57
+ # of raw values, depending on how many loggers in the broadcasts responded to
58
+ # the method:
59
+ #
60
+ # class MyLogger < ::Logger
61
+ # def loggable?
62
+ # true
63
+ # end
64
+ # end
65
+ #
66
+ # logger = BroadcastLogger.new
67
+ # logger.loggable? # => A NoMethodError exception is raised because no loggers in the broadcasts could respond.
68
+ #
69
+ # logger.broadcast_to(MyLogger.new(STDOUT))
70
+ # logger.loggable? # => true
71
+ # logger.broadcast_to(MyLogger.new(STDOUT))
72
+ # puts logger.broadcasts # => [MyLogger, MyLogger]
73
+ # logger.loggable? # [true, true]
54
74
  class BroadcastLogger
55
75
  include ActiveSupport::LoggerSilence
56
76
 
@@ -198,20 +218,28 @@ module ActiveSupport
198
218
  dispatch { |logger| logger.fatal! }
199
219
  end
200
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
+
201
229
  private
202
230
  def dispatch(&block)
203
231
  @broadcasts.each { |logger| block.call(logger) }
204
232
  end
205
233
 
206
- def method_missing(name, *args, &block)
234
+ def method_missing(name, *args, **kwargs, &block)
207
235
  loggers = @broadcasts.select { |logger| logger.respond_to?(name) }
208
236
 
209
237
  if loggers.none?
210
- super(name, *args, &block)
238
+ super(name, *args, **kwargs, &block)
211
239
  elsif loggers.one?
212
- loggers.first.send(name, *args, &block)
240
+ loggers.first.send(name, *args, **kwargs, &block)
213
241
  else
214
- loggers.map { |logger| logger.send(name, *args, &block) }
242
+ loggers.map { |logger| logger.send(name, *args, **kwargs, &block) }
215
243
  end
216
244
  end
217
245
 
@@ -121,7 +121,13 @@ module ActiveSupport
121
121
 
122
122
  private
123
123
  def uncompress(value)
124
- Marshal.load(Zlib::Inflate.inflate(value))
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 = @data.with { |c| c.get_multi(keys_to_names.keys) }
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
- values[keys_to_names[key]] = entry.value
285
+ begin
286
+ values[keys_to_names[key]] = entry.value
287
+ rescue DeserializationError
288
+ end
281
289
  end
282
290
  end
283
291
 
@@ -238,16 +238,18 @@ module ActiveSupport
238
238
  key = normalize_key(name, options)
239
239
  version = normalize_version(name, options)
240
240
 
241
- entry = read_entry(key, **options)
241
+ synchronize do
242
+ entry = read_entry(key, **options)
242
243
 
243
- if !entry || entry.expired? || entry.mismatched?(version)
244
- write(name, Integer(amount), options)
245
- amount
246
- else
247
- num = entry.value.to_i + amount
248
- entry = Entry.new(num, expires_at: entry.expires_at, version: entry.version)
249
- write_entry(key, entry)
250
- num
244
+ if !entry || entry.expired? || entry.mismatched?(version)
245
+ write(name, Integer(amount), options)
246
+ amount
247
+ else
248
+ num = entry.value.to_i + amount
249
+ entry = Entry.new(num, expires_at: entry.expires_at, version: entry.version)
250
+ write_entry(key, entry)
251
+ num
252
+ end
251
253
  end
252
254
  end
253
255
  end
@@ -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
- results[name] = entry.value
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, expires_in: nil, race_condition_ttl: nil, **options)
389
+ def write_multi_entries(entries, **options)
387
390
  return if entries.empty?
388
391
 
389
392
  failsafe :write_multi_entries do
@@ -438,18 +441,26 @@ module ActiveSupport
438
441
  redis.then do |c|
439
442
  c = c.node_for(key) if c.is_a?(Redis::Distributed)
440
443
 
441
- if options[:expires_in] && supports_expire_nx?
442
- c.pipelined do |pipeline|
443
- pipeline.incrby(key, amount)
444
- pipeline.call(:expire, key, options[:expires_in].to_i, "NX")
445
- end.first
444
+ expires_in = options[:expires_in]
445
+
446
+ if expires_in
447
+ if supports_expire_nx?
448
+ count, _ = c.pipelined do |pipeline|
449
+ pipeline.incrby(key, amount)
450
+ pipeline.call(:expire, key, expires_in.to_i, "NX")
451
+ end
452
+ else
453
+ count, ttl = c.pipelined do |pipeline|
454
+ pipeline.incrby(key, amount)
455
+ pipeline.ttl(key)
456
+ end
457
+ c.expire(key, expires_in.to_i) if ttl < 0
458
+ end
446
459
  else
447
460
  count = c.incrby(key, amount)
448
- if count != amount && options[:expires_in] && c.ttl(key) < 0
449
- c.expire(key, options[:expires_in].to_i)
450
- end
451
- count
452
461
  end
462
+
463
+ count
453
464
  end
454
465
  end
455
466
 
@@ -439,9 +439,9 @@ module ActiveSupport
439
439
  #
440
440
  # ==== Dynamic Options
441
441
  #
442
- # In some cases it may be necessary to to dynamically compute options based
443
- # on the cached value. For this purpose, a ActiveSupport::Cache::WriteOptions
444
- # instance is passed as a second argument to the block
442
+ # In some cases it may be necessary to dynamically compute options based
443
+ # on the cached value. To support this, an ActiveSupport::Cache::WriteOptions
444
+ # instance is passed as the second argument to the block. For example:
445
445
  #
446
446
  # cache.fetch("authentication-token:#{user.id}") do |key, options|
447
447
  # token = authenticate_to_service
@@ -449,12 +449,6 @@ module ActiveSupport
449
449
  # token
450
450
  # end
451
451
  #
452
- # Only some options can be set dynamically:
453
- #
454
- # - +:expires_in+
455
- # - +:expires_at+
456
- # - +:version+
457
- #
458
452
  def fetch(name, options = nil, &block)
459
453
  if block_given?
460
454
  options = merged_options(options)
@@ -465,7 +459,17 @@ module ActiveSupport
465
459
  instrument(:read, name, options) do |payload|
466
460
  cached_entry = read_entry(key, **options, event: payload)
467
461
  entry = handle_expired_entry(cached_entry, key, options)
468
- entry = nil if entry && entry.mismatched?(normalize_version(name, options))
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
469
473
  payload[:super_operation] = :fetch if payload
470
474
  payload[:hit] = !!entry if payload
471
475
  end
@@ -517,7 +521,12 @@ module ActiveSupport
517
521
  nil
518
522
  else
519
523
  payload[:hit] = true if payload
520
- entry.value
524
+ begin
525
+ entry.value
526
+ rescue DeserializationError
527
+ payload[:hit] = false
528
+ nil
529
+ end
521
530
  end
522
531
  else
523
532
  payload[:hit] = false if payload
@@ -1044,6 +1053,8 @@ module ActiveSupport
1044
1053
  end
1045
1054
 
1046
1055
  def save_block_result_to_cache(name, options)
1056
+ options = options.dup
1057
+
1047
1058
  result = instrument(:generate, name, options) do
1048
1059
  yield(name, WriteOptions.new(options))
1049
1060
  end
@@ -52,7 +52,7 @@ class Date
52
52
  strftime(formatter)
53
53
  end
54
54
  else
55
- to_default_s
55
+ to_s
56
56
  end
57
57
  end
58
58
  alias_method :to_formatted_s, :to_fs
@@ -3,7 +3,7 @@
3
3
  require "active_support/concern"
4
4
 
5
5
  class Module
6
- # = Bite-sized separation of concerns
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
- # = Dissatisfying ways to separate small concerns
21
+ # == Dissatisfying ways to separate small concerns
22
22
  #
23
- # == Using comments:
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
- # == With an inline module:
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
- # == Mix-in noise exiled to its own file:
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
- # = Introducing Module#concerning
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.
@@ -29,7 +29,7 @@ require "active_support/core_ext/date/conversions"
29
29
  # It should be noted that when using ::JSON.{generate,dump} directly, ActiveSupport's encoder is
30
30
  # bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
31
31
  # ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
32
- # should give exactly the same results with or without active support.
32
+ # should give exactly the same results with or without Active Support.
33
33
 
34
34
  module ActiveSupport
35
35
  module ToJsonWithActiveSupportEncoder # :nodoc:
@@ -60,8 +60,8 @@ module ActiveSupport
60
60
  # [+raise+] Raise ActiveSupport::DeprecationException.
61
61
  # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
62
62
  # [+log+] Log all deprecation warnings to +Rails.logger+.
63
- # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
64
- # [+report+] Use +ActiveSupport::ErrorReporter+ to report deprecations.
63
+ # [+notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
64
+ # [+report+] Use ActiveSupport::ErrorReporter to report deprecations.
65
65
  # [+silence+] Do nothing. On \Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
66
66
  #
67
67
  # Setting behaviors only affects deprecations that happen after boot time.
@@ -88,8 +88,8 @@ module ActiveSupport
88
88
  # [+raise+] Raise ActiveSupport::DeprecationException.
89
89
  # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
90
90
  # [+log+] Log all deprecation warnings to +Rails.logger+.
91
- # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
92
- # [+report+] Use +ActiveSupport::ErrorReporter+ to report deprecations.
91
+ # [+notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
92
+ # [+report+] Use ActiveSupport::ErrorReporter to report deprecations.
93
93
  # [+silence+] Do nothing.
94
94
  #
95
95
  # Setting behaviors only affects deprecations that happen after boot time.
@@ -9,7 +9,7 @@ module ActiveSupport
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 1
12
- TINY = 0
12
+ TINY = 2
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -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 => ::Logger.const_get(level.upcase))
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? || logger.level > @event_levels.fetch(event, Float::INFINITY)
146
+ logger.nil? || @event_levels[event]&.call(logger)
141
147
  end
142
148
 
143
149
  def call(event)
@@ -130,6 +130,7 @@ module ActiveSupport
130
130
  # indicate whether old option sets are still in use or can be removed from
131
131
  # rotation.
132
132
 
133
+ ##
133
134
  private
134
135
  def build(salt, secret_generator:, secret_generator_options:, **options)
135
136
  secret_length = MessageEncryptor.key_len(*options[:cipher])
@@ -126,6 +126,7 @@ module ActiveSupport
126
126
  # indicate whether old option sets are still in use or can be removed from
127
127
  # rotation.
128
128
 
129
+ ##
129
130
  private
130
131
  def build(salt, secret_generator:, secret_generator_options:, **options)
131
132
  MessageVerifier.new(secret_generator.call(salt, **secret_generator_options), **options)
@@ -82,7 +82,7 @@ module ActiveSupport
82
82
  throw :invalid_message_content, "expired"
83
83
  end
84
84
 
85
- if hash["pur"] != purpose&.to_s
85
+ if hash["pur"].to_s != purpose.to_s
86
86
  throw :invalid_message_content, "mismatched purpose"
87
87
  end
88
88
 
@@ -18,26 +18,30 @@ module ActiveSupport
18
18
  end
19
19
 
20
20
  module FanoutIteration # :nodoc:
21
- def iterate_guarding_exceptions(listeners)
22
- exceptions = nil
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
- if exceptions
32
- if exceptions.size == 1
33
- raise exceptions.first
34
- else
35
- raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
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
- listeners
40
- end
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.each do |group|
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.each do |group|
261
+ iterate_guarding_exceptions(@groups) do |group|
256
262
  group.finish(name, id, payload)
257
263
  end
258
264
  end
@@ -65,16 +65,16 @@ module ActiveSupport
65
65
  end
66
66
  end
67
67
 
68
- # Returns a "handle" for an event with the given +name+ and +payload+
68
+ # Returns a "handle" for an event with the given +name+ and +payload+.
69
69
  #
70
- # +#start+ and +#finish+ must each be called exactly once on the returned object.
70
+ # #start and #finish must each be called exactly once on the returned object.
71
71
  #
72
- # Where possible, it's best to use +#instrument+, which will record the
72
+ # Where possible, it's best to use #instrument, which will record the
73
73
  # start and finish of the event and correctly handle any exceptions.
74
74
  # +build_handle+ is a low-level API intended for cases where using
75
- # +#instrument+ isn't possible.
75
+ # +instrument+ isn't possible.
76
76
  #
77
- # See ActiveSupport::Notifications::Fanout::Handle
77
+ # See ActiveSupport::Notifications::Fanout::Handle.
78
78
  def build_handle(name, payload)
79
79
  @notifier.build_handle(name, @id, payload)
80
80
  end
@@ -146,21 +146,21 @@ module ActiveSupport
146
146
  @allocation_count_finish = now_allocations
147
147
  end
148
148
 
149
- # Returns the CPU time (in milliseconds) passed since the call to
150
- # +start!+ and the call to +finish!+
149
+ # Returns the CPU time (in milliseconds) passed between the call to
150
+ # #start! and the call to #finish!.
151
151
  def cpu_time
152
152
  @cpu_time_finish - @cpu_time_start
153
153
  end
154
154
 
155
- # Returns the idle time time (in milliseconds) passed since the call to
156
- # +start!+ and the call to +finish!+
155
+ # Returns the idle time time (in milliseconds) passed between the call to
156
+ # #start! and the call to #finish!.
157
157
  def idle_time
158
158
  diff = duration - cpu_time
159
159
  diff > 0.0 ? diff : 0.0
160
160
  end
161
161
 
162
- # Returns the number of allocations made since the call to +start!+ and
163
- # the call to +finish!+
162
+ # Returns the number of allocations made between the call to #start! and
163
+ # the call to #finish!.
164
164
  def allocations
165
165
  @allocation_count_finish - @allocation_count_start
166
166
  end
@@ -179,8 +179,10 @@ module ActiveSupport
179
179
  case number
180
180
  when Float, Rational
181
181
  number.to_d(0)
182
- else
182
+ when String
183
183
  BigDecimal(number, exception: false)
184
+ else
185
+ number.to_d rescue nil
184
186
  end
185
187
  end
186
188
  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
@@ -42,8 +42,8 @@ module ActiveSupport
42
42
  super(key.to_sym)
43
43
  end
44
44
 
45
- def dig(*keys)
46
- super(*keys.flatten.map(&:to_sym))
45
+ def dig(key, *identifiers)
46
+ super(key.to_sym, *identifiers)
47
47
  end
48
48
 
49
49
  def method_missing(name, *args)
@@ -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
 
@@ -25,7 +25,7 @@ module ActiveSupport
25
25
  unstub_object(stub)
26
26
  end
27
27
 
28
- new_name = "__simple_stub__#{method_name}"
28
+ new_name = "__simple_stub__#{method_name}__#{object_id}"
29
29
 
30
30
  @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
31
31
 
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.0
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-05 00:00:00.000000000 Z
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.0/activesupport/CHANGELOG.md
450
- documentation_uri: https://api.rubyonrails.org/v7.1.0/
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.0/activesupport
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: