activesupport 7.1.2 → 7.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/lib/active_support/cache/mem_cache_store.rb +6 -6
- data/lib/active_support/cache/memory_store.rb +4 -4
- data/lib/active_support/cache/redis_cache_store.rb +16 -12
- data/lib/active_support/cache/strategy/local_cache.rb +9 -6
- data/lib/active_support/cache.rb +15 -5
- 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 +1 -1
- data/lib/active_support/json/encoding.rb +1 -1
- data/lib/active_support/number_helper.rb +379 -318
- data/lib/active_support/syntax_error_proxy.rb +22 -1
- data/lib/active_support/testing/assertions.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +4 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5694cfb6b4f9606e418f0719251eddccf4ddb2db2747a3965d22e204d7d53da3
|
4
|
+
data.tar.gz: fb6419c22aa79734268b1c3435692cf6e9e7e18a0522d4089f1528a4f401edb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84e38bfcc73526a4f62531d6387a57e235f211112dc65f4dd436a32c6cf88aceaa40990d29cb49612c4458d4768036bb1315cb96265109c029a4faed65fb6e02
|
7
|
+
data.tar.gz: 0f0a733d3dcf357ebee24484b1c9832f55b22e362328a537d2d6ee3afe4996e5c880d6ebb78bd90c4e1a7139a75dfcfdaef7bbba06289d90d213ed0dcbfc6abe
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
## Rails 7.1.3 (January 16, 2024) ##
|
2
|
+
|
3
|
+
* Handle nil `backtrace_locations` in `ActiveSupport::SyntaxErrorProxy`.
|
4
|
+
|
5
|
+
*Eugene Kenny*
|
6
|
+
|
7
|
+
* Fix `ActiveSupport::JSON.encode` to prevent duplicate keys.
|
8
|
+
|
9
|
+
If the same key exist in both String and Symbol form it could
|
10
|
+
lead to the same key being emitted twice.
|
11
|
+
|
12
|
+
*Manish Sharma*
|
13
|
+
|
14
|
+
* Fix `ActiveSupport::Cache::Store#read_multi` when using a cache namespace
|
15
|
+
and local cache strategy.
|
16
|
+
|
17
|
+
*Mark Oleson*
|
18
|
+
|
19
|
+
* Fix `Time.now/DateTime.now/Date.today` to return results in a system timezone after `#travel_to`.
|
20
|
+
|
21
|
+
There is a bug in the current implementation of #travel_to:
|
22
|
+
it remembers a timezone of its argument, and all stubbed methods start
|
23
|
+
returning results in that remembered timezone. However, the expected
|
24
|
+
behaviour is to return results in a system timezone.
|
25
|
+
|
26
|
+
*Aleksei Chernenkov*
|
27
|
+
|
28
|
+
* Fix `:unless_exist` option for `MemoryStore#write` (et al) when using a
|
29
|
+
cache namespace.
|
30
|
+
|
31
|
+
*S. Brent Faulkner*
|
32
|
+
|
33
|
+
* Fix ActiveSupport::Deprecation to handle blaming generated code.
|
34
|
+
|
35
|
+
*Jean Boussier*, *fatkodima*
|
36
|
+
|
37
|
+
|
1
38
|
## Rails 7.1.2 (November 10, 2023) ##
|
2
39
|
|
3
40
|
* Fix `:expires_in` option for `RedisCacheStore#write_multi`.
|
@@ -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
|
@@ -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
|
#
|
@@ -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
|
@@ -818,7 +818,7 @@ module ActiveSupport
|
|
818
818
|
end
|
819
819
|
end
|
820
820
|
|
821
|
-
def deserialize_entry(payload)
|
821
|
+
def deserialize_entry(payload, **)
|
822
822
|
payload.nil? ? nil : @coder.load(payload)
|
823
823
|
rescue DeserializationError
|
824
824
|
nil
|
@@ -1064,6 +1064,10 @@ module ActiveSupport
|
|
1064
1064
|
end
|
1065
1065
|
end
|
1066
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+.
|
1067
1071
|
class WriteOptions
|
1068
1072
|
def initialize(options) # :nodoc:
|
1069
1073
|
@options = options
|
@@ -1081,6 +1085,9 @@ module ActiveSupport
|
|
1081
1085
|
@options[:expires_in]
|
1082
1086
|
end
|
1083
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.
|
1084
1091
|
def expires_in=(expires_in)
|
1085
1092
|
@options.delete(:expires_at)
|
1086
1093
|
@options[:expires_in] = expires_in
|
@@ -1090,6 +1097,9 @@ module ActiveSupport
|
|
1090
1097
|
@options[:expires_at]
|
1091
1098
|
end
|
1092
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.
|
1093
1103
|
def expires_at=(expires_at)
|
1094
1104
|
@options.delete(:expires_in)
|
1095
1105
|
@options[:expires_at] = expires_at
|
@@ -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
|