activesupport 7.0.2.4 → 7.0.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/cache/mem_cache_store.rb +21 -5
- data/lib/active_support/cache/memory_store.rb +1 -1
- data/lib/active_support/cache/redis_cache_store.rb +17 -11
- data/lib/active_support/cache/strategy/local_cache.rb +3 -0
- data/lib/active_support/cache.rb +122 -114
- data/lib/active_support/callbacks.rb +5 -5
- data/lib/active_support/configurable.rb +2 -2
- data/lib/active_support/core_ext/array/conversions.rb +0 -1
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/date/calculations.rb +5 -5
- data/lib/active_support/core_ext/date/conversions.rb +3 -3
- data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +26 -9
- data/lib/active_support/core_ext/hash/conversions.rb +0 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +4 -4
- data/lib/active_support/core_ext/numeric/conversions.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +1 -1
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +3 -3
- data/lib/active_support/core_ext/time/calculations.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +3 -3
- data/lib/active_support/deprecation/behaviors.rb +4 -4
- data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/encrypted_file.rb +12 -0
- data/lib/active_support/error_reporter.rb +2 -2
- data/lib/active_support/evented_file_update_checker.rb +2 -4
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/inflector/transliterate.rb +1 -1
- data/lib/active_support/isolated_execution_state.rb +8 -0
- data/lib/active_support/key_generator.rb +4 -4
- data/lib/active_support/lazy_load_hooks.rb +28 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +2 -2
- data/lib/active_support/message_encryptor.rb +4 -3
- data/lib/active_support/notifications.rb +8 -2
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/railtie.rb +5 -5
- data/lib/active_support/rescuable.rb +10 -10
- data/lib/active_support/secure_compare_rotator.rb +1 -1
- data/lib/active_support/test_case.rb +4 -0
- data/lib/active_support/testing/assertions.rb +1 -1
- data/lib/active_support/time_with_zone.rb +6 -7
- data/lib/active_support/values/time_zone.rb +5 -5
- data/lib/active_support/version.rb +1 -1
- 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: 342ae35dc85cf68674201fd516c85b208adccc0c930e888d301d0ed5fa9e2cad
|
4
|
+
data.tar.gz: 8c611de7bc5d9ea07c57a1848abb556e9090009db790404fa1da49278a49d0b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68144c1574e6fe740072399749fef96a992ad390c5877a63110758a7184256882e118d9dc5290150b2b623a391a37ab8c2648e49782ae2f9b3c42cb9e21837c4
|
7
|
+
data.tar.gz: 6906af5f3a19a04f13ec6ca1c8f492259018181ad3bcb63eb75bdb8cf2fe7316a6dd787125de809cfc04a7dd72ff310f673001f69865b0753fcc571966b8b573
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
## Rails 7.0.4 (September 09, 2022) ##
|
2
|
+
|
3
|
+
* Redis cache store is now compatible with redis-rb 5.0.
|
4
|
+
|
5
|
+
*Jean Boussier*
|
6
|
+
|
7
|
+
* Fix `NoMethodError` on custom `ActiveSupport::Deprecation` behavior.
|
8
|
+
|
9
|
+
`ActiveSupport::Deprecation.behavior=` was supposed to accept any object
|
10
|
+
that responds to `call`, but in fact its internal implementation assumed that
|
11
|
+
this object could respond to `arity`, so it was restricted to only `Proc` objects.
|
12
|
+
|
13
|
+
This change removes this `arity` restriction of custom behaviors.
|
14
|
+
|
15
|
+
*Ryo Nakamura*
|
16
|
+
|
17
|
+
|
18
|
+
## Rails 7.0.3.1 (July 12, 2022) ##
|
19
|
+
|
20
|
+
* No changes.
|
21
|
+
|
22
|
+
|
23
|
+
## Rails 7.0.3 (May 09, 2022) ##
|
24
|
+
|
25
|
+
* No changes.
|
26
|
+
|
27
|
+
|
1
28
|
## Rails 7.0.2.4 (April 26, 2022) ##
|
2
29
|
|
3
30
|
* Fix and add protections for XSS in `ActionView::Helpers` and `ERB::Util`.
|
@@ -21,10 +21,10 @@ module ActiveSupport
|
|
21
21
|
#
|
22
22
|
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
23
23
|
# and show as much data as possible, you can always call
|
24
|
-
#
|
24
|
+
# BacktraceCleaner#remove_silencers!, which will restore the
|
25
25
|
# backtrace to a pristine state. If you need to reconfigure an existing
|
26
26
|
# BacktraceCleaner so that it does not filter or modify the paths of any lines
|
27
|
-
# of the backtrace, you can call
|
27
|
+
# of the backtrace, you can call BacktraceCleaner#remove_filters!
|
28
28
|
# These two methods will give you a completely untouched backtrace.
|
29
29
|
#
|
30
30
|
# Inspired by the Quiet Backtrace gem by thoughtbot.
|
@@ -104,7 +104,7 @@ module ActiveSupport
|
|
104
104
|
#
|
105
105
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
106
106
|
#
|
107
|
-
# If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
|
107
|
+
# If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
|
108
108
|
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
109
109
|
def initialize(*addresses)
|
110
110
|
addresses = addresses.flatten
|
@@ -128,9 +128,25 @@ 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
|
-
# operator and can only be used on values written with the
|
133
|
-
# Calling it on a value not stored with
|
148
|
+
# operator and can only be used on values written with the +:raw+ option.
|
149
|
+
# Calling it on a value not stored with +:raw+ will initialize that value
|
134
150
|
# to zero.
|
135
151
|
def increment(name, amount = 1, options = nil)
|
136
152
|
options = merged_options(options)
|
@@ -142,8 +158,8 @@ module ActiveSupport
|
|
142
158
|
end
|
143
159
|
|
144
160
|
# Decrement a cached value. This method uses the memcached decr atomic
|
145
|
-
# operator and can only be used on values written with the
|
146
|
-
# Calling it on a value not stored with
|
161
|
+
# operator and can only be used on values written with the +:raw+ option.
|
162
|
+
# Calling it on a value not stored with +:raw+ will initialize that value
|
147
163
|
# to zero.
|
148
164
|
def decrement(name, amount = 1, options = nil)
|
149
165
|
options = merged_options(options)
|
@@ -11,7 +11,7 @@ module ActiveSupport
|
|
11
11
|
# to share cache data with each other and this may not be the most
|
12
12
|
# appropriate cache in that scenario.
|
13
13
|
#
|
14
|
-
# This cache has a bounded size specified by the
|
14
|
+
# This cache has a bounded size specified by the +:size+ options to the
|
15
15
|
# initializer (default is 32Mb). When the cache exceeds the allotted size,
|
16
16
|
# a cleanup will occur which tries to prune the cache down to three quarters
|
17
17
|
# of the maximum size by removing the least recently used entries.
|
@@ -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
|
|
@@ -139,7 +145,7 @@ module ActiveSupport
|
|
139
145
|
#
|
140
146
|
# Race condition TTL is not set by default. This can be used to avoid
|
141
147
|
# "thundering herd" cache writes when hot cache entries are expired.
|
142
|
-
# See
|
148
|
+
# See ActiveSupport::Cache::Store#fetch for more.
|
143
149
|
def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, coder: default_coder, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
|
144
150
|
@redis_options = redis_options
|
145
151
|
|
@@ -225,8 +231,8 @@ module ActiveSupport
|
|
225
231
|
# Cache Store API implementation.
|
226
232
|
#
|
227
233
|
# Increment a cached value. This method uses the Redis incr atomic
|
228
|
-
# operator and can only be used on values written with the
|
229
|
-
# Calling it on a value not stored with
|
234
|
+
# operator and can only be used on values written with the +:raw+ option.
|
235
|
+
# Calling it on a value not stored with +:raw+ will initialize that value
|
230
236
|
# to zero.
|
231
237
|
#
|
232
238
|
# Failsafe: Raises errors.
|
@@ -248,8 +254,8 @@ module ActiveSupport
|
|
248
254
|
# Cache Store API implementation.
|
249
255
|
#
|
250
256
|
# Decrement a cached value. This method uses the Redis decr atomic
|
251
|
-
# operator and can only be used on values written with the
|
252
|
-
# Calling it on a value not stored with
|
257
|
+
# operator and can only be used on values written with the +:raw+ option.
|
258
|
+
# Calling it on a value not stored with +:raw+ will initialize that value
|
253
259
|
# to zero.
|
254
260
|
#
|
255
261
|
# Failsafe: Raises errors.
|
@@ -123,6 +123,9 @@ module ActiveSupport
|
|
123
123
|
return super unless local_cache
|
124
124
|
|
125
125
|
local_entries = local_cache.read_multi_entries(keys)
|
126
|
+
local_entries.transform_values! do |payload|
|
127
|
+
deserialize_entry(payload).value
|
128
|
+
end
|
126
129
|
missed_keys = keys - local_entries.keys
|
127
130
|
|
128
131
|
if missed_keys.any?
|
data/lib/active_support/cache.rb
CHANGED
@@ -139,9 +139,10 @@ 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
|
-
# ActiveSupport::Cache::Store can store any
|
144
|
+
# ActiveSupport::Cache::Store can store any Ruby object that is supported by
|
145
|
+
# its +coder+'s +dump+ and +load+ methods.
|
145
146
|
#
|
146
147
|
# cache = ActiveSupport::Cache::MemoryStore.new
|
147
148
|
#
|
@@ -149,6 +150,8 @@ module ActiveSupport
|
|
149
150
|
# cache.write('city', "Duckburgh")
|
150
151
|
# cache.read('city') # => "Duckburgh"
|
151
152
|
#
|
153
|
+
# cache.write('not serializable', Proc.new {}) # => TypeError
|
154
|
+
#
|
152
155
|
# Keys are always translated into Strings and are case sensitive. When an
|
153
156
|
# object is specified as a key and has a +cache_key+ method defined, this
|
154
157
|
# method will be called to define the key. Otherwise, the +to_param+
|
@@ -169,11 +172,6 @@ module ActiveSupport
|
|
169
172
|
# cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
|
170
173
|
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
|
171
174
|
#
|
172
|
-
# Cached data larger than 1kB are compressed by default. To turn off
|
173
|
-
# compression, pass <tt>compress: false</tt> to the initializer or to
|
174
|
-
# individual +fetch+ or +write+ method calls. The 1kB compression
|
175
|
-
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
176
|
-
# specified in bytes.
|
177
175
|
class Store
|
178
176
|
cattr_accessor :logger, instance_writer: true
|
179
177
|
|
@@ -197,9 +195,19 @@ module ActiveSupport
|
|
197
195
|
end
|
198
196
|
end
|
199
197
|
|
200
|
-
# Creates a new cache.
|
201
|
-
#
|
202
|
-
#
|
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.
|
203
211
|
def initialize(options = nil)
|
204
212
|
@options = options ? normalize_options(options) : {}
|
205
213
|
@options[:compress] = true unless @options.key?(:compress)
|
@@ -241,111 +249,75 @@ module ActiveSupport
|
|
241
249
|
# end
|
242
250
|
# cache.fetch('city') # => "Duckburgh"
|
243
251
|
#
|
244
|
-
#
|
245
|
-
# Setting <tt>force: true</tt> forces a cache "miss," meaning we treat
|
246
|
-
# the cache value as missing even if it's present. Passing a block is
|
247
|
-
# required when +force+ is true so this always results in a cache write.
|
252
|
+
# ==== Options
|
248
253
|
#
|
249
|
-
#
|
250
|
-
#
|
251
|
-
#
|
252
|
-
#
|
253
|
-
# The +:force+ option is useful when you're calling some other method to
|
254
|
-
# ask whether you should force a cache write. Otherwise, it's clearer to
|
255
|
-
# just call <tt>Cache#write</tt>.
|
256
|
-
#
|
257
|
-
# Setting <tt>skip_nil: true</tt> will not cache nil result:
|
258
|
-
#
|
259
|
-
# cache.fetch('foo') { nil }
|
260
|
-
# cache.fetch('bar', skip_nil: true) { nil }
|
261
|
-
# cache.exist?('foo') # => true
|
262
|
-
# cache.exist?('bar') # => false
|
263
|
-
#
|
264
|
-
#
|
265
|
-
# Setting <tt>compress: false</tt> disables compression of the cache entry.
|
266
|
-
#
|
267
|
-
# Setting <tt>:expires_in</tt> will set an expiration time on the cache.
|
268
|
-
# All caches support auto-expiring content after a specified number of
|
269
|
-
# seconds. This value can be specified as an option to the constructor
|
270
|
-
# (in which case all entries will be affected), or it can be supplied to
|
271
|
-
# the +fetch+ or +write+ method to affect just one entry.
|
272
|
-
# <tt>:expire_in</tt> and <tt>:expired_in</tt> are aliases for
|
273
|
-
# <tt>:expires_in</tt>.
|
274
|
-
#
|
275
|
-
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
276
|
-
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
|
277
|
-
#
|
278
|
-
# Setting <tt>:expires_at</tt> will set an absolute expiration time on the cache.
|
279
|
-
# All caches support auto-expiring content after a specified number of
|
280
|
-
# seconds. This value can only be supplied to the +fetch+ or +write+ method to
|
281
|
-
# affect just one entry.
|
282
|
-
#
|
283
|
-
# cache = ActiveSupport::Cache::MemoryStore.new
|
284
|
-
# cache.write(key, value, expires_at: Time.now.at_end_of_hour)
|
285
|
-
#
|
286
|
-
# Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
|
287
|
-
# is of the same version. nil is returned on mismatches despite contents.
|
288
|
-
# This feature is used to support recyclable cache keys.
|
289
|
-
#
|
290
|
-
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where
|
291
|
-
# a cache entry is used very frequently and is under heavy load. If a
|
292
|
-
# cache expires and due to heavy load several different processes will try
|
293
|
-
# to read data natively and then they all will try to write to cache. To
|
294
|
-
# avoid that case the first process to find an expired cache entry will
|
295
|
-
# bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>.
|
296
|
-
# Yes, this process is extending the time for a stale value by another few
|
297
|
-
# seconds. Because of extended life of the previous cache, other processes
|
298
|
-
# will continue to use slightly stale data for a just a bit longer. In the
|
299
|
-
# meantime that first process will go ahead and will write into cache the
|
300
|
-
# new value. After that all the processes will start getting the new value.
|
301
|
-
# The key is to keep <tt>:race_condition_ttl</tt> small.
|
302
|
-
#
|
303
|
-
# If the process regenerating the entry errors out, the entry will be
|
304
|
-
# regenerated after the specified number of seconds. Also note that the
|
305
|
-
# life of stale cache is extended only if it expired recently. Otherwise
|
306
|
-
# a new value is generated and <tt>:race_condition_ttl</tt> does not play
|
307
|
-
# any role.
|
308
|
-
#
|
309
|
-
# # Set all values to expire after one minute.
|
310
|
-
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
|
311
|
-
#
|
312
|
-
# cache.write('foo', 'original value')
|
313
|
-
# val_1 = nil
|
314
|
-
# val_2 = nil
|
315
|
-
# sleep 60
|
316
|
-
#
|
317
|
-
# Thread.new do
|
318
|
-
# val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
|
319
|
-
# sleep 1
|
320
|
-
# 'new value 1'
|
321
|
-
# end
|
322
|
-
# 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:
|
323
257
|
#
|
324
|
-
#
|
325
|
-
#
|
326
|
-
#
|
327
|
-
# end
|
328
|
-
# 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.
|
329
261
|
#
|
330
|
-
#
|
331
|
-
#
|
332
|
-
#
|
333
|
-
# val_1 # => "new value 1"
|
334
|
-
# val_2 # => "original value"
|
262
|
+
# cache.write('today', 'Monday')
|
263
|
+
# cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday'
|
264
|
+
# cache.fetch('today', force: true) # => ArgumentError
|
335
265
|
#
|
336
|
-
#
|
337
|
-
#
|
338
|
-
#
|
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+.
|
339
269
|
#
|
340
|
-
#
|
341
|
-
#
|
342
|
-
#
|
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"
|
343
320
|
#
|
344
|
-
# cache = ActiveSupport::Cache::MemCacheStore.new
|
345
|
-
# cache.fetch("foo", force: true, raw: true) do
|
346
|
-
# :bar
|
347
|
-
# end
|
348
|
-
# cache.fetch('foo') # => "bar"
|
349
321
|
def fetch(name, options = nil, &block)
|
350
322
|
if block_given?
|
351
323
|
options = merged_options(options)
|
@@ -380,7 +352,13 @@ module ActiveSupport
|
|
380
352
|
# <tt>:version</tt> options, both of these conditions are applied before
|
381
353
|
# the data is returned.
|
382
354
|
#
|
383
|
-
# 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.
|
384
362
|
def read(name, options = nil)
|
385
363
|
options = merged_options(options)
|
386
364
|
key = normalize_key(name, options)
|
@@ -488,9 +466,39 @@ module ActiveSupport
|
|
488
466
|
end
|
489
467
|
end
|
490
468
|
|
491
|
-
# 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.
|
492
471
|
#
|
493
|
-
#
|
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.
|
494
502
|
def write(name, value, options = nil)
|
495
503
|
options = merged_options(options)
|
496
504
|
|
@@ -566,7 +574,7 @@ module ActiveSupport
|
|
566
574
|
raise NotImplementedError.new("#{self.class.name} does not support decrement")
|
567
575
|
end
|
568
576
|
|
569
|
-
#
|
577
|
+
# Cleans up the cache by removing expired entries.
|
570
578
|
#
|
571
579
|
# Options are passed to the underlying cache implementation.
|
572
580
|
#
|
@@ -835,7 +843,7 @@ module ActiveSupport
|
|
835
843
|
when 7.0
|
836
844
|
Rails70Coder
|
837
845
|
else
|
838
|
-
raise ArgumentError, "Unknown ActiveSupport::Cache.format_version #{Cache.format_version.inspect}"
|
846
|
+
raise ArgumentError, "Unknown ActiveSupport::Cache.format_version: #{Cache.format_version.inspect}"
|
839
847
|
end
|
840
848
|
end
|
841
849
|
end
|
@@ -16,19 +16,19 @@ module ActiveSupport
|
|
16
16
|
# needing to override or redefine methods of the base class.
|
17
17
|
#
|
18
18
|
# Mixing in this module allows you to define the events in the object's
|
19
|
-
# life cycle that will support callbacks (via
|
19
|
+
# life cycle that will support callbacks (via ClassMethods#define_callbacks),
|
20
20
|
# set the instance methods, procs, or callback objects to be called (via
|
21
|
-
#
|
21
|
+
# ClassMethods#set_callback), and run the installed callbacks at the
|
22
22
|
# appropriate times (via +run_callbacks+).
|
23
23
|
#
|
24
24
|
# By default callbacks are halted by throwing +:abort+.
|
25
|
-
# See
|
25
|
+
# See ClassMethods#define_callbacks for details.
|
26
26
|
#
|
27
27
|
# Three kinds of callbacks are supported: before callbacks, run before a
|
28
28
|
# certain event; after callbacks, run after the event; and around callbacks,
|
29
29
|
# blocks that surround the event, triggering it when they yield. Callback code
|
30
30
|
# can be contained in instance methods, procs or lambdas, or callback objects
|
31
|
-
# that respond to certain predetermined methods. See
|
31
|
+
# that respond to certain predetermined methods. See ClassMethods#set_callback
|
32
32
|
# for details.
|
33
33
|
#
|
34
34
|
# class Record
|
@@ -600,7 +600,7 @@ module ActiveSupport
|
|
600
600
|
end
|
601
601
|
end
|
602
602
|
|
603
|
-
class CallbackChain # :nodoc
|
603
|
+
class CallbackChain # :nodoc:
|
604
604
|
include Enumerable
|
605
605
|
|
606
606
|
attr_reader :name, :config
|
@@ -5,7 +5,7 @@ require "active_support/ordered_options"
|
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
# Configurable provides a <tt>config</tt> method to store and retrieve
|
8
|
-
# configuration options as an
|
8
|
+
# configuration options as an OrderedOptions.
|
9
9
|
module Configurable
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
@@ -127,7 +127,7 @@ module ActiveSupport
|
|
127
127
|
private :config_accessor
|
128
128
|
end
|
129
129
|
|
130
|
-
# Reads and writes attributes from a configuration
|
130
|
+
# Reads and writes attributes from a configuration OrderedOptions.
|
131
131
|
#
|
132
132
|
# require "active_support/configurable"
|
133
133
|
#
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require "active_support/array_inquirer"
|
4
4
|
|
5
5
|
class Array
|
6
|
-
# Wraps the array in an
|
7
|
-
# to check its string-like contents.
|
6
|
+
# Wraps the array in an ActiveSupport::ArrayInquirer object, which gives a
|
7
|
+
# friendlier way to check its string-like contents.
|
8
8
|
#
|
9
9
|
# pets = [:cat, :dog].inquiry
|
10
10
|
#
|
@@ -13,22 +13,22 @@ class Date
|
|
13
13
|
class << self
|
14
14
|
attr_accessor :beginning_of_week_default
|
15
15
|
|
16
|
-
# Returns the week start (e.g.
|
16
|
+
# Returns the week start (e.g. +:monday+) for the current request, if this has been set (via Date.beginning_of_week=).
|
17
17
|
# If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
|
18
|
-
# If no config.beginning_of_week was specified, returns
|
18
|
+
# If no +config.beginning_of_week+ was specified, returns +:monday+.
|
19
19
|
def beginning_of_week
|
20
20
|
::ActiveSupport::IsolatedExecutionState[:beginning_of_week] || beginning_of_week_default || :monday
|
21
21
|
end
|
22
22
|
|
23
|
-
# Sets <tt>Date.beginning_of_week</tt> to a week start (e.g.
|
23
|
+
# Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. +:monday+) for current request/thread.
|
24
24
|
#
|
25
25
|
# This method accepts any of the following day symbols:
|
26
|
-
#
|
26
|
+
# +:monday+, +:tuesday+, +:wednesday+, +:thursday+, +:friday+, +:saturday+, +:sunday+
|
27
27
|
def beginning_of_week=(week_start)
|
28
28
|
::ActiveSupport::IsolatedExecutionState[:beginning_of_week] = find_beginning_of_week!(week_start)
|
29
29
|
end
|
30
30
|
|
31
|
-
# Returns week start day symbol (e.g.
|
31
|
+
# Returns week start day symbol (e.g. +:monday+), or raises an +ArgumentError+ for invalid day symbol.
|
32
32
|
def find_beginning_of_week!(week_start)
|
33
33
|
raise ArgumentError, "Invalid beginning of week: #{week_start}" unless ::Date::DAYS_INTO_WEEK.key?(week_start)
|
34
34
|
week_start
|
@@ -68,7 +68,7 @@ class Date
|
|
68
68
|
silence_redefinition_of_method :to_time
|
69
69
|
|
70
70
|
# Converts a Date instance to a Time, where the time is set to the beginning of the day.
|
71
|
-
# The timezone can be either
|
71
|
+
# The timezone can be either +:local+ or +:utc+ (default +:local+).
|
72
72
|
#
|
73
73
|
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
|
74
74
|
#
|
@@ -77,8 +77,8 @@ class Date
|
|
77
77
|
#
|
78
78
|
# date.to_time(:utc) # => 2007-11-10 00:00:00 UTC
|
79
79
|
#
|
80
|
-
# NOTE: The
|
81
|
-
#
|
80
|
+
# NOTE: The +:local+ timezone is Ruby's *process* timezone, i.e. <tt>ENV['TZ']</tt>.
|
81
|
+
# If the <b>application's</b> timezone is needed, then use +in_time_zone+ instead.
|
82
82
|
def to_time(form = :local)
|
83
83
|
raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form)
|
84
84
|
::Time.public_send(form, year, month, day)
|