activesupport 7.0.3.1 → 7.0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4e3f1179b029500503dbf9f399d00a8072610e1b0de00817c8892ed03af34bf
4
- data.tar.gz: d627490cc53ce2be525df66b9a4e46869c53daa9458eaaa3d9cb5828d9dd327c
3
+ metadata.gz: d9470ff58694a134f22c189060593e6c108b738bfe7ad4b6e30f8baac494879e
4
+ data.tar.gz: bf6ec0c4573ad54d38d8ad108869736d2308c1c8b4561110b5ecd8dc8550e852
5
5
  SHA512:
6
- metadata.gz: 00bda131342cb0bca89db7291d96c24db0d247f56fa4b9a0f6375a2a29025f947b863e46a411acbec5c01133efec2ce3a0b44f8bc1f402e490e4d814d5f6e388
7
- data.tar.gz: ca0ca139495bada0d5b2efe2da3d5b7bcd68506fa571ae4cc1a505a5487a39a7ca388e78f8e5091b1523b60a6634f5d6e2f02600181bc65dbb0ffd87c4c0f354
6
+ metadata.gz: 55f8f041f06207f6b2f95c96330eb8bcc88e5488fe5fe4571b6025aef87bad579ad601a31f86bac8b7e8b0f339daba55e032b8d3745dacc06acac7dccd2048f5
7
+ data.tar.gz: a7e2097592b625e4b5f938c7e9c056d441f7fba47ada65187396fcfc7ed95353c327bd898288d3720c11792198378cddf62db7cf4576c283239ab912296f0488
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ ## Rails 7.0.4.1 (January 17, 2023) ##
2
+
3
+ * Avoid regex backtracking in Inflector.underscore
4
+
5
+ [CVE-2023-22796]
6
+
7
+
8
+ ## Rails 7.0.4 (September 09, 2022) ##
9
+
10
+ * Redis cache store is now compatible with redis-rb 5.0.
11
+
12
+ *Jean Boussier*
13
+
14
+ * Fix `NoMethodError` on custom `ActiveSupport::Deprecation` behavior.
15
+
16
+ `ActiveSupport::Deprecation.behavior=` was supposed to accept any object
17
+ that responds to `call`, but in fact its internal implementation assumed that
18
+ this object could respond to `arity`, so it was restricted to only `Proc` objects.
19
+
20
+ This change removes this `arity` restriction of custom behaviors.
21
+
22
+ *Ryo Nakamura*
23
+
24
+
1
25
  ## Rails 7.0.3.1 (July 12, 2022) ##
2
26
 
3
27
  * No changes.
@@ -128,6 +128,22 @@ module ActiveSupport
128
128
  end
129
129
  end
130
130
 
131
+ ##
132
+ # :method: write
133
+ # :call-seq: write(name, value, options = nil)
134
+ #
135
+ # Behaves the same as ActiveSupport::Cache::Store#write, but supports
136
+ # additional options specific to memcached.
137
+ #
138
+ # ==== Additional Options
139
+ #
140
+ # * <tt>raw: true</tt> - Sends the value directly to the server as raw
141
+ # bytes. The value must be a string or number. You can use memcached
142
+ # direct operations like +increment+ and +decrement+ only on raw values.
143
+ #
144
+ # * <tt>unless_exist: true</tt> - Prevents overwriting an existing cache
145
+ # entry.
146
+
131
147
  # Increment a cached value. This method uses the memcached incr atomic
132
148
  # operator and can only be used on values written with the +:raw+ option.
133
149
  # Calling it on a value not stored with +:raw+ will initialize that value
@@ -5,13 +5,17 @@ begin
5
5
  require "redis"
6
6
  require "redis/distributed"
7
7
  rescue LoadError
8
- warn "The Redis cache store requires the redis gem, version 4.0.1 or later. Please add it to your Gemfile: `gem \"redis\", \"~> 4.0\"`"
8
+ warn "The Redis cache store requires the redis gem, version 4.0.1 or later. Please add it to your Gemfile: `gem \"redis\", \">= 4.0.1\"`"
9
9
  raise
10
10
  end
11
11
 
