activesupport 7.1.2 → 7.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +134 -0
- data/lib/active_support/backtrace_cleaner.rb +5 -0
- data/lib/active_support/broadcast_logger.rb +15 -14
- 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 +17 -6
- data/lib/active_support/code_generator.rb +15 -10
- data/lib/active_support/core_ext/module/delegation.rb +41 -26
- data/lib/active_support/core_ext/object/duplicable.rb +24 -15
- data/lib/active_support/core_ext/object/json.rb +5 -3
- 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 +8 -5
- data/lib/active_support/gem_version.rb +1 -1
- data/lib/active_support/html_safe_translation.rb +16 -6
- data/lib/active_support/log_subscriber.rb +1 -0
- data/lib/active_support/messages/codec.rb +1 -1
- data/lib/active_support/notifications/instrumenter.rb +11 -3
- data/lib/active_support/number_helper.rb +379 -318
- data/lib/active_support/railtie.rb +3 -3
- data/lib/active_support/syntax_error_proxy.rb +12 -1
- data/lib/active_support/tagged_logging.rb +4 -0
- data/lib/active_support/testing/assertions.rb +1 -1
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/time_helpers.rb +4 -0
- data/lib/active_support/values/time_zone.rb +9 -0
- data/lib/active_support.rb +1 -1
- metadata +51 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d05cf683e37c600f522c4be11034dfa45e30ef52cea9e41dc0087a624fd4063
|
|
4
|
+
data.tar.gz: 7e7ba21207beeb10e1093ac45cd02a096fda507504e229f8df559b746937f1e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 96c1bc0122ee7fcd400846ada8641591d06ca82c42bb4d35bc87c7c8062826b1aa6eec7d2fe81144947353ff29195fd9ca3b4b307c9d21aa366a0717c974eb40
|
|
7
|
+
data.tar.gz: 668f85b8c485c9bc089781d623d3e6a6c84e8e2c57afb350d35ce346ad629679df837e9c9ea8db31b72a8b05839ab296f5e8ac8289103195ecd27b227ebe696d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,137 @@
|
|
|
1
|
+
## Rails 7.1.5 (October 30, 2024) ##
|
|
2
|
+
|
|
3
|
+
* No changes.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Rails 7.1.4.2 (October 23, 2024) ##
|
|
7
|
+
|
|
8
|
+
* No changes.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Rails 7.1.4.1 (October 15, 2024) ##
|
|
12
|
+
|
|
13
|
+
* No changes.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## Rails 7.1.4 (August 22, 2024) ##
|
|
17
|
+
|
|
18
|
+
* Improve compatibility for `ActiveSupport::BroadcastLogger`.
|
|
19
|
+
|
|
20
|
+
*Máximo Mussini*
|
|
21
|
+
|
|
22
|
+
* Pass options along to write_entry in handle_expired_entry method.
|
|
23
|
+
|
|
24
|
+
*Graham Cooper*
|
|
25
|
+
|
|
26
|
+
* Fix Active Support configurations deprecations.
|
|
27
|
+
|
|
28
|
+
*fatkodima*
|
|
29
|
+
|
|
30
|
+
* Fix teardown callbacks.
|
|
31
|
+
|
|
32
|
+
*Tristan Starck*
|
|
33
|
+
|
|
34
|
+
* `BacktraceCleaner` silence core internal methods by default.
|
|
35
|
+
|
|
36
|
+
*Jean Boussier*
|
|
37
|
+
|
|
38
|
+
* Fix `delegate_missing_to allow_nil: true` when called with implict self
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
class Person
|
|
42
|
+
delegate_missing_to :address, allow_nil: true
|
|
43
|
+
|
|
44
|
+
def address
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def berliner?
|
|
49
|
+
city == "Berlin"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Person.new.city # => nil
|
|
54
|
+
Person.new.berliner? # undefined local variable or method `city' for an instance of Person (NameError)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
*Jean Boussier*
|
|
58
|
+
|
|
59
|
+
* Work around a Ruby bug that can cause a VM crash.
|
|
60
|
+
|
|
61
|
+
This would happen if using `TaggerLogger` with a Proc
|
|
62
|
+
formatter on which you called `object_id`.
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
[BUG] Object ID seen, but not in mapping table: proc
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
*Jean Boussier*
|
|
69
|
+
|
|
70
|
+
* Fix `ActiveSupport::Notifications.publish_event` to preserve units.
|
|
71
|
+
|
|
72
|
+
This solves the incorrect reporting of time spent running Active Record
|
|
73
|
+
asynchronous queries (by a factor `1000`).
|
|
74
|
+
|
|
75
|
+
*Jean Boussier*
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
## Rails 7.1.3.4 (June 04, 2024) ##
|
|
79
|
+
|
|
80
|
+
* No changes.
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
## Rails 7.1.3.3 (May 16, 2024) ##
|
|
84
|
+
|
|
85
|
+
* No changes.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Rails 7.1.3.2 (February 21, 2024) ##
|
|
89
|
+
|
|
90
|
+
* No changes.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## Rails 7.1.3.1 (February 21, 2024) ##
|
|
94
|
+
|
|
95
|
+
* No changes.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Rails 7.1.3 (January 16, 2024) ##
|
|
99
|
+
|
|
100
|
+
* Handle nil `backtrace_locations` in `ActiveSupport::SyntaxErrorProxy`.
|
|
101
|
+
|
|
102
|
+
*Eugene Kenny*
|
|
103
|
+
|
|
104
|
+
* Fix `ActiveSupport::JSON.encode` to prevent duplicate keys.
|
|
105
|
+
|
|
106
|
+
If the same key exist in both String and Symbol form it could
|
|
107
|
+
lead to the same key being emitted twice.
|
|
108
|
+
|
|
109
|
+
*Manish Sharma*
|
|
110
|
+
|
|
111
|
+
* Fix `ActiveSupport::Cache::Store#read_multi` when using a cache namespace
|
|
112
|
+
and local cache strategy.
|
|
113
|
+
|
|
114
|
+
*Mark Oleson*
|
|
115
|
+
|
|
116
|
+
* Fix `Time.now/DateTime.now/Date.today` to return results in a system timezone after `#travel_to`.
|
|
117
|
+
|
|
118
|
+
There is a bug in the current implementation of #travel_to:
|
|
119
|
+
it remembers a timezone of its argument, and all stubbed methods start
|
|
120
|
+
returning results in that remembered timezone. However, the expected
|
|
121
|
+
behaviour is to return results in a system timezone.
|
|
122
|
+
|
|
123
|
+
*Aleksei Chernenkov*
|
|
124
|
+
|
|
125
|
+
* Fix `:unless_exist` option for `MemoryStore#write` (et al) when using a
|
|
126
|
+
cache namespace.
|
|
127
|
+
|
|
128
|
+
*S. Brent Faulkner*
|
|
129
|
+
|
|
130
|
+
* Fix ActiveSupport::Deprecation to handle blaming generated code.
|
|
131
|
+
|
|
132
|
+
*Jean Boussier*, *fatkodima*
|
|
133
|
+
|
|
134
|
+
|
|
1
135
|
## Rails 7.1.2 (November 10, 2023) ##
|
|
2
136
|
|
|
3
137
|
* Fix `:expires_in` option for `RedisCacheStore#write_multi`.
|
|
@@ -33,6 +33,7 @@ module ActiveSupport
|
|
|
33
33
|
class BacktraceCleaner
|
|
34
34
|
def initialize
|
|
35
35
|
@filters, @silencers = [], []
|
|
36
|
+
add_core_silencer
|
|
36
37
|
add_gem_filter
|
|
37
38
|
add_gem_silencer
|
|
38
39
|
add_stdlib_silencer
|
|
@@ -116,6 +117,10 @@ module ActiveSupport
|
|
|
116
117
|
add_filter { |line| line.sub(gems_regexp, gems_result) }
|
|
117
118
|
end
|
|
118
119
|
|
|
120
|
+
def add_core_silencer
|
|
121
|
+
add_silencer { |line| line.include?("<internal:") }
|
|
122
|
+
end
|
|
123
|
+
|
|
119
124
|
def add_gem_silencer
|
|
120
125
|
add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
|
|
121
126
|
end
|
|
@@ -113,33 +113,33 @@ module ActiveSupport
|
|
|
113
113
|
dispatch { |logger| logger.<<(message) }
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
-
def add(
|
|
117
|
-
dispatch { |logger| logger.add(
|
|
116
|
+
def add(...)
|
|
117
|
+
dispatch { |logger| logger.add(...) }
|
|
118
118
|
end
|
|
119
119
|
alias_method :log, :add
|
|
120
120
|
|
|
121
|
-
def debug(
|
|
122
|
-
dispatch { |logger| logger.debug(
|
|
121
|
+
def debug(...)
|
|
122
|
+
dispatch { |logger| logger.debug(...) }
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
def info(
|
|
126
|
-
dispatch { |logger| logger.info(
|
|
125
|
+
def info(...)
|
|
126
|
+
dispatch { |logger| logger.info(...) }
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
def warn(
|
|
130
|
-
dispatch { |logger| logger.warn(
|
|
129
|
+
def warn(...)
|
|
130
|
+
dispatch { |logger| logger.warn(...) }
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
def error(
|
|
134
|
-
dispatch { |logger| logger.error(
|
|
133
|
+
def error(...)
|
|
134
|
+
dispatch { |logger| logger.error(...) }
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
-
def fatal(
|
|
138
|
-
dispatch { |logger| logger.fatal(
|
|
137
|
+
def fatal(...)
|
|
138
|
+
dispatch { |logger| logger.fatal(...) }
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
def unknown(
|
|
142
|
-
dispatch { |logger| logger.unknown(
|
|
141
|
+
def unknown(...)
|
|
142
|
+
dispatch { |logger| logger.unknown(...) }
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
def formatter=(formatter)
|
|
@@ -229,6 +229,7 @@ module ActiveSupport
|
|
|
229
229
|
private
|
|
230
230
|
def dispatch(&block)
|
|
231
231
|
@broadcasts.each { |logger| block.call(logger) }
|
|
232
|
+
true
|
|
232
233
|
end
|
|
233
234
|
|
|
234
235
|
def method_missing(name, *args, **kwargs, &block)
|
|
@@ -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
|
|
@@ -1038,7 +1038,8 @@ module ActiveSupport
|
|
|
1038
1038
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
|
1039
1039
|
# for a brief period while the entry is being recalculated.
|
|
1040
1040
|
entry.expires_at = Time.now.to_f + race_ttl
|
|
1041
|
-
|
|
1041
|
+
options[:expires_in] = race_ttl * 2
|
|
1042
|
+
write_entry(key, entry, **options)
|
|
1042
1043
|
else
|
|
1043
1044
|
delete_entry(key, **options)
|
|
1044
1045
|
end
|
|
@@ -1064,6 +1065,10 @@ module ActiveSupport
|
|
|
1064
1065
|
end
|
|
1065
1066
|
end
|
|
1066
1067
|
|
|
1068
|
+
# Enables the dynamic configuration of Cache entry options while ensuring
|
|
1069
|
+
# that conflicting options are not both set. When a block is given to
|
|
1070
|
+
# ActiveSupport::Cache::Store#fetch, the second argument will be an
|
|
1071
|
+
# instance of +WriteOptions+.
|
|
1067
1072
|
class WriteOptions
|
|
1068
1073
|
def initialize(options) # :nodoc:
|
|
1069
1074
|
@options = options
|
|
@@ -1081,6 +1086,9 @@ module ActiveSupport
|
|
|
1081
1086
|
@options[:expires_in]
|
|
1082
1087
|
end
|
|
1083
1088
|
|
|
1089
|
+
# Sets the Cache entry's +expires_in+ value. If an +expires_at+ option was
|
|
1090
|
+
# previously set, this will unset it since +expires_in+ and +expires_at+
|
|
1091
|
+
# cannot both be set.
|
|
1084
1092
|
def expires_in=(expires_in)
|
|
1085
1093
|
@options.delete(:expires_at)
|
|
1086
1094
|
@options[:expires_in] = expires_in
|
|
@@ -1090,6 +1098,9 @@ module ActiveSupport
|
|
|
1090
1098
|
@options[:expires_at]
|
|
1091
1099
|
end
|
|
1092
1100
|
|
|
1101
|
+
# Sets the Cache entry's +expires_at+ value. If an +expires_in+ option was
|
|
1102
|
+
# previously set, this will unset it since +expires_at+ and +expires_in+
|
|
1103
|
+
# cannot both be set.
|
|
1093
1104
|
def expires_at=(expires_at)
|
|
1094
1105
|
@options.delete(:expires_in)
|
|
1095
1106
|
@options[:expires_at] = expires_at
|
|
@@ -9,16 +9,19 @@ module ActiveSupport
|
|
|
9
9
|
@cache = METHOD_CACHES[namespace]
|
|
10
10
|
@sources = []
|
|
11
11
|
@methods = {}
|
|
12
|
+
@canonical_methods = {}
|
|
12
13
|
end
|
|
13
14
|
|
|
14
|
-
def define_cached_method(
|
|
15
|
-
|
|
16
|
-
as = as.to_sym
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
def define_cached_method(canonical_name, as: nil)
|
|
16
|
+
canonical_name = canonical_name.to_sym
|
|
17
|
+
as = (as || canonical_name).to_sym
|
|
18
|
+
|
|
19
|
+
@methods.fetch(as) do
|
|
20
|
+
unless @cache.method_defined?(canonical_name) || @canonical_methods[canonical_name]
|
|
19
21
|
yield @sources
|
|
20
22
|
end
|
|
21
|
-
@
|
|
23
|
+
@canonical_methods[canonical_name] = true
|
|
24
|
+
@methods[as] = canonical_name
|
|
22
25
|
end
|
|
23
26
|
end
|
|
24
27
|
|
|
@@ -26,8 +29,10 @@ module ActiveSupport
|
|
|
26
29
|
unless @sources.empty?
|
|
27
30
|
@cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
|
|
28
31
|
end
|
|
29
|
-
@
|
|
30
|
-
|
|
32
|
+
@canonical_methods.clear
|
|
33
|
+
|
|
34
|
+
@methods.each do |as, canonical_name|
|
|
35
|
+
owner.define_method(as, @cache.instance_method(canonical_name))
|
|
31
36
|
end
|
|
32
37
|
end
|
|
33
38
|
end
|
|
@@ -52,8 +57,8 @@ module ActiveSupport
|
|
|
52
57
|
@namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
|
|
53
58
|
end
|
|
54
59
|
|
|
55
|
-
def define_cached_method(
|
|
56
|
-
@namespaces[namespace].define_cached_method(
|
|
60
|
+
def define_cached_method(canonical_name, namespace:, as: nil, &block)
|
|
61
|
+
@namespaces[namespace].define_cached_method(canonical_name, as: as, &block)
|
|
57
62
|
end
|
|
58
63
|
|
|
59
64
|
def execute
|
|
@@ -317,37 +317,52 @@ class Module
|
|
|
317
317
|
# of <tt>object</tt> add or remove instance variables.
|
|
318
318
|
def delegate_missing_to(target, allow_nil: nil)
|
|
319
319
|
target = target.to_s
|
|
320
|
-
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
|
|
320
|
+
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target) || target == "__target"
|
|
321
321
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
322
|
+
if allow_nil
|
|
323
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
324
|
+
def respond_to_missing?(name, include_private = false)
|
|
325
|
+
# It may look like an oversight, but we deliberately do not pass
|
|
326
|
+
# +include_private+, because they do not get delegated.
|
|
326
327
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
328
|
+
return false if name == :marshal_dump || name == :_dump
|
|
329
|
+
#{target}.respond_to?(name) || super
|
|
330
|
+
end
|
|
330
331
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
332
|
+
def method_missing(method, *args, &block)
|
|
333
|
+
__target = #{target}
|
|
334
|
+
if __target.nil? && !nil.respond_to?(method)
|
|
335
|
+
nil
|
|
336
|
+
elsif __target.respond_to?(method)
|
|
337
|
+
__target.public_send(method, *args, &block)
|
|
338
|
+
else
|
|
336
339
|
super
|
|
337
|
-
rescue NoMethodError
|
|
338
|
-
if #{target}.nil?
|
|
339
|
-
if #{allow_nil == true}
|
|
340
|
-
nil
|
|
341
|
-
else
|
|
342
|
-
raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
|
|
343
|
-
end
|
|
344
|
-
else
|
|
345
|
-
raise
|
|
346
|
-
end
|
|
347
340
|
end
|
|
348
341
|
end
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
342
|
+
ruby2_keywords(:method_missing)
|
|
343
|
+
RUBY
|
|
344
|
+
else
|
|
345
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
346
|
+
def respond_to_missing?(name, include_private = false)
|
|
347
|
+
# It may look like an oversight, but we deliberately do not pass
|
|
348
|
+
# +include_private+, because they do not get delegated.
|
|
349
|
+
|
|
350
|
+
return false if name == :marshal_dump || name == :_dump
|
|
351
|
+
#{target}.respond_to?(name) || super
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def method_missing(method, *args, &block)
|
|
355
|
+
__target = #{target}
|
|
356
|
+
if __target.nil? && !nil.respond_to?(method)
|
|
357
|
+
raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
|
|
358
|
+
elsif __target.respond_to?(method)
|
|
359
|
+
__target.public_send(method, *args, &block)
|
|
360
|
+
else
|
|
361
|
+
super
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
ruby2_keywords(:method_missing)
|
|
365
|
+
RUBY
|
|
366
|
+
end
|
|
352
367
|
end
|
|
353
368
|
end
|
|
@@ -28,23 +28,32 @@ class Object
|
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def duplicable?
|
|
37
|
-
false
|
|
38
|
-
end
|
|
31
|
+
methods_are_duplicable = begin
|
|
32
|
+
Object.instance_method(:duplicable?).dup
|
|
33
|
+
true
|
|
34
|
+
rescue TypeError
|
|
35
|
+
false
|
|
39
36
|
end
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
unless methods_are_duplicable
|
|
39
|
+
class Method
|
|
40
|
+
# Methods are not duplicable:
|
|
41
|
+
#
|
|
42
|
+
# method(:puts).duplicable? # => false
|
|
43
|
+
# method(:puts).dup # => TypeError: allocator undefined for Method
|
|
44
|
+
def duplicable?
|
|
45
|
+
false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class UnboundMethod
|
|
50
|
+
# Unbound methods are not duplicable:
|
|
51
|
+
#
|
|
52
|
+
# method(:puts).unbind.duplicable? # => false
|
|
53
|
+
# method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
|
|
54
|
+
def duplicable?
|
|
55
|
+
false
|
|
56
|
+
end
|
|
48
57
|
end
|
|
49
58
|
end
|
|
50
59
|
|
|
@@ -233,9 +233,11 @@ class Pathname # :nodoc:
|
|
|
233
233
|
end
|
|
234
234
|
end
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
unless IPAddr.method_defined?(:as_json, false)
|
|
237
|
+
class IPAddr # :nodoc:
|
|
238
|
+
def as_json(options = nil)
|
|
239
|
+
to_s
|
|
240
|
+
end
|
|
239
241
|
end
|
|
240
242
|
end
|
|
241
243
|
|
|
@@ -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"
|