activesupport 7.1.1 → 7.1.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +124 -0
- data/lib/active_support/broadcast_logger.rb +8 -0
- data/lib/active_support/cache/entry.rb +7 -1
- data/lib/active_support/cache/file_store.rb +1 -1
- data/lib/active_support/cache/mem_cache_store.rb +16 -8
- data/lib/active_support/cache/memory_store.rb +4 -4
- data/lib/active_support/cache/redis_cache_store.rb +21 -14
- data/lib/active_support/cache/strategy/local_cache.rb +9 -6
- data/lib/active_support/cache.rb +34 -7
- data/lib/active_support/core_ext/date/conversions.rb +1 -1
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/deprecation/behaviors.rb +18 -16
- data/lib/active_support/deprecation/reporting.rb +7 -4
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/html_safe_translation.rb +12 -2
- data/lib/active_support/inflector/methods.rb +2 -2
- data/lib/active_support/json/encoding.rb +1 -1
- data/lib/active_support/log_subscriber.rb +8 -2
- data/lib/active_support/messages/metadata.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +25 -19
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/number_helper.rb +379 -318
- data/lib/active_support/ordered_options.rb +2 -2
- data/lib/active_support/syntax_error_proxy.rb +22 -1
- data/lib/active_support/testing/assertions.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +1 -0
- data/lib/active_support/testing/time_helpers.rb +5 -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: 63e4b9598ffeea57d9aa5ab27deb5249cc21324883d53ad536bb02fd5d8e4526
|
4
|
+
data.tar.gz: 82041b4d7a4b287404280f004cc9a255ad55ec975682ceb4829be789bce352bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0e517fefe56838a7851ec1832ea1cb9fbc10aa392da9f3840ee7d71b0768d29825e03176b5358a5e098ed42686d0602bd13ebb08a750e6294992fb3ac845555
|
7
|
+
data.tar.gz: d58c4664ef7962fab547b4d5dc91e7cca0ac647b0b4e080c49129c06ca9d0604dc7d4ee2f9e0347a1100d435789923aafb94adfa49c6cb7f031e18b1e44d798f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,127 @@
|
|
1
|
+
## Rails 7.1.3.4 (June 04, 2024) ##
|
2
|
+
|
3
|
+
* No changes.
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 7.1.3.3 (May 16, 2024) ##
|
7
|
+
|
8
|
+
* No changes.
|
9
|
+
|
10
|
+
|
11
|
+
## Rails 7.1.3.2 (February 21, 2024) ##
|
12
|
+
|
13
|
+
* No changes.
|
14
|
+
|
15
|
+
|
16
|
+
## Rails 7.1.3.1 (February 21, 2024) ##
|
17
|
+
|
18
|
+
* No changes.
|
19
|
+
|
20
|
+
|
21
|
+
## Rails 7.1.3 (January 16, 2024) ##
|
22
|
+
|
23
|
+
* Handle nil `backtrace_locations` in `ActiveSupport::SyntaxErrorProxy`.
|
24
|
+
|
25
|
+
*Eugene Kenny*
|
26
|
+
|
27
|
+
* Fix `ActiveSupport::JSON.encode` to prevent duplicate keys.
|
28
|
+
|
29
|
+
If the same key exist in both String and Symbol form it could
|
30
|
+
lead to the same key being emitted twice.
|
31
|
+
|
32
|
+
*Manish Sharma*
|
33
|
+
|
34
|
+
* Fix `ActiveSupport::Cache::Store#read_multi` when using a cache namespace
|
35
|
+
and local cache strategy.
|
36
|
+
|
37
|
+
*Mark Oleson*
|
38
|
+
|
39
|
+
* Fix `Time.now/DateTime.now/Date.today` to return results in a system timezone after `#travel_to`.
|
40
|
+
|
41
|
+
There is a bug in the current implementation of #travel_to:
|
42
|
+
it remembers a timezone of its argument, and all stubbed methods start
|
43
|
+
returning results in that remembered timezone. However, the expected
|
44
|
+
behaviour is to return results in a system timezone.
|
45
|
+
|
46
|
+
*Aleksei Chernenkov*
|
47
|
+
|
48
|
+
* Fix `:unless_exist` option for `MemoryStore#write` (et al) when using a
|
49
|
+
cache namespace.
|
50
|
+
|
51
|
+
*S. Brent Faulkner*
|
52
|
+
|
53
|
+
* Fix ActiveSupport::Deprecation to handle blaming generated code.
|
54
|
+
|
55
|
+
*Jean Boussier*, *fatkodima*
|
56
|
+
|
57
|
+
|
58
|
+
## Rails 7.1.2 (November 10, 2023) ##
|
59
|
+
|
60
|
+
* Fix `:expires_in` option for `RedisCacheStore#write_multi`.
|
61
|
+
|
62
|
+
*fatkodima*
|
63
|
+
|
64
|
+
* Fix deserialization of non-string "purpose" field in Message serializer
|
65
|
+
|
66
|
+
*Jacopo Beschi*
|
67
|
+
|
68
|
+
* Prevent global cache options being overwritten when setting dynamic options
|
69
|
+
inside a `ActiveSupport::Cache::Store#fetch` block.
|
70
|
+
|
71
|
+
*Yasha Krasnou*
|
72
|
+
|
73
|
+
* Fix missing `require` resulting in `NoMethodError` when running
|
74
|
+
`bin/rails secrets:show` or `bin/rails secrets:edit`.
|
75
|
+
|
76
|
+
*Stephen Ierodiaconou*
|
77
|
+
|
78
|
+
* Ensure `{down,up}case_first` returns non-frozen string.
|
79
|
+
|
80
|
+
*Jonathan Hefner*
|
81
|
+
|
82
|
+
* Fix `#to_fs(:human_size)` to correctly work with negative numbers.
|
83
|
+
|
84
|
+
*Earlopain*
|
85
|
+
|
86
|
+
* Fix `BroadcastLogger#dup` so that it duplicates the logger's `broadcasts`.
|
87
|
+
|
88
|
+
*Andrew Novoselac*
|
89
|
+
|
90
|
+
* Fix issue where `bootstrap.rb` overwrites the `level` of a `BroadcastLogger`'s `broadcasts`.
|
91
|
+
|
92
|
+
*Andrew Novoselac*
|
93
|
+
|
94
|
+
* Fix `ActiveSupport::Cache` to handle outdated Marshal payload from Rails 6.1 format.
|
95
|
+
|
96
|
+
Active Support's Cache is supposed to treat a Marshal payload that can no longer be
|
97
|
+
deserialized as a cache miss. It fail to do so for compressed payload in the Rails 6.1
|
98
|
+
legacy format.
|
99
|
+
|
100
|
+
*Jean Boussier*
|
101
|
+
|
102
|
+
* Fix `OrderedOptions#dig` for array indexes.
|
103
|
+
|
104
|
+
*fatkodima*
|
105
|
+
|
106
|
+
* Fix time travel helpers to work when nested using with separate classes.
|
107
|
+
|
108
|
+
*fatkodima*
|
109
|
+
|
110
|
+
* Fix `delete_matched` for file cache store to work with keys longer than the
|
111
|
+
max filename size.
|
112
|
+
|
113
|
+
*fatkodima* and *Jonathan Hefner*
|
114
|
+
|
115
|
+
* Fix compatibility with the `semantic_logger` gem.
|
116
|
+
|
117
|
+
The `semantic_logger` gem doesn't behave exactly like stdlib logger in that
|
118
|
+
`SemanticLogger#level` returns a Symbol while stdlib `Logger#level` returns an Integer.
|
119
|
+
|
120
|
+
This caused the various `LogSubscriber` classes in Rails to break when assigned a
|
121
|
+
`SemanticLogger` instance.
|
122
|
+
|
123
|
+
*Jean Boussier*, *ojab*
|
124
|
+
|
1
125
|
## Rails 7.1.1 (October 11, 2023) ##
|
2
126
|
|
3
127
|
* Add support for keyword arguments when delegating calls to custom loggers from `ActiveSupport::BroadcastLogger`.
|
@@ -218,6 +218,14 @@ module ActiveSupport
|
|
218
218
|
dispatch { |logger| logger.fatal! }
|
219
219
|
end
|
220
220
|
|
221
|
+
def initialize_copy(other)
|
222
|
+
@broadcasts = []
|
223
|
+
@progname = other.progname.dup
|
224
|
+
@formatter = other.formatter.dup
|
225
|
+
|
226
|
+
broadcast_to(*other.broadcasts.map(&:dup))
|
227
|
+
end
|
228
|
+
|
221
229
|
private
|
222
230
|
def dispatch(&block)
|
223
231
|
@broadcasts.each { |logger| block.call(logger) }
|
@@ -121,7 +121,13 @@ module ActiveSupport
|
|
121
121
|
|
122
122
|
private
|
123
123
|
def uncompress(value)
|
124
|
-
|
124
|
+
marshal_load(Zlib::Inflate.inflate(value))
|
125
|
+
end
|
126
|
+
|
127
|
+
def marshal_load(payload)
|
128
|
+
Marshal.load(payload)
|
129
|
+
rescue ArgumentError => error
|
130
|
+
raise Cache::DeserializationError, error.message
|
125
131
|
end
|
126
132
|
end
|
127
133
|
end
|
@@ -176,7 +176,7 @@ module ActiveSupport
|
|
176
176
|
|
177
177
|
# Translate a file path into a key.
|
178
178
|
def file_path_key(path)
|
179
|
-
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
|
179
|
+
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last.delete(File::SEPARATOR)
|
180
180
|
URI.decode_www_form_component(fname, Encoding::UTF_8)
|
181
181
|
end
|
182
182
|
|
@@ -24,11 +24,11 @@ module ActiveSupport
|
|
24
24
|
#
|
25
25
|
# Special features:
|
26
26
|
# - Clustering and load balancing. One can specify multiple memcached servers,
|
27
|
-
# and MemCacheStore will load balance between all available servers. If a
|
28
|
-
# server goes down, then MemCacheStore will ignore it until it comes back up.
|
27
|
+
# and +MemCacheStore+ will load balance between all available servers. If a
|
28
|
+
# server goes down, then +MemCacheStore+ will ignore it until it comes back up.
|
29
29
|
#
|
30
|
-
# MemCacheStore implements the Strategy::LocalCache strategy which
|
31
|
-
# an in-memory cache inside of a block.
|
30
|
+
# +MemCacheStore+ implements the Strategy::LocalCache strategy which
|
31
|
+
# implements an in-memory cache inside of a block.
|
32
32
|
class MemCacheStore < Store
|
33
33
|
# These options represent behavior overridden by this implementation and should
|
34
34
|
# not be allowed to get down to the Dalli client
|
@@ -106,14 +106,14 @@ module ActiveSupport
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
-
# Creates a new MemCacheStore object, with the given memcached server
|
109
|
+
# Creates a new +MemCacheStore+ object, with the given memcached server
|
110
110
|
# addresses. Each address is either a host name, or a host-with-port string
|
111
111
|
# in the form of "host_name:port". For example:
|
112
112
|
#
|
113
113
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
114
114
|
#
|
115
115
|
# If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
|
116
|
-
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
116
|
+
# +MemCacheStore+ will connect to localhost:11211 (the default memcached port).
|
117
117
|
# Passing a +Dalli::Client+ instance is deprecated and will be removed. Please pass an address instead.
|
118
118
|
def initialize(*addresses)
|
119
119
|
addresses = addresses.flatten
|
@@ -270,14 +270,22 @@ module ActiveSupport
|
|
270
270
|
def read_multi_entries(names, **options)
|
271
271
|
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
272
272
|
|
273
|
-
raw_values =
|
273
|
+
raw_values = begin
|
274
|
+
@data.with { |c| c.get_multi(keys_to_names.keys) }
|
275
|
+
rescue Dalli::UnmarshalError
|
276
|
+
{}
|
277
|
+
end
|
278
|
+
|
274
279
|
values = {}
|
275
280
|
|
276
281
|
raw_values.each do |key, value|
|
277
282
|
entry = deserialize_entry(value, raw: options[:raw])
|
278
283
|
|
279
284
|
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
280
|
-
|
285
|
+
begin
|
286
|
+
values[keys_to_names[key]] = entry.value
|
287
|
+
rescue DeserializationError
|
288
|
+
end
|
281
289
|
end
|
282
290
|
end
|
283
291
|
|
@@ -18,13 +18,13 @@ module ActiveSupport
|
|
18
18
|
# a cleanup will occur which tries to prune the cache down to three quarters
|
19
19
|
# of the maximum size by removing the least recently used entries.
|
20
20
|
#
|
21
|
-
# Unlike other Cache store implementations, MemoryStore does not compress
|
22
|
-
# values by default. MemoryStore does not benefit from compression as much
|
21
|
+
# Unlike other Cache store implementations, +MemoryStore+ does not compress
|
22
|
+
# values by default. +MemoryStore+ does not benefit from compression as much
|
23
23
|
# as other Store implementations, as it does not send data over a network.
|
24
24
|
# However, when compression is enabled, it still pays the full cost of
|
25
25
|
# compression in terms of cpu use.
|
26
26
|
#
|
27
|
-
# MemoryStore is thread-safe.
|
27
|
+
# +MemoryStore+ is thread-safe.
|
28
28
|
class MemoryStore < Store
|
29
29
|
module DupCoder # :nodoc:
|
30
30
|
extend self
|
@@ -209,7 +209,7 @@ module ActiveSupport
|
|
209
209
|
def write_entry(key, entry, **options)
|
210
210
|
payload = serialize_entry(entry, **options)
|
211
211
|
synchronize do
|
212
|
-
return false if options[:unless_exist] && exist?(key)
|
212
|
+
return false if options[:unless_exist] && exist?(key, namespace: nil)
|
213
213
|
|
214
214
|
old_payload = @data[key]
|
215
215
|
if old_payload
|
@@ -19,22 +19,23 @@ module ActiveSupport
|
|
19
19
|
module Cache
|
20
20
|
# = Redis \Cache \Store
|
21
21
|
#
|
22
|
-
# Deployment note: Take care to use a
|
23
|
-
# than pointing this at
|
24
|
-
#
|
22
|
+
# Deployment note: Take care to use a <b>dedicated Redis cache</b> rather
|
23
|
+
# than pointing this at a persistent Redis server (for example, one used as
|
24
|
+
# an Active Job queue). Redis won't cope well with mixed usage patterns and it
|
25
|
+
# won't expire cache entries by default.
|
25
26
|
#
|
26
27
|
# Redis cache server setup guide: https://redis.io/topics/lru-cache
|
27
28
|
#
|
28
|
-
# * Supports vanilla Redis, hiredis, and Redis::Distributed
|
29
|
-
# * Supports Memcached-like sharding across Redises with Redis::Distributed
|
29
|
+
# * Supports vanilla Redis, hiredis, and +Redis::Distributed+.
|
30
|
+
# * Supports Memcached-like sharding across Redises with +Redis::Distributed+.
|
30
31
|
# * Fault tolerant. If the Redis server is unavailable, no exceptions are
|
31
32
|
# raised. Cache fetches are all misses and writes are dropped.
|
32
33
|
# * Local cache. Hot in-memory primary cache within block/middleware scope.
|
33
|
-
# * +read_multi+ and +write_multi+ support for Redis mget/mset. Use
|
34
|
-
# 4.0.1+ for distributed mget support.
|
34
|
+
# * +read_multi+ and +write_multi+ support for Redis mget/mset. Use
|
35
|
+
# +Redis::Distributed+ 4.0.1+ for distributed mget support.
|
35
36
|
# * +delete_matched+ support for Redis KEYS globs.
|
36
37
|
class RedisCacheStore < Store
|
37
|
-
# Keys are truncated with the
|
38
|
+
# Keys are truncated with the Active Support digest if they exceed 1kB
|
38
39
|
MAX_KEY_BYTESIZE = 1024
|
39
40
|
|
40
41
|
DEFAULT_REDIS_OPTIONS = {
|
@@ -110,8 +111,11 @@ module ActiveSupport
|
|
110
111
|
|
111
112
|
# Creates a new Redis cache store.
|
112
113
|
#
|
113
|
-
#
|
114
|
-
#
|
114
|
+
# There are four ways to provide the Redis client used by the cache: the
|
115
|
+
# +:redis+ param can be a Redis instance or a block that returns a Redis
|
116
|
+
# instance, or the +:url+ param can be a string or an array of strings
|
117
|
+
# which will be used to create a Redis instance or a +Redis::Distributed+
|
118
|
+
# instance.
|
115
119
|
#
|
116
120
|
# Option Class Result
|
117
121
|
# :redis Proc -> options[:redis].call
|
@@ -134,7 +138,7 @@ module ActiveSupport
|
|
134
138
|
#
|
135
139
|
# Race condition TTL is not set by default. This can be used to avoid
|
136
140
|
# "thundering herd" cache writes when hot cache entries are expired.
|
137
|
-
# See
|
141
|
+
# See ActiveSupport::Cache::Store#fetch for more.
|
138
142
|
#
|
139
143
|
# Setting <tt>skip_nil: true</tt> will not cache nil results:
|
140
144
|
#
|
@@ -242,7 +246,7 @@ module ActiveSupport
|
|
242
246
|
# Decrement a cached integer value using the Redis decrby atomic operator.
|
243
247
|
# Returns the updated value.
|
244
248
|
#
|
245
|
-
# If the key is unset or has expired, it will be set to
|
249
|
+
# If the key is unset or has expired, it will be set to +-amount+:
|
246
250
|
#
|
247
251
|
# cache.decrement("foo") # => -1
|
248
252
|
#
|
@@ -332,7 +336,10 @@ module ActiveSupport
|
|
332
336
|
if value
|
333
337
|
entry = deserialize_entry(value, raw: raw)
|
334
338
|
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(name, options))
|
335
|
-
|
339
|
+
begin
|
340
|
+
results[name] = entry.value
|
341
|
+
rescue DeserializationError
|
342
|
+
end
|
336
343
|
end
|
337
344
|
end
|
338
345
|
end
|
@@ -383,7 +390,7 @@ module ActiveSupport
|
|
383
390
|
end
|
384
391
|
|
385
392
|
# Nonstandard store provider API to write multiple values at once.
|
386
|
-
def write_multi_entries(entries,
|
393
|
+
def write_multi_entries(entries, **options)
|
387
394
|
return if entries.empty?
|
388
395
|
|
389
396
|
failsafe :write_multi_entries do
|
@@ -131,17 +131,20 @@ module ActiveSupport
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
-
def read_multi_entries(
|
134
|
+
def read_multi_entries(names, **options)
|
135
135
|
return super unless local_cache
|
136
136
|
|
137
|
-
|
137
|
+
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
138
|
+
|
139
|
+
local_entries = local_cache.read_multi_entries(keys_to_names.keys)
|
140
|
+
local_entries.transform_keys! { |key| keys_to_names[key] }
|
138
141
|
local_entries.transform_values! do |payload|
|
139
|
-
deserialize_entry(payload)&.value
|
142
|
+
deserialize_entry(payload, **options)&.value
|
140
143
|
end
|
141
|
-
|
144
|
+
missed_names = names - local_entries.keys
|
142
145
|
|
143
|
-
if
|
144
|
-
local_entries.merge!(super(
|
146
|
+
if missed_names.any?
|
147
|
+
local_entries.merge!(super(missed_names, **options))
|
145
148
|
else
|
146
149
|
local_entries
|
147
150
|
end
|
data/lib/active_support/cache.rb
CHANGED
@@ -160,8 +160,8 @@ module ActiveSupport
|
|
160
160
|
# Some implementations may not support all methods beyond the basic cache
|
161
161
|
# methods of #fetch, #write, #read, #exist?, and #delete.
|
162
162
|
#
|
163
|
-
# ActiveSupport::Cache::Store can store any Ruby object that is supported
|
164
|
-
# its +coder+'s +dump+ and +load+ methods.
|
163
|
+
# +ActiveSupport::Cache::Store+ can store any Ruby object that is supported
|
164
|
+
# by its +coder+'s +dump+ and +load+ methods.
|
165
165
|
#
|
166
166
|
# cache = ActiveSupport::Cache::MemoryStore.new
|
167
167
|
#
|
@@ -370,8 +370,8 @@ module ActiveSupport
|
|
370
370
|
#
|
371
371
|
# ==== Options
|
372
372
|
#
|
373
|
-
# Internally, +fetch+ calls
|
374
|
-
# miss. Thus, +fetch+ supports the same options as #read and #write.
|
373
|
+
# Internally, +fetch+ calls +read_entry+, and calls +write_entry+ on a
|
374
|
+
# cache miss. Thus, +fetch+ supports the same options as #read and #write.
|
375
375
|
# Additionally, +fetch+ supports the following options:
|
376
376
|
#
|
377
377
|
# * <tt>force: true</tt> - Forces a cache "miss," meaning we treat the
|
@@ -459,7 +459,17 @@ module ActiveSupport
|
|
459
459
|
instrument(:read, name, options) do |payload|
|
460
460
|
cached_entry = read_entry(key, **options, event: payload)
|
461
461
|
entry = handle_expired_entry(cached_entry, key, options)
|
462
|
-
|
462
|
+
if entry
|
463
|
+
if entry.mismatched?(normalize_version(name, options))
|
464
|
+
entry = nil
|
465
|
+
else
|
466
|
+
begin
|
467
|
+
entry.value
|
468
|
+
rescue DeserializationError
|
469
|
+
entry = nil
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
463
473
|
payload[:super_operation] = :fetch if payload
|
464
474
|
payload[:hit] = !!entry if payload
|
465
475
|
end
|
@@ -511,7 +521,12 @@ module ActiveSupport
|
|
511
521
|
nil
|
512
522
|
else
|
513
523
|
payload[:hit] = true if payload
|
514
|
-
|
524
|
+
begin
|
525
|
+
entry.value
|
526
|
+
rescue DeserializationError
|
527
|
+
payload[:hit] = false
|
528
|
+
nil
|
529
|
+
end
|
515
530
|
end
|
516
531
|
else
|
517
532
|
payload[:hit] = false if payload
|
@@ -803,7 +818,7 @@ module ActiveSupport
|
|
803
818
|
end
|
804
819
|
end
|
805
820
|
|
806
|
-
def deserialize_entry(payload)
|
821
|
+
def deserialize_entry(payload, **)
|
807
822
|
payload.nil? ? nil : @coder.load(payload)
|
808
823
|
rescue DeserializationError
|
809
824
|
nil
|
@@ -1038,6 +1053,8 @@ module ActiveSupport
|
|
1038
1053
|
end
|
1039
1054
|
|
1040
1055
|
def save_block_result_to_cache(name, options)
|
1056
|
+
options = options.dup
|
1057
|
+
|
1041
1058
|
result = instrument(:generate, name, options) do
|
1042
1059
|
yield(name, WriteOptions.new(options))
|
1043
1060
|
end
|
@@ -1047,6 +1064,10 @@ module ActiveSupport
|
|
1047
1064
|
end
|
1048
1065
|
end
|
1049
1066
|
|
1067
|
+
# Enables the dynamic configuration of Cache entry options while ensuring
|
1068
|
+
# that conflicting options are not both set. When a block is given to
|
1069
|
+
# ActiveSupport::Cache::Store#fetch, the second argument will be an
|
1070
|
+
# instance of +WriteOptions+.
|
1050
1071
|
class WriteOptions
|
1051
1072
|
def initialize(options) # :nodoc:
|
1052
1073
|
@options = options
|
@@ -1064,6 +1085,9 @@ module ActiveSupport
|
|
1064
1085
|
@options[:expires_in]
|
1065
1086
|
end
|
1066
1087
|
|
1088
|
+
# Sets the Cache entry's +expires_in+ value. If an +expires_at+ option was
|
1089
|
+
# previously set, this will unset it since +expires_in+ and +expires_at+
|
1090
|
+
# cannot both be set.
|
1067
1091
|
def expires_in=(expires_in)
|
1068
1092
|
@options.delete(:expires_at)
|
1069
1093
|
@options[:expires_in] = expires_in
|
@@ -1073,6 +1097,9 @@ module ActiveSupport
|
|
1073
1097
|
@options[:expires_at]
|
1074
1098
|
end
|
1075
1099
|
|
1100
|
+
# Sets the Cache entry's +expires_at+ value. If an +expires_in+ option was
|
1101
|
+
# previously set, this will unset it since +expires_at+ and +expires_in+
|
1102
|
+
# cannot both be set.
|
1076
1103
|
def expires_at=(expires_at)
|
1077
1104
|
@options.delete(:expires_in)
|
1078
1105
|
@options[:expires_at] = expires_at
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/concern"
|
4
4
|
|
5
5
|
class Module
|
6
|
-
#
|
6
|
+
# == Bite-sized separation of concerns
|
7
7
|
#
|
8
8
|
# We often find ourselves with a medium-sized chunk of behavior that we'd
|
9
9
|
# like to extract, but only mix in to a single class.
|
@@ -18,9 +18,9 @@ class Module
|
|
18
18
|
# with a comment, as a least-bad alternative. Using modules in separate files
|
19
19
|
# means tedious sifting to get a big-picture view.
|
20
20
|
#
|
21
|
-
#
|
21
|
+
# == Dissatisfying ways to separate small concerns
|
22
22
|
#
|
23
|
-
#
|
23
|
+
# === Using comments:
|
24
24
|
#
|
25
25
|
# class Todo < ApplicationRecord
|
26
26
|
# # Other todo implementation
|
@@ -37,7 +37,7 @@ class Module
|
|
37
37
|
# end
|
38
38
|
# end
|
39
39
|
#
|
40
|
-
#
|
40
|
+
# === With an inline module:
|
41
41
|
#
|
42
42
|
# Noisy syntax.
|
43
43
|
#
|
@@ -61,7 +61,7 @@ class Module
|
|
61
61
|
# include EventTracking
|
62
62
|
# end
|
63
63
|
#
|
64
|
-
#
|
64
|
+
# === Mix-in noise exiled to its own file:
|
65
65
|
#
|
66
66
|
# Once our chunk of behavior starts pushing the scroll-to-understand-it
|
67
67
|
# boundary, we give in and move it to a separate file. At this size, the
|
@@ -75,7 +75,7 @@ class Module
|
|
75
75
|
# include TodoEventTracking
|
76
76
|
# end
|
77
77
|
#
|
78
|
-
#
|
78
|
+
# == Introducing Module#concerning
|
79
79
|
#
|
80
80
|
# By quieting the mix-in noise, we arrive at a natural, low-ceremony way to
|
81
81
|
# separate bite-sized concerns.
|
@@ -68,7 +68,7 @@ class Object
|
|
68
68
|
# You can access these methods using the class name instead:
|
69
69
|
#
|
70
70
|
# class Phone < ActiveRecord::Base
|
71
|
-
# enum phone_number_type
|
71
|
+
# enum :phone_number_type, { home: 0, office: 1, mobile: 2 }
|
72
72
|
#
|
73
73
|
# with_options presence: true do
|
74
74
|
# validates :phone_number_type, inclusion: { in: Phone.phone_number_types.keys }
|
@@ -24,7 +24,7 @@ class String
|
|
24
24
|
#
|
25
25
|
# The second argument, +indent_string+, specifies which indent string to
|
26
26
|
# use. The default is +nil+, which tells the method to make a guess by
|
27
|
-
# peeking at the first indented line, and
|
27
|
+
# peeking at the first indented line, and fall back to a space if there is
|
28
28
|
# none.
|
29
29
|
#
|
30
30
|
# " foo".indent(2) # => " foo"
|
@@ -57,15 +57,15 @@ module ActiveSupport
|
|
57
57
|
# You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+
|
58
58
|
# constant. Available behaviors are:
|
59
59
|
#
|
60
|
-
# [
|
61
|
-
# [
|
62
|
-
# [
|
63
|
-
# [
|
64
|
-
# [
|
65
|
-
# [
|
60
|
+
# [+:raise+] Raise ActiveSupport::DeprecationException.
|
61
|
+
# [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
|
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.
|
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.
|
68
|
-
# For more information you can read the documentation of the
|
68
|
+
# For more information you can read the documentation of the #behavior= method.
|
69
69
|
module Behavior
|
70
70
|
# Whether to print a backtrace along with the warning.
|
71
71
|
attr_accessor :debug
|
@@ -85,12 +85,12 @@ module ActiveSupport
|
|
85
85
|
#
|
86
86
|
# Available behaviors:
|
87
87
|
#
|
88
|
-
# [
|
89
|
-
# [
|
90
|
-
# [
|
91
|
-
# [
|
92
|
-
# [
|
93
|
-
# [
|
88
|
+
# [+:raise+] Raise ActiveSupport::DeprecationException.
|
89
|
+
# [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
|
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.
|
93
|
+
# [+:silence+] Do nothing.
|
94
94
|
#
|
95
95
|
# Setting behaviors only affects deprecations that happen after boot time.
|
96
96
|
# Deprecation warnings raised by gems are not affected by this setting
|
@@ -104,15 +104,17 @@ module ActiveSupport
|
|
104
104
|
# # custom stuff
|
105
105
|
# }
|
106
106
|
#
|
107
|
-
# If you are using \Rails, you can set
|
108
|
-
#
|
107
|
+
# If you are using \Rails, you can set
|
108
|
+
# <tt>config.active_support.report_deprecations = false</tt> to disable
|
109
|
+
# all deprecation behaviors. This is similar to the +:silence+ option but
|
110
|
+
# more performant.
|
109
111
|
def behavior=(behavior)
|
110
112
|
@behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
|
111
113
|
end
|
112
114
|
|
113
115
|
# Sets the behavior for disallowed deprecations (those configured by
|
114
116
|
# ActiveSupport::Deprecation#disallowed_warnings=) to the specified
|
115
|
-
# value. As with
|
117
|
+
# value. As with #behavior=, this can be a single value, array, or an
|
116
118
|
# object that responds to +call+.
|
117
119
|
def disallowed_behavior=(behavior)
|
118
120
|
@disallowed_behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
|
@@ -142,7 +142,9 @@ module ActiveSupport
|
|
142
142
|
return _extract_callstack(callstack) if callstack.first.is_a? String
|
143
143
|
|
144
144
|
offending_line = callstack.find { |frame|
|
145
|
-
|
145
|
+
# Code generated with `eval` doesn't have an `absolute_path`, e.g. templates.
|
146
|
+
path = frame.absolute_path || frame.path
|
147
|
+
path && !ignored_callstack?(path)
|
146
148
|
} || callstack.first
|
147
149
|
|
148
150
|
[offending_line.path, offending_line.lineno, offending_line.label]
|
@@ -150,7 +152,7 @@ module ActiveSupport
|
|
150
152
|
|
151
153
|
def _extract_callstack(callstack)
|
152
154
|
warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
|
153
|
-
offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
|
155
|
+
offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first
|
154
156
|
|
155
157
|
if offending_line
|
156
158
|
if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
|
@@ -162,9 +164,10 @@ module ActiveSupport
|
|
162
164
|
end
|
163
165
|
|
164
166
|
RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
|
167
|
+
LIB_DIR = RbConfig::CONFIG["libdir"]
|
165
168
|
|
166
|
-
def ignored_callstack(path)
|
167
|
-
path.start_with?(RAILS_GEM_ROOT
|
169
|
+
def ignored_callstack?(path)
|
170
|
+
path.start_with?(RAILS_GEM_ROOT, LIB_DIR)
|
168
171
|
end
|
169
172
|
end
|
170
173
|
end
|