12
12
  # Prefer the hiredis driver but don't require it.
13
13
  begin
14
- require "redis/connection/hiredis"
14
+ if ::Redis::VERSION < "5"
15
+ require "redis/connection/hiredis"
16
+ else
17
+ require "hiredis-client"
18
+ end
15
19
  rescue LoadError
16
20
  end
17
21
 
@@ -92,9 +96,11 @@ module ActiveSupport
92
96
  elsif redis
93
97
  redis
94
98
  elsif urls.size > 1
95
- build_redis_distributed_client urls: urls, **redis_options
99
+ build_redis_distributed_client(urls: urls, **redis_options)
100
+ elsif urls.empty?
101
+ build_redis_client(**redis_options)
96
102
  else
97
- build_redis_client url: urls.first, **redis_options
103
+ build_redis_client(url: urls.first, **redis_options)
98
104
  end
99
105
  end
100
106
 
@@ -105,8 +111,8 @@ module ActiveSupport
105
111
  end
106
112
  end
107
113
 
108
- def build_redis_client(url:, **redis_options)
109
- ::Redis.new DEFAULT_REDIS_OPTIONS.merge(redis_options.merge(url: url))
114
+ def build_redis_client(**redis_options)
115
+ ::Redis.new(DEFAULT_REDIS_OPTIONS.merge(redis_options))
110
116
  end
111
117
  end
112
118
 
@@ -139,7 +139,7 @@ module ActiveSupport
139
139
  # popular cache store for large production websites.
140
140
  #
141
141
  # Some implementations may not support all methods beyond the basic cache
142
- # methods of +fetch+, +write+, +read+, +exist?+, and +delete+.
142
+ # methods of #fetch, #write, #read, #exist?, and #delete.
143
143
  #
144
144
  # ActiveSupport::Cache::Store can store any Ruby object that is supported by
145
145
  # its +coder+'s +dump+ and +load+ methods.
@@ -172,11 +172,6 @@ module ActiveSupport
172
172
  # cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
173
173
  # @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
174
174
  #
175
- # Cached data larger than 1kB are compressed by default. To turn off
176
- # compression, pass <tt>compress: false</tt> to the initializer or to
177
- # individual +fetch+ or +write+ method calls. The 1kB compression
178
- # threshold is configurable with the <tt>:compress_threshold</tt> option,
179
- # specified in bytes.
180
175
  class Store
181
176
  cattr_accessor :logger, instance_writer: true
182
177
 
@@ -200,9 +195,19 @@ module ActiveSupport
200
195
  end
201
196
  end
202
197
 
203
- # Creates a new cache. The options will be passed to any write method calls
204
- # except for <tt>:namespace</tt> which can be used to set the global
205
- # namespace for the cache.
198
+ # Creates a new cache.
199
+ #
200
+ # ==== Options
201
+ #
202
+ # * +:namespace+ - Sets the namespace for the cache. This option is
203
+ # especially useful if your application shares a cache with other
204
+ # applications.
205
+ # * +:coder+ - Replaces the default cache entry serialization mechanism
206
+ # with a custom one. The +coder+ must respond to +dump+ and +load+.
207
+ # Using a custom coder disables automatic compression.
208
+ #
209
+ # Any other specified options are treated as default options for the
210
+ # relevant cache operations, such as #read, #write, and #fetch.
206
211
  def initialize(options = nil)
207
212
  @options = options ? normalize_options(options) : {}
208
213
  @options[:compress] = true unless @options.key?(:compress)
@@ -244,111 +249,75 @@ module ActiveSupport
244
249
  # end
245
250
  # cache.fetch('city') # => "Duckburgh"
246
251
  #
247
- # You may also specify additional options via the +options+ argument.
248
- # Setting <tt>force: true</tt> forces a cache "miss," meaning we treat
249
- # the cache value as missing even if it's present. Passing a block is
250
- # required when +force+ is true so this always results in a cache write.
252
+ # ==== Options
251
253
  #
