activesupport 7.2.2.2 → 7.2.3
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 +143 -0
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +1 -1
- data/lib/active_support/broadcast_logger.rb +61 -74
- data/lib/active_support/cache/file_store.rb +2 -2
- data/lib/active_support/cache/mem_cache_store.rb +13 -15
- data/lib/active_support/cache/memory_store.rb +5 -5
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +1 -1
- data/lib/active_support/cache/strategy/local_cache.rb +56 -20
- data/lib/active_support/cache.rb +3 -3
- data/lib/active_support/callbacks.rb +3 -2
- data/lib/active_support/core_ext/benchmark.rb +1 -0
- data/lib/active_support/core_ext/class/attribute.rb +2 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/enumerable.rb +17 -5
- data/lib/active_support/core_ext/erb/util.rb +2 -2
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +1 -0
- data/lib/active_support/core_ext/securerandom.rb +24 -8
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/time/compatibility.rb +9 -1
- data/lib/active_support/current_attributes.rb +14 -7
- data/lib/active_support/error_reporter.rb +5 -2
- data/lib/active_support/execution_wrapper.rb +1 -1
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/hash_with_indifferent_access.rb +20 -16
- data/lib/active_support/json/decoding.rb +1 -1
- data/lib/active_support/json/encoding.rb +23 -5
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/message_encryptors.rb +2 -2
- data/lib/active_support/message_verifier.rb +9 -0
- data/lib/active_support/message_verifiers.rb +5 -3
- data/lib/active_support/messages/rotator.rb +5 -0
- data/lib/active_support/multibyte/chars.rb +4 -1
- data/lib/active_support/testing/parallelization/server.rb +15 -2
- data/lib/active_support/testing/parallelization/worker.rb +2 -2
- data/lib/active_support/testing/parallelization.rb +12 -1
- data/lib/active_support/xml_mini.rb +2 -0
- metadata +5 -5
- data/lib/active_support/testing/strict_warnings.rb +0 -43
|
@@ -11,7 +11,8 @@ class DateTime
|
|
|
11
11
|
#
|
|
12
12
|
# This method is aliased to <tt>to_formatted_s</tt>.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
14
|
+
# ==== Examples
|
|
15
|
+
#
|
|
15
16
|
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
|
|
16
17
|
#
|
|
17
18
|
# datetime.to_fs(:db) # => "2007-12-04 00:00:00"
|
|
@@ -23,7 +24,8 @@ class DateTime
|
|
|
23
24
|
# datetime.to_fs(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
|
|
24
25
|
# datetime.to_fs(:iso8601) # => "2007-12-04T00:00:00+00:00"
|
|
25
26
|
#
|
|
26
|
-
#
|
|
27
|
+
# ==== Adding your own datetime formats to +to_fs+
|
|
28
|
+
#
|
|
27
29
|
# DateTime formats are shared with Time. You can add your own to the
|
|
28
30
|
# Time::DATE_FORMATS hash. Use the format name as the hash key and
|
|
29
31
|
# either a strftime string or Proc instance that takes a time or
|
|
@@ -198,16 +198,28 @@ module Enumerable
|
|
|
198
198
|
end
|
|
199
199
|
|
|
200
200
|
# Returns the sole item in the enumerable. If there are no items, or more
|
|
201
|
-
# than one item, raises
|
|
201
|
+
# than one item, raises Enumerable::SoleItemExpectedError.
|
|
202
202
|
#
|
|
203
203
|
# ["x"].sole # => "x"
|
|
204
204
|
# Set.new.sole # => Enumerable::SoleItemExpectedError: no item found
|
|
205
205
|
# { a: 1, b: 2 }.sole # => Enumerable::SoleItemExpectedError: multiple items found
|
|
206
206
|
def sole
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
result = nil
|
|
208
|
+
found = false
|
|
209
|
+
|
|
210
|
+
each do |*element|
|
|
211
|
+
if found
|
|
212
|
+
raise SoleItemExpectedError, "multiple items found"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
result = element.size == 1 ? element[0] : element
|
|
216
|
+
found = true
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
if found
|
|
220
|
+
result
|
|
221
|
+
else
|
|
222
|
+
raise SoleItemExpectedError, "no item found"
|
|
211
223
|
end
|
|
212
224
|
end
|
|
213
225
|
end
|
|
@@ -174,7 +174,7 @@ class ERB
|
|
|
174
174
|
|
|
175
175
|
case source.matched
|
|
176
176
|
when start_re
|
|
177
|
-
tokens << [:TEXT, source.string
|
|
177
|
+
tokens << [:TEXT, source.string.byteslice(pos, len)] if len > 0
|
|
178
178
|
tokens << [:OPEN, source.matched]
|
|
179
179
|
if source.scan(/(.*?)(?=#{finish_re}|\z)/m)
|
|
180
180
|
tokens << [:CODE, source.matched] unless source.matched.empty?
|
|
@@ -183,7 +183,7 @@ class ERB
|
|
|
183
183
|
raise NotImplementedError
|
|
184
184
|
end
|
|
185
185
|
when finish_re
|
|
186
|
-
tokens << [:CODE, source.string
|
|
186
|
+
tokens << [:CODE, source.string.byteslice(pos, len)] if len > 0
|
|
187
187
|
tokens << [:CLOSE, source.matched]
|
|
188
188
|
else
|
|
189
189
|
raise NotImplementedError, source.matched
|
|
@@ -145,14 +145,14 @@ class NilClass
|
|
|
145
145
|
#
|
|
146
146
|
# With +try+
|
|
147
147
|
# @person.try(:children).try(:first).try(:name)
|
|
148
|
-
def try(
|
|
148
|
+
def try(*, &)
|
|
149
149
|
nil
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
# Calling +try!+ on +nil+ always returns +nil+.
|
|
153
153
|
#
|
|
154
154
|
# nil.try!(:name) # => nil
|
|
155
|
-
def try!(
|
|
155
|
+
def try!(*, &)
|
|
156
156
|
nil
|
|
157
157
|
end
|
|
158
158
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Range
|
|
4
|
+
# Returns the sole item in the range. If there are no items, or more
|
|
5
|
+
# than one item, raises Enumerable::SoleItemExpectedError.
|
|
6
|
+
#
|
|
7
|
+
# (1..1).sole # => 1
|
|
8
|
+
# (2..1).sole # => Enumerable::SoleItemExpectedError: no item found
|
|
9
|
+
# (..1).sole # => Enumerable::SoleItemExpectedError: infinite range cannot represent a sole item
|
|
10
|
+
def sole
|
|
11
|
+
if self.begin.nil? || self.end.nil?
|
|
12
|
+
raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "infinite range '#{inspect}' cannot represent a sole item"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -16,8 +16,18 @@ module SecureRandom
|
|
|
16
16
|
#
|
|
17
17
|
# p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
|
|
18
18
|
# p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
if SecureRandom.method(:alphanumeric).parameters.size == 2 # Remove check when Ruby 3.3 is the minimum supported version
|
|
20
|
+
def self.base58(n = 16)
|
|
21
|
+
alphanumeric(n, chars: BASE58_ALPHABET)
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
def self.base58(n = 16)
|
|
25
|
+
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
|
26
|
+
idx = byte % 64
|
|
27
|
+
idx = SecureRandom.random_number(58) if idx >= 58
|
|
28
|
+
BASE58_ALPHABET[idx]
|
|
29
|
+
end.join
|
|
30
|
+
end
|
|
21
31
|
end
|
|
22
32
|
|
|
23
33
|
# SecureRandom.base36 generates a random base36 string in lowercase.
|
|
@@ -31,11 +41,17 @@ module SecureRandom
|
|
|
31
41
|
#
|
|
32
42
|
# p SecureRandom.base36 # => "4kugl2pdqmscqtje"
|
|
33
43
|
# p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
if SecureRandom.method(:alphanumeric).parameters.size == 2 # Remove check when Ruby 3.3 is the minimum supported version
|
|
45
|
+
def self.base36(n = 16)
|
|
46
|
+
alphanumeric(n, chars: BASE36_ALPHABET)
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
def self.base36(n = 16)
|
|
50
|
+
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
|
51
|
+
idx = byte % 64
|
|
52
|
+
idx = SecureRandom.random_number(36) if idx >= 36
|
|
53
|
+
BASE36_ALPHABET[idx]
|
|
54
|
+
end.join
|
|
55
|
+
end
|
|
40
56
|
end
|
|
41
57
|
end
|
|
@@ -88,11 +88,11 @@ class String
|
|
|
88
88
|
# characters.
|
|
89
89
|
#
|
|
90
90
|
# >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".size
|
|
91
|
-
# => 20
|
|
91
|
+
# # => 20
|
|
92
92
|
# >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".bytesize
|
|
93
|
-
# => 80
|
|
93
|
+
# # => 80
|
|
94
94
|
# >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".truncate_bytes(20)
|
|
95
|
-
# => "🔪🔪🔪🔪…"
|
|
95
|
+
# # => "🔪🔪🔪🔪…"
|
|
96
96
|
#
|
|
97
97
|
# The truncated text ends with the <tt>:omission</tt> string, defaulting
|
|
98
98
|
# to "…", for a total length not exceeding <tt>truncate_to</tt>.
|
|
@@ -12,12 +12,12 @@ class String
|
|
|
12
12
|
# class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
|
|
13
13
|
#
|
|
14
14
|
# >> "lj".mb_chars.upcase.to_s
|
|
15
|
-
# => "LJ"
|
|
15
|
+
# # => "LJ"
|
|
16
16
|
#
|
|
17
17
|
# NOTE: Ruby 2.4 and later support native Unicode case mappings:
|
|
18
18
|
#
|
|
19
19
|
# >> "lj".upcase
|
|
20
|
-
# => "LJ"
|
|
20
|
+
# # => "LJ"
|
|
21
21
|
#
|
|
22
22
|
# == \Method chaining
|
|
23
23
|
#
|
|
@@ -15,10 +15,18 @@ class Time
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def preserve_timezone # :nodoc:
|
|
18
|
-
|
|
18
|
+
system_local_time? || super
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
private
|
|
22
|
+
def system_local_time?
|
|
23
|
+
if ::Time.equal?(self.class)
|
|
24
|
+
zone = self.zone
|
|
25
|
+
String === zone &&
|
|
26
|
+
(zone != "UTC" || active_support_local_zone == "UTC")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
22
30
|
@@active_support_local_tz = nil
|
|
23
31
|
|
|
24
32
|
def active_support_local_zone
|
|
@@ -108,15 +108,18 @@ module ActiveSupport
|
|
|
108
108
|
# ==== Options
|
|
109
109
|
#
|
|
110
110
|
# * <tt>:default</tt> - The default value for the attributes. If the value
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
111
|
+
# is a proc or lambda, it will be called whenever an instance is
|
|
112
|
+
# constructed. Otherwise, the value will be duplicated with +#dup+.
|
|
113
|
+
# Default values are re-assigned when the attributes are reset.
|
|
114
114
|
def attribute(*names, default: NOT_SET)
|
|
115
115
|
invalid_attribute_names = names.map(&:to_sym) & INVALID_ATTRIBUTE_NAMES
|
|
116
116
|
if invalid_attribute_names.any?
|
|
117
117
|
raise ArgumentError, "Restricted attribute names: #{invalid_attribute_names.join(", ")}"
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
+
Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
|
|
121
|
+
Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
|
|
122
|
+
|
|
120
123
|
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
|
|
121
124
|
names.each do |name|
|
|
122
125
|
owner.define_cached_method(name, namespace: :current_attributes) do |batch|
|
|
@@ -134,9 +137,6 @@ module ActiveSupport
|
|
|
134
137
|
end
|
|
135
138
|
end
|
|
136
139
|
|
|
137
|
-
Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
|
|
138
|
-
Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
|
|
139
|
-
|
|
140
140
|
self.defaults = defaults.merge(names.index_with { default })
|
|
141
141
|
end
|
|
142
142
|
|
|
@@ -185,9 +185,16 @@ module ActiveSupport
|
|
|
185
185
|
|
|
186
186
|
def method_added(name)
|
|
187
187
|
super
|
|
188
|
+
|
|
189
|
+
# We try to generate instance delegators early to not rely on method_missing.
|
|
188
190
|
return if name == :initialize
|
|
191
|
+
|
|
192
|
+
# If the added method isn't public, we don't delegate it.
|
|
189
193
|
return unless public_method_defined?(name)
|
|
190
|
-
|
|
194
|
+
|
|
195
|
+
# If we already have a class method by that name, we don't override it.
|
|
196
|
+
return if singleton_class.method_defined?(name) || singleton_class.private_method_defined?(name)
|
|
197
|
+
|
|
191
198
|
Delegation.generate(singleton_class, [name], to: :instance, as: self, nilable: false)
|
|
192
199
|
end
|
|
193
200
|
end
|
|
@@ -231,8 +231,11 @@ module ActiveSupport
|
|
|
231
231
|
end
|
|
232
232
|
end
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
error.
|
|
234
|
+
while error
|
|
235
|
+
unless error.frozen?
|
|
236
|
+
error.instance_variable_set(:@__rails_error_reported, true)
|
|
237
|
+
end
|
|
238
|
+
error = error.cause
|
|
236
239
|
end
|
|
237
240
|
|
|
238
241
|
nil
|
|
@@ -120,7 +120,7 @@ module ActiveSupport
|
|
|
120
120
|
# healthy to consider this edge case because with mtimes in the future
|
|
121
121
|
# reloading is not triggered.
|
|
122
122
|
def max_mtime(paths)
|
|
123
|
-
time_now = Time.
|
|
123
|
+
time_now = Time.at(0, Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond), :nanosecond)
|
|
124
124
|
max_mtime = nil
|
|
125
125
|
|
|
126
126
|
# Time comparisons are performed with #compare_without_coercion because
|
|
@@ -262,9 +262,7 @@ module ActiveSupport
|
|
|
262
262
|
# hash[:a][:c] # => "c"
|
|
263
263
|
# dup[:a][:c] # => "c"
|
|
264
264
|
def dup
|
|
265
|
-
self.class.new(self)
|
|
266
|
-
set_defaults(new_hash)
|
|
267
|
-
end
|
|
265
|
+
copy_defaults(self.class.new(self))
|
|
268
266
|
end
|
|
269
267
|
|
|
270
268
|
# This method has the same semantics of +update+, except it does not
|
|
@@ -342,21 +340,26 @@ module ActiveSupport
|
|
|
342
340
|
NOT_GIVEN = Object.new # :nodoc:
|
|
343
341
|
|
|
344
342
|
def transform_keys(hash = NOT_GIVEN, &block)
|
|
345
|
-
|
|
346
|
-
|
|
343
|
+
if NOT_GIVEN.equal?(hash)
|
|
344
|
+
if block_given?
|
|
345
|
+
self.class.new(super(&block))
|
|
346
|
+
else
|
|
347
|
+
to_enum(:transform_keys)
|
|
348
|
+
end
|
|
349
|
+
else
|
|
350
|
+
self.class.new(super)
|
|
351
|
+
end
|
|
347
352
|
end
|
|
348
353
|
|
|
349
354
|
def transform_keys!(hash = NOT_GIVEN, &block)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
elsif block_given?
|
|
357
|
-
keys.each { |key| self[hash[key] || yield(key)] = delete(key) }
|
|
355
|
+
if NOT_GIVEN.equal?(hash)
|
|
356
|
+
if block_given?
|
|
357
|
+
replace(copy_defaults(transform_keys(&block)))
|
|
358
|
+
else
|
|
359
|
+
return to_enum(:transform_keys!)
|
|
360
|
+
end
|
|
358
361
|
else
|
|
359
|
-
|
|
362
|
+
replace(copy_defaults(transform_keys(hash, &block)))
|
|
360
363
|
end
|
|
361
364
|
|
|
362
365
|
self
|
|
@@ -379,7 +382,7 @@ module ActiveSupport
|
|
|
379
382
|
# Convert to a regular hash with string keys.
|
|
380
383
|
def to_hash
|
|
381
384
|
_new_hash = Hash.new
|
|
382
|
-
|
|
385
|
+
copy_defaults(_new_hash)
|
|
383
386
|
|
|
384
387
|
each do |key, value|
|
|
385
388
|
_new_hash[key] = convert_value(value, conversion: :to_hash)
|
|
@@ -413,12 +416,13 @@ module ActiveSupport
|
|
|
413
416
|
end
|
|
414
417
|
end
|
|
415
418
|
|
|
416
|
-
def
|
|
419
|
+
def copy_defaults(target)
|
|
417
420
|
if default_proc
|
|
418
421
|
target.default_proc = default_proc.dup
|
|
419
422
|
else
|
|
420
423
|
target.default = default
|
|
421
424
|
end
|
|
425
|
+
target
|
|
422
426
|
end
|
|
423
427
|
|
|
424
428
|
def update_with_single_argument(other_hash, block)
|
|
@@ -18,7 +18,7 @@ module ActiveSupport
|
|
|
18
18
|
# See http://www.json.org for more info.
|
|
19
19
|
#
|
|
20
20
|
# ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
|
|
21
|
-
# => {"team" => "rails", "players" => "36"}
|
|
21
|
+
# # => {"team" => "rails", "players" => "36"}
|
|
22
22
|
def decode(json)
|
|
23
23
|
data = ::JSON.parse(json, quirks_mode: true)
|
|
24
24
|
|
|
@@ -13,12 +13,30 @@ module ActiveSupport
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
module JSON
|
|
16
|
-
# Dumps objects in JSON (JavaScript Object Notation).
|
|
17
|
-
# See http://www.json.org for more info.
|
|
18
|
-
#
|
|
19
|
-
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
20
|
-
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
21
16
|
class << self
|
|
17
|
+
# Dumps objects in JSON (JavaScript Object Notation).
|
|
18
|
+
# See http://www.json.org for more info.
|
|
19
|
+
#
|
|
20
|
+
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
21
|
+
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
22
|
+
#
|
|
23
|
+
# Generates JSON that is safe to include in JavaScript as it escapes
|
|
24
|
+
# U+2028 (Line Separator) and U+2029 (Paragraph Separator):
|
|
25
|
+
#
|
|
26
|
+
# ActiveSupport::JSON.encode({ key: "\u2028" })
|
|
27
|
+
# # => "{\"key\":\"\\u2028\"}"
|
|
28
|
+
#
|
|
29
|
+
# By default, it also generates JSON that is safe to include in HTML, as
|
|
30
|
+
# it escapes <tt><</tt>, <tt>></tt>, and <tt>&</tt>:
|
|
31
|
+
#
|
|
32
|
+
# ActiveSupport::JSON.encode({ key: "<>&" })
|
|
33
|
+
# # => "{\"key\":\"\\u003c\\u003e\\u0026\"}"
|
|
34
|
+
#
|
|
35
|
+
# This can be changed with the +escape_html_entities+ option, or the
|
|
36
|
+
# global escape_html_entities_in_json configuration option.
|
|
37
|
+
#
|
|
38
|
+
# ActiveSupport::JSON.encode({ key: "<>&" }, escape_html_entities: false)
|
|
39
|
+
# # => "{\"key\":\"<>&\"}"
|
|
22
40
|
def encode(value, options = nil)
|
|
23
41
|
Encoding.json_encoder.new(options).encode(value)
|
|
24
42
|
end
|
|
@@ -53,7 +53,7 @@ module ActiveSupport
|
|
|
53
53
|
# loaded. If the component has already loaded, the block is executed
|
|
54
54
|
# immediately.
|
|
55
55
|
#
|
|
56
|
-
# Options
|
|
56
|
+
# ==== Options
|
|
57
57
|
#
|
|
58
58
|
# * <tt>:yield</tt> - Yields the object that run_load_hooks to +block+.
|
|
59
59
|
# * <tt>:run_once</tt> - Given +block+ will run only once.
|
|
@@ -28,8 +28,8 @@ module ActiveSupport
|
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
29
|
|
|
30
30
|
##
|
|
31
|
-
# :method:
|
|
32
|
-
# :call-seq:
|
|
31
|
+
# :singleton-method: new
|
|
32
|
+
# :call-seq: new(&secret_generator)
|
|
33
33
|
#
|
|
34
34
|
# Initializes a new instance. +secret_generator+ must accept a salt and a
|
|
35
35
|
# +secret_length+ kwarg, and return a suitable secret (string) or secrets
|
|
@@ -154,6 +154,8 @@ module ActiveSupport
|
|
|
154
154
|
# not URL-safe. In other words, they can contain "+" and "/". If you want to
|
|
155
155
|
# generate URL-safe strings (in compliance with "Base 64 Encoding with URL
|
|
156
156
|
# and Filename Safe Alphabet" in RFC 4648), you can pass +true+.
|
|
157
|
+
# Note that MessageVerifier will always accept both URL-safe and URL-unsafe
|
|
158
|
+
# encoded messages, to allow a smooth transition between the two settings.
|
|
157
159
|
#
|
|
158
160
|
# [+:force_legacy_metadata_serializer+]
|
|
159
161
|
# Whether to use the legacy metadata serializer, which serializes the
|
|
@@ -318,6 +320,13 @@ module ActiveSupport
|
|
|
318
320
|
end
|
|
319
321
|
|
|
320
322
|
private
|
|
323
|
+
def decode(encoded, url_safe: @url_safe)
|
|
324
|
+
catch :invalid_message_format do
|
|
325
|
+
return super
|
|
326
|
+
end
|
|
327
|
+
super(encoded, url_safe: !url_safe)
|
|
328
|
+
end
|
|
329
|
+
|
|
321
330
|
def sign_encoded(encoded)
|
|
322
331
|
digest = generate_digest(encoded)
|
|
323
332
|
encoded << SEPARATOR << digest
|
|
@@ -28,8 +28,8 @@ module ActiveSupport
|
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
29
|
|
|
30
30
|
##
|
|
31
|
-
# :method:
|
|
32
|
-
# :call-seq:
|
|
31
|
+
# :singleton-method: new
|
|
32
|
+
# :call-seq: new(&secret_generator)
|
|
33
33
|
#
|
|
34
34
|
# Initializes a new instance. +secret_generator+ must accept a salt, and
|
|
35
35
|
# return a suitable secret (string). +secret_generator+ may also accept
|
|
@@ -59,7 +59,9 @@ module ActiveSupport
|
|
|
59
59
|
|
|
60
60
|
##
|
|
61
61
|
# :method: rotate
|
|
62
|
-
# :call-seq:
|
|
62
|
+
# :call-seq:
|
|
63
|
+
# rotate(**options)
|
|
64
|
+
# rotate(&block)
|
|
63
65
|
#
|
|
64
66
|
# Adds +options+ to the list of option sets. Messages will be signed using
|
|
65
67
|
# the first set in the list. When verifying, however, each set will be
|
|
@@ -55,7 +55,10 @@ module ActiveSupport # :nodoc:
|
|
|
55
55
|
# Creates a new Chars instance by wrapping _string_.
|
|
56
56
|
def initialize(string)
|
|
57
57
|
@wrapped_string = string
|
|
58
|
-
|
|
58
|
+
if string.encoding != Encoding::UTF_8
|
|
59
|
+
@wrapped_string = @wrapped_string.dup
|
|
60
|
+
@wrapped_string.force_encoding(Encoding::UTF_8)
|
|
61
|
+
end
|
|
59
62
|
end
|
|
60
63
|
|
|
61
64
|
# Forward all undefined methods to the wrapped string.
|
|
@@ -14,6 +14,7 @@ module ActiveSupport
|
|
|
14
14
|
def initialize
|
|
15
15
|
@queue = Queue.new
|
|
16
16
|
@active_workers = Concurrent::Map.new
|
|
17
|
+
@worker_pids = Concurrent::Map.new
|
|
17
18
|
@in_flight = Concurrent::Map.new
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -40,12 +41,24 @@ module ActiveSupport
|
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
def start_worker(worker_id)
|
|
44
|
+
def start_worker(worker_id, worker_pid)
|
|
44
45
|
@active_workers[worker_id] = true
|
|
46
|
+
@worker_pids[worker_id] = worker_pid
|
|
45
47
|
end
|
|
46
48
|
|
|
47
|
-
def stop_worker(worker_id)
|
|
49
|
+
def stop_worker(worker_id, worker_pid)
|
|
48
50
|
@active_workers.delete(worker_id)
|
|
51
|
+
@worker_pids.delete(worker_id)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def remove_dead_workers(dead_pids)
|
|
55
|
+
dead_pids.each do |dead_pid|
|
|
56
|
+
worker_id = @worker_pids.key(dead_pid)
|
|
57
|
+
if worker_id
|
|
58
|
+
@active_workers.delete(worker_id)
|
|
59
|
+
@worker_pids.delete(worker_id)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
49
62
|
end
|
|
50
63
|
|
|
51
64
|
def active_workers?
|
|
@@ -18,7 +18,7 @@ module ActiveSupport
|
|
|
18
18
|
DRb.stop_service
|
|
19
19
|
|
|
20
20
|
@queue = DRbObject.new_with_uri(@url)
|
|
21
|
-
@queue.start_worker(@id)
|
|
21
|
+
@queue.start_worker(@id, Process.pid)
|
|
22
22
|
|
|
23
23
|
begin
|
|
24
24
|
after_fork
|
|
@@ -29,7 +29,7 @@ module ActiveSupport
|
|
|
29
29
|
set_process_title("(stopping)")
|
|
30
30
|
|
|
31
31
|
run_cleanup
|
|
32
|
-
@queue.stop_worker(@id)
|
|
32
|
+
@queue.stop_worker(@id, Process.pid)
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
@@ -47,8 +47,19 @@ module ActiveSupport
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def shutdown
|
|
50
|
+
dead_worker_pids = @worker_pool.filter_map do |pid|
|
|
51
|
+
Process.waitpid(pid, Process::WNOHANG)
|
|
52
|
+
rescue Errno::ECHILD
|
|
53
|
+
pid
|
|
54
|
+
end
|
|
55
|
+
@queue_server.remove_dead_workers(dead_worker_pids)
|
|
56
|
+
|
|
50
57
|
@queue_server.shutdown
|
|
51
|
-
@worker_pool.each
|
|
58
|
+
@worker_pool.each do |pid|
|
|
59
|
+
Process.waitpid(pid)
|
|
60
|
+
rescue Errno::ECHILD
|
|
61
|
+
nil
|
|
62
|
+
end
|
|
52
63
|
end
|
|
53
64
|
end
|
|
54
65
|
end
|