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 +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/active_support/cache/mem_cache_store.rb +16 -0
- data/lib/active_support/cache/redis_cache_store.rb +12 -6
- data/lib/active_support/cache.rb +118 -113
- data/lib/active_support/deprecation/behaviors.rb +3 -3
- data/lib/active_support/encrypted_file.rb +12 -0
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/inflector/methods.rb +1 -1
- data/lib/active_support/lazy_load_hooks.rb +14 -1
- data/lib/active_support/logger.rb +5 -4
- data/lib/active_support/notifications.rb +6 -0
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/rescuable.rb +8 -8
- data/lib/active_support/tagged_logging.rb +0 -15
- data/lib/active_support/test_case.rb +4 -0
- data/lib/active_support/time_with_zone.rb +2 -3
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9470ff58694a134f22c189060593e6c108b738bfe7ad4b6e30f8baac494879e
|
4
|
+
data.tar.gz: bf6ec0c4573ad54d38d8ad108869736d2308c1c8b4561110b5ecd8dc8550e852
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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\", \"
|
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
|
-
|
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
|
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
|
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(
|
109
|
-
::Redis.new
|
114
|
+
def build_redis_client(**redis_options)
|
115
|
+
::Redis.new(DEFAULT_REDIS_OPTIONS.merge(redis_options))
|
110
116
|
end
|
111
117
|
end
|
112
118
|
|
data/lib/active_support/cache.rb
CHANGED
@@ -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
|
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.
|
204
|
-
#
|
205
|
-
#
|
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
|
-
#
|
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
|
-
#
|
253
|
-
#
|
254
|
-
#
|
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
|
-
#
|
328
|
-
#
|
329
|
-
#
|
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
|
-
#
|
334
|
-
#
|
335
|
-
#
|
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
|
-
#
|
340
|
-
#
|
341
|
-
#
|
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
|
-
#
|
344
|
-
#
|
345
|
-
#
|
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
|
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
|
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
|
-
#
|
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
|
-
#
|
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
|
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
|
@@ -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]
|
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.
|
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
|
34
|
-
# rescue_from ActiveRecord::RecordInvalid, with: :
|
33
|
+
# rescue_from User::NotAuthorized, with: :deny_access
|
34
|
+
# rescue_from ActiveRecord::RecordInvalid, with: :show_record_errors
|
35
35
|
#
|
36
|
-
# rescue_from
|
37
|
-
#
|
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
|
46
|
-
# exception.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 }
|
@@ -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.
|
341
|
-
#
|
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.
|
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:
|
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.
|
363
|
-
documentation_uri: https://api.rubyonrails.org/v7.0.
|
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.
|
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.
|
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
|