252
- # cache.write('today', 'Monday')
253
- # cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday'
254
- # cache.fetch('today', force: true) # => ArgumentError
255
- #
256
- # The +:force+ option is useful when you're calling some other method to
257
- # ask whether you should force a cache write. Otherwise, it's clearer to
258
- # just call <tt>Cache#write</tt>.
259
- #
260
- # Setting <tt>skip_nil: true</tt> will not cache nil result:
261
- #
262
- # cache.fetch('foo') { nil }
263
- # cache.fetch('bar', skip_nil: true) { nil }
264
- # cache.exist?('foo') # => true
265
- # cache.exist?('bar') # => false
266
- #
267
- #
268
- # Setting <tt>compress: false</tt> disables compression of the cache entry.
269
- #
270
- # Setting <tt>:expires_in</tt> will set an expiration time on the cache.
271
- # All caches support auto-expiring content after a specified number of
272
- # seconds. This value can be specified as an option to the constructor
273
- # (in which case all entries will be affected), or it can be supplied to
274
- # the +fetch+ or +write+ method to affect just one entry.
275
- # <tt>:expire_in</tt> and <tt>:expired_in</tt> are aliases for
276
- # <tt>:expires_in</tt>.
277
- #
278
- # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
279
- # cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
280
- #
281
- # Setting <tt>:expires_at</tt> will set an absolute expiration time on the cache.
282
- # All caches support auto-expiring content after a specified number of
283
- # seconds. This value can only be supplied to the +fetch+ or +write+ method to
284
- # affect just one entry.
285
- #
286
- # cache = ActiveSupport::Cache::MemoryStore.new
287
- # cache.write(key, value, expires_at: Time.now.at_end_of_hour)
288
- #
289
- # Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
290
- # is of the same version. nil is returned on mismatches despite contents.
291
- # This feature is used to support recyclable cache keys.
292
- #
293
- # Setting <tt>:race_condition_ttl</tt> is very useful in situations where
294
- # a cache entry is used very frequently and is under heavy load. If a
295
- # cache expires and due to heavy load several different processes will try
296
- # to read data natively and then they all will try to write to cache. To
297
- # avoid that case the first process to find an expired cache entry will
298
- # bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>.
299
- # Yes, this process is extending the time for a stale value by another few
300
- # seconds. Because of extended life of the previous cache, other processes
301
- # will continue to use slightly stale data for a just a bit longer. In the
302
- # meantime that first process will go ahead and will write into cache the
303
- # new value. After that all the processes will start getting the new value.
304
- # The key is to keep <tt>:race_condition_ttl</tt> small.
305
- #
306
- # If the process regenerating the entry errors out, the entry will be
307
- # regenerated after the specified number of seconds. Also note that the
308
- # life of stale cache is extended only if it expired recently. Otherwise
309
- # a new value is generated and <tt>:race_condition_ttl</tt> does not play
310
- # any role.
311
- #
312
- # # Set all values to expire after one minute.
313
- # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
314
- #
315
- # cache.write('foo', 'original value')
316
- # val_1 = nil
317
- # val_2 = nil
318
- # sleep 60
319
- #
320
- # Thread.new do
321
- # val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
322
- # sleep 1
323
- # 'new value 1'
324
- # end
325
- # end
254
+ # Internally, +fetch+ calls #read_entry, and calls #write_entry on a cache
255
+ # miss. Thus, +fetch+ supports the same options as #read and #write.
256
+ # Additionally, +fetch+ supports the following options:
326
257
  #
327
- # Thread.new do
328
- # val_2 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
329
- # 'new value 2'
330
- # end
331
- # end
258
+ # * <tt>force: true</tt> - Forces a cache "miss," meaning we treat the
259
+ # cache value as missing even if it's present. Passing a block is
260
+ # required when +force+ is true so this always results in a cache write.
332
261
  #
333
- # cache.fetch('foo') # => "original value"
334
- # sleep 10 # First thread extended the life of cache by another 10 seconds
335
- # cache.fetch('foo') # => "new value 1"
336
- # val_1 # => "new value 1"
337
- # val_2 # => "original value"
262
+ # cache.write('today', 'Monday')
263
+ # cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday'
264
+ # cache.fetch('today', force: true) # => ArgumentError
338
265
  #
339
- # Other options will be handled by the specific cache store implementation.
340
- # Internally, #fetch calls #read_entry, and calls #write_entry on a cache
341
- # miss. +options+ will be passed to the #read and #write calls.
266
+ # The +:force+ option is useful when you're calling some other method to
267
+ # ask whether you should force a cache write. Otherwise, it's clearer to
268
+ # just call +write+.
342
269
  #
343
- # For example, MemCacheStore's #write method supports the +:raw+
344
- # option, which tells the memcached server to store all values as strings.
345
- # We can use this option with #fetch too:
270
+ # * <tt>skip_nil: true</tt> - Prevents caching a nil result:
271
+ #
272
+ # cache.fetch('foo') { nil }
273
+ # cache.fetch('bar', skip_nil: true) { nil }
274
+ # cache.exist?('foo') # => true
275
+ # cache.exist?('bar') # => false
276
+ #
277
+ # * +:race_condition_ttl+ - Specifies the number of seconds during which
278
+ # an expired value can be reused while a new value is being generated.
279
+ # This can be used to prevent race conditions when cache entries expire,
280
+ # by preventing multiple processes from simultaneously regenerating the
281
+ # same entry (also known as the dog pile effect).
282
+ #
283
+ # When a process encounters a cache entry that has expired less than
284
+ # +:race_condition_ttl+ seconds ago, it will bump the expiration time by
285
+ # +:race_condition_ttl+ seconds before generating a new value. During
286
+ # this extended time window, while the process generates a new value,
287
+ # other processes will continue to use the old value. After the first
288
+ # process writes the new value, other processes will then use it.
289
+ #
290
+ # If the first process errors out while generating a new value, another
291
+ # process can try to generate a new value after the extended time window
292
+ # has elapsed.
293
+ #
294
+ # # Set all values to expire after one minute.
295
+ # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
296
+ #
297
+ # cache.write('foo', 'original value')
298
+ # val_1 = nil
299
+ # val_2 = nil
300
+ # sleep 60
301
+ #
302
+ # Thread.new do
303
+ # val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
304
+ # sleep 1
305
+ # 'new value 1'
306
+ # end
307
+ # end
308
+ #
309
+ # Thread.new do
310
+ # val_2 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
311
+ # 'new value 2'
312
+ # end
313
+ # end
314
+ #
315
+ # cache.fetch('foo') # => "original value"
316
+ # sleep 10 # First thread extended the life of cache by another 10 seconds
317
+ # cache.fetch('foo') # => "new value 1"
318
+ # val_1 # => "new value 1"
319
+ # val_2 # => "original value"
346
320
  #
347
- # cache = ActiveSupport::Cache::MemCacheStore.new
348
- # cache.fetch("foo", force: true, raw: true) do
349
- # :bar
350
- # end
351
- # cache.fetch('foo') # => "bar"
352
321
  def fetch(name, options = nil, &block)
353
322
  if block_given?
354
323
  options = merged_options(options)
@@ -383,7 +352,13 @@ module ActiveSupport
383
352
  # <tt>:version</tt> options, both of these conditions are applied before
384
353
  # the data is returned.
385
354
  #
386
- # Options are passed to the underlying cache implementation.
355
+ # ==== Options
356
+ #
357
+ # * +:version+ - Specifies a version for the cache entry. If the cached
358
+ # version does not match the requested version, the read will be treated
359
+ # as a cache miss. This feature is used to support recyclable cache keys.
360
+ #
361
+ # Other options will be handled by the specific cache store implementation.
387
362
  def read(name, options = nil)
388
363
  options = merged_options(options)
389
364
  key = normalize_key(name, options)
@@ -491,9 +466,39 @@ module ActiveSupport
491
466
  end
492
467
  end
493
468
 
494
- # Writes the value to the cache, with the key.
469
+ # Writes the value to the cache with the key. The value must be supported
470
+ # by the +coder+'s +dump+ and +load+ methods.
495
471
  #
496
- # Options are passed to the underlying cache implementation.
472
+ # By default, cache entries larger than 1kB are compressed. Compression
473
+ # allows more data to be stored in the same memory footprint, leading to
474
+ # fewer cache evictions and higher hit rates.
475
+ #
476
+ # ==== Options
477
+ #
478
+ # * <tt>compress: false</tt> - Disables compression of the cache entry.
479
+ #
480
+ # * +:compress_threshold+ - The compression threshold, specified in bytes.
481
+ # \Cache entries larger than this threshold will be compressed. Defaults
482
+ # to +1.kilobyte+.
483
+ #
484
+ # * +:expires_in+ - Sets a relative expiration time for the cache entry,
485
+ # specified in seconds. +:expire_in+ and +:expired_in+ are aliases for
486
+ # +:expires_in+.
487
+ #
488
+ # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
489
+ # cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
490
+ #
491
+ # * +:expires_at+ - Sets an absolute expiration time for the cache entry.
492
+ #
493
+ # cache = ActiveSupport::Cache::MemoryStore.new
494
+ # cache.write(key, value, expires_at: Time.now.at_end_of_hour)
495
+ #
496
+ # * +:version+ - Specifies a version for the cache entry. When reading
497
+ # from the cache, if the cached version does not match the requested
498
+ # version, the read will be treated as a cache miss. This feature is
499
+ # used to support recyclable cache keys.
500
+ #
501
+ # Other options will be handled by the specific cache store implementation.
497
502
  def write(name, value, options = nil)
498
503
  options = merged_options(options)
499
504
 
@@ -569,7 +574,7 @@ module ActiveSupport
569
574
  raise NotImplementedError.new("#{self.class.name} does not support decrement")
570
575
  end
571
576
 
572
- # Cleanups the cache by removing expired entries.
577
+ # Cleans up the cache by removing expired entries.
573
578
  #
574
579
  # Options are passed to the underlying cache implementation.
575
580
  #
@@ -838,7 +843,7 @@ module ActiveSupport
838
843
  when 7.0
839
844
  Rails70Coder
840
845
  else
841
- raise ArgumentError, "Unknown ActiveSupport::Cache.format_version #{Cache.format_version.inspect}"
846
+ raise ArgumentError, "Unknown ActiveSupport::Cache.format_version: #{Cache.format_version.inspect}"
842
847
  end
843
848
  end
844
849
  end
@@ -114,10 +114,10 @@ module ActiveSupport
114
114
  raise ArgumentError, "#{behavior.inspect} is not a valid deprecation behavior."
115
115
  end
116
116
 
117
- if behavior.arity == 4 || behavior.arity == -1
118
- behavior
119
- else
117
+ if behavior.respond_to?(:arity) && behavior.arity == 2
120
118
  -> message, callstack, _, _ { behavior.call(message, callstack) }
119
+ else
120
+ behavior
121
121
  end
122
122
  end
123
123
  end
@@ -45,10 +45,22 @@ module ActiveSupport
45
45
  @env_key, @raise_if_missing_key = env_key, raise_if_missing_key
46
46
  end
47
47
 
48
+ # Returns the encryption key, first trying the environment variable
49
+ # specified by +env_key+, then trying the key file specified by +key_path+.
50
+ # If +raise_if_missing_key+ is true, raises MissingKeyError if the
51
+ # environment variable is not set and the key file does not exist.
48
52
  def key
49
53
  read_env_key || read_key_file || handle_missing_key
50
54
  end
51
55
 
56
+ # Reads the file and returns the decrypted content.
57
+ #
58
+ # Raises:
59
+ # - MissingKeyError if the key is missing and +raise_if_missing_key+ is true.
60
+ # - MissingContentError if the encrypted file does not exist or otherwise
61
+ # if the key is missing.
62
+ # - ActiveSupport::MessageEncryptor::InvalidMessage if the content cannot be
63
+ # decrypted or verified.
52
64
  def read
53
65
  if !key.nil? && content_path.exist?
54
66
  decrypt content_path.binread
@@ -9,7 +9,7 @@ module ActiveSupport
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
- TINY = 3
12
+ TINY = 4
13
13
  PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -97,7 +97,7 @@ module ActiveSupport
97
97
  return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
98
98
  word = camel_cased_word.to_s.gsub("::", "/")
99
99
  word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
100
- word.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
100
+ word.gsub!(/([A-Z])(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
101
101
  word.tr!("-", "_")
102
102
  word.downcase!
103
103
  word
@@ -26,6 +26,18 @@ module ActiveSupport
26
26
  # run_load_hooks will then execute all the hooks that were registered
27
27
  # with the on_load method. In the case of the above example, it will
28
28
  # execute the block of code that is in the +initializer+.
29
+ #
30
+ # Registering a hook that has already run results in that hook executing
31
+ # immediately. This allows hooks to be nested for code that relies on
32
+ # multiple lazily loaded components:
33
+ #
34
+ # initializer "action_text.renderer" do
35
+ # ActiveSupport.on_load(:action_controller_base) do
36
+ # ActiveSupport.on_load(:action_text_content) do
37
+ # self.default_renderer = Class.new(ActionController::Base).renderer
38
+ # end
39
+ # end
40
+ # end
29
41
  module LazyLoadHooks
30
42
  def self.extended(base) # :nodoc:
31
43
  base.class_eval do
@@ -36,7 +48,8 @@ module ActiveSupport
36
48
  end
37
49
 
38
50
  # Declares a block that will be executed when a Rails component is fully
39
- # loaded.
51
+ # loaded. If the component has already loaded, the block is executed
52
+ # immediately.
40
53
  #
41
54
  # Options:
42
55
  #
@@ -22,10 +22,6 @@ module ActiveSupport
22
22
  # Broadcasts logs to multiple loggers.
23
23
  def self.broadcast(logger) # :nodoc:
24
24
  Module.new do
25
- define_singleton_method(:extended) do |base|
26
- base.public_send(:broadcast_to, logger) if base.respond_to?(:broadcast_to)
27
- end
28
-
29
25
  define_method(:add) do |*args, &block|
30
26
  logger.add(*args, &block)
31
27
  super(*args, &block)
@@ -46,6 +42,11 @@ module ActiveSupport
46
42
  super(name)
47
43
  end
48
44
 
45
+ define_method(:formatter=) do |formatter|
46
+ logger.formatter = formatter
47
+ super(formatter)
48
+ end
49
+
49
50
  define_method(:level=) do |level|
50
51
  logger.level = level
51
52
  super(level)
@@ -244,6 +244,12 @@ module ActiveSupport
244
244
  notifier.subscribe(pattern, callback, monotonic: false, &block)
245
245
  end
246
246
 
247
+ # Performs the same functionality as #subscribe, but the +start+ and
248
+ # +finish+ block arguments are in monotonic time instead of wall-clock
249
+ # time. Monotonic time will not jump forward or backward (due to NTP or
250
+ # Daylights Savings). Use +monotonic_subscribe+ when accuracy of time
251
+ # duration is important. For example, computing elapsed time between
252
+ # two events.
247
253
  def monotonic_subscribe(pattern = nil, callback = nil, &block)
248
254
  notifier.subscribe(pattern, callback, monotonic: true, &block)
249
255
  end
@@ -15,8 +15,8 @@ module ActiveSupport
15
15
  private
16
16
  def method_missing(method, *arguments, &block)
17
17
  options = nil
18
- if arguments.first.is_a?(Proc)
19
- proc = arguments.pop
18
+ if arguments.size == 1 && arguments.first.is_a?(Proc)
19
+ proc = arguments.shift
20
20
  arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
21
21
  elsif arguments.last.respond_to?(:to_hash)
22
22
  options = @options.deep_merge(arguments.pop)
@@ -30,20 +30,20 @@ module ActiveSupport
30
30
  # any.
31
31
  #
32
32
  # class ApplicationController < ActionController::Base
33
- # rescue_from User::NotAuthorized, with: :deny_access # self defined exception
34
- # rescue_from ActiveRecord::RecordInvalid, with: :show_errors
33
+ # rescue_from User::NotAuthorized, with: :deny_access
34
+ # rescue_from ActiveRecord::RecordInvalid, with: :show_record_errors
35
35
  #
36
- # rescue_from 'MyAppError::Base' do |exception|
37
- # render xml: exception, status: 500
36
+ # rescue_from "MyApp::BaseError" do |exception|
37
+ # redirect_to root_url, alert: exception.message
38
38
  # end
39
39
  #
40
40
  # private
41
41
  # def deny_access
42
- # ...
42
+ # head :forbidden
43
43
  # end
44
44
  #
45
- # def show_errors(exception)
46
- # exception.record.new_record? ? ...
45
+ # def show_record_errors(exception)
46
+ # redirect_back_or_to root_url, alert: exception.record.errors.full_messages.to_sentence
47
47
  # end
48
48
  # end
49
49
  #
@@ -79,7 +79,7 @@ module ActiveSupport
79
79
  # Be sure to re-raise unhandled exceptions if this is what you expect.
80
80
  #
81
81
  # begin
82
- #
82
+ # # ...
83
83
  # rescue => exception
84
84
  # rescue_with_handler(exception) || raise
85
85
  # end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/module/delegation"
4
- require "active_support/core_ext/module/redefine_method"
5
4
  require "active_support/core_ext/object/blank"
6
5
  require "logger"
7
6
  require "active_support/logger"
@@ -95,20 +94,6 @@ module ActiveSupport
95
94
 
96
95
  delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
97
96
 
98
- def broadcast_to(other_logger) # :nodoc:
99
- define_singleton_method(:formatter=) do |formatter|
100
- other_logger.formatter ||= formatter
101
-
102
- other_logger.formatter.singleton_class.redefine_method(:current_tags) do
103
- formatter.current_tags
104
- end
105
-
106
- super(formatter)
107
- end
108
-
109
- self.formatter = self.formatter.clone
110
- end
111
-
112
97
  def tagged(*tags)
113
98
  if block_given?
114
99
  formatter.tagged(*tags) { yield self }
@@ -147,5 +147,9 @@ module ActiveSupport
147
147
  alias :assert_not_same :refute_same
148
148
 
149
149
  ActiveSupport.run_load_hooks(:active_support_test_case, self)
150
+
151
+ def inspect # :nodoc:
152
+ Object.instance_method(:to_s).bind_call(self)
153
+ end
150
154
  end
151
155
  end
@@ -337,9 +337,8 @@ module ActiveSupport
337
337
  alias_method :in, :+
338
338
 
339
339
  # Subtracts an interval of time and returns a new TimeWithZone object unless
340
- # the other value +acts_like?+ time. Then it will return a Float of the difference
341
- # between the two times that represents the difference between the current
342
- # object's time and the +other+ time.
340
+ # the other value +acts_like?+ time. In which case, it will subtract the
341
+ # other time and return the difference in seconds as a Float.
343
342
  #
344
343
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
345
344
  # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
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.0.3.1
4
+ version: 7.0.4.1
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: 2022-07-12 00:00:00.000000000 Z
11
+ date: 2023-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -359,10 +359,10 @@ licenses:
359
359
  - MIT
360
360
  metadata:
361
361
  bug_tracker_uri: https://github.com/rails/rails/issues
362
- changelog_uri: https://github.com/rails/rails/blob/v7.0.3.1/activesupport/CHANGELOG.md
363
- documentation_uri: https://api.rubyonrails.org/v7.0.3.1/
362
+ changelog_uri: https://github.com/rails/rails/blob/v7.0.4.1/activesupport/CHANGELOG.md
363
+ documentation_uri: https://api.rubyonrails.org/v7.0.4.1/
364
364
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
365
- source_code_uri: https://github.com/rails/rails/tree/v7.0.3.1/activesupport
365
+ source_code_uri: https://github.com/rails/rails/tree/v7.0.4.1/activesupport
366
366
  rubygems_mfa_required: 'true'
367
367
  post_install_message:
368
368
  rdoc_options:
@@ -381,7 +381,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
381
381
  - !ruby/object:Gem::Version
382
382
  version: '0'
383
383
  requirements: []
384
- rubygems_version: 3.3.3
384
+ rubygems_version: 3.4.3
385
385
  signing_key:
386
386
  specification_version: 4
387
387
  summary: A toolkit of support libraries and Ruby core extensions extracted from the