activesupport 6.1.6.1 → 7.0.3.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +231 -515
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +15 -9
- data/lib/active_support/cache/mem_cache_store.rb +132 -37
- data/lib/active_support/cache/memory_store.rb +24 -16
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +47 -72
- data/lib/active_support/cache/strategy/local_cache.rb +38 -61
- data/lib/active_support/cache.rb +193 -46
- data/lib/active_support/callbacks.rb +184 -85
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +5 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +8 -5
- data/lib/active_support/configuration_file.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +25 -17
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +14 -14
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -14
- data/lib/active_support/core_ext/enumerable.rb +101 -32
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +0 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +30 -25
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +62 -38
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +7 -8
- data/lib/active_support/core_ext/time/conversions.rb +13 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -27
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/current_attributes.rb +31 -14
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +5 -2
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation.rb +2 -2
- data/lib/active_support/descendants_tracker.rb +174 -68
- data/lib/active_support/digest.rb +4 -4
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -1
- data/lib/active_support/duration.rb +77 -48
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +3 -5
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +30 -11
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +19 -12
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +1 -1
- data/lib/active_support/inflector/inflections.rb +23 -7
- data/lib/active_support/inflector/methods.rb +24 -48
- data/lib/active_support/inflector/transliterate.rb +1 -1
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +22 -5
- data/lib/active_support/lazy_load_hooks.rb +14 -3
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +15 -5
- data/lib/active_support/logger.rb +4 -5
- data/lib/active_support/logger_thread_safe_level.rb +4 -13
- data/lib/active_support/message_encryptor.rb +12 -6
- data/lib/active_support/message_verifier.rb +46 -14
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte/unicode.rb +0 -12
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +91 -65
- data/lib/active_support/notifications/instrumenter.rb +32 -15
- data/lib/active_support/notifications.rb +17 -23
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/rounding_helper.rb +1 -5
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +8 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +5 -0
- data/lib/active_support/per_thread_registry.rb +5 -1
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/rescuable.rb +4 -4
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +2 -2
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +7 -18
- data/lib/active_support/tagged_logging.rb +16 -1
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +35 -5
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +13 -2
- data/lib/active_support/time_with_zone.rb +58 -17
- data/lib/active_support/values/time_zone.rb +33 -14
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +16 -0
- metadata +23 -21
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -9,10 +9,6 @@ module ActiveSupport
|
|
9
9
|
module LoggerThreadSafeLevel # :nodoc:
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
|
-
included do
|
13
|
-
cattr_accessor :local_levels, default: Concurrent::Map.new(initial_capacity: 2), instance_accessor: false
|
14
|
-
end
|
15
|
-
|
16
12
|
Logger::Severity.constants.each do |severity|
|
17
13
|
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
|
18
14
|
def #{severity.downcase}? # def debug?
|
@@ -21,25 +17,20 @@ module ActiveSupport
|
|
21
17
|
EOT
|
22
18
|
end
|
23
19
|
|
24
|
-
def local_log_id
|
25
|
-
Fiber.current.__id__
|
26
|
-
end
|
27
|
-
|
28
20
|
def local_level
|
29
|
-
|
21
|
+
IsolatedExecutionState[:logger_thread_safe_level]
|
30
22
|
end
|
31
23
|
|
32
24
|
def local_level=(level)
|
33
25
|
case level
|
34
26
|
when Integer
|
35
|
-
self.class.local_levels[local_log_id] = level
|
36
27
|
when Symbol
|
37
|
-
|
28
|
+
level = Logger::Severity.const_get(level.to_s.upcase)
|
38
29
|
when nil
|
39
|
-
self.class.local_levels.delete(local_log_id)
|
40
30
|
else
|
41
31
|
raise ArgumentError, "Invalid log level: #{level.inspect}"
|
42
32
|
end
|
33
|
+
IsolatedExecutionState[:logger_thread_safe_level] = level
|
43
34
|
end
|
44
35
|
|
45
36
|
def level
|
@@ -56,7 +47,7 @@ module ActiveSupport
|
|
56
47
|
|
57
48
|
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
|
58
49
|
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
|
59
|
-
def add(severity, message = nil, progname = nil, &block)
|
50
|
+
def add(severity, message = nil, progname = nil, &block) # :nodoc:
|
60
51
|
severity ||= UNKNOWN
|
61
52
|
progname ||= @progname
|
62
53
|
|
@@ -13,7 +13,7 @@ module ActiveSupport
|
|
13
13
|
# The cipher text and initialization vector are base64 encoded and returned
|
14
14
|
# to you.
|
15
15
|
#
|
16
|
-
# This can be used in situations similar to the
|
16
|
+
# This can be used in situations similar to the MessageVerifier, but
|
17
17
|
# where you don't want users to be able to determine the value of the payload.
|
18
18
|
#
|
19
19
|
# len = ActiveSupport::MessageEncryptor.key_len
|
@@ -23,6 +23,12 @@ module ActiveSupport
|
|
23
23
|
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
|
24
24
|
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
|
25
25
|
#
|
26
|
+
# The +decrypt_and_verify+ method will raise an
|
27
|
+
# <tt>ActiveSupport::MessageEncryptor::InvalidMessage</tt> exception if the data
|
28
|
+
# provided cannot be decrypted or verified.
|
29
|
+
#
|
30
|
+
# crypt.decrypt_and_verify('not encrypted data') # => ActiveSupport::MessageEncryptor::InvalidMessage
|
31
|
+
#
|
26
32
|
# === Confining messages to a specific purpose
|
27
33
|
#
|
28
34
|
# By default any message can be used throughout your app. But they can also be
|
@@ -84,7 +90,7 @@ module ActiveSupport
|
|
84
90
|
cattr_accessor :use_authenticated_message_encryption, instance_accessor: false, default: false
|
85
91
|
|
86
92
|
class << self
|
87
|
-
def default_cipher
|
93
|
+
def default_cipher # :nodoc:
|
88
94
|
if use_authenticated_message_encryption
|
89
95
|
"aes-256-gcm"
|
90
96
|
else
|
@@ -93,7 +99,7 @@ module ActiveSupport
|
|
93
99
|
end
|
94
100
|
end
|
95
101
|
|
96
|
-
module NullSerializer
|
102
|
+
module NullSerializer # :nodoc:
|
97
103
|
def self.load(value)
|
98
104
|
value
|
99
105
|
end
|
@@ -103,7 +109,7 @@ module ActiveSupport
|
|
103
109
|
end
|
104
110
|
end
|
105
111
|
|
106
|
-
module NullVerifier
|
112
|
+
module NullVerifier # :nodoc:
|
107
113
|
def self.verify(value)
|
108
114
|
value
|
109
115
|
end
|
@@ -119,10 +125,10 @@ module ActiveSupport
|
|
119
125
|
# Initialize a new MessageEncryptor. +secret+ must be at least as long as
|
120
126
|
# the cipher key size. For the default 'aes-256-gcm' cipher, this is 256
|
121
127
|
# bits. If you are using a user-entered secret, you can generate a suitable
|
122
|
-
# key by using
|
128
|
+
# key by using ActiveSupport::KeyGenerator or a similar key
|
123
129
|
# derivation function.
|
124
130
|
#
|
125
|
-
# First additional parameter is used as the signature key for
|
131
|
+
# First additional parameter is used as the signature key for MessageVerifier.
|
126
132
|
# This allows you to specify keys to encrypt and sign data.
|
127
133
|
#
|
128
134
|
# ActiveSupport::MessageEncryptor.new('secret', 'signature_secret')
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "openssl"
|
3
4
|
require "base64"
|
4
5
|
require "active_support/core_ext/object/blank"
|
5
6
|
require "active_support/security_utils"
|
@@ -68,8 +69,8 @@ module ActiveSupport
|
|
68
69
|
# return the original value. But messages can be set to expire at a given
|
69
70
|
# time with +:expires_in+ or +:expires_at+.
|
70
71
|
#
|
71
|
-
# @verifier.generate(parcel, expires_in: 1.month)
|
72
|
-
# @verifier.generate(doowad, expires_at: Time.now.end_of_year)
|
72
|
+
# @verifier.generate("parcel", expires_in: 1.month)
|
73
|
+
# @verifier.generate("doowad", expires_at: Time.now.end_of_year)
|
73
74
|
#
|
74
75
|
# Then the messages can be verified and returned up to the expire time.
|
75
76
|
# Thereafter, the +verified+ method returns +nil+ while +verify+ raises
|
@@ -78,8 +79,8 @@ module ActiveSupport
|
|
78
79
|
# === Rotating keys
|
79
80
|
#
|
80
81
|
# MessageVerifier also supports rotating out old configurations by falling
|
81
|
-
# back to a stack of verifiers. Call +rotate+ to build and add a verifier
|
82
|
-
#
|
82
|
+
# back to a stack of verifiers. Call +rotate+ to build and add a verifier so
|
83
|
+
# either +verified+ or +verify+ will also try verifying with the fallback.
|
83
84
|
#
|
84
85
|
# By default any rotated verifiers use the values of the primary
|
85
86
|
# verifier unless specified otherwise.
|
@@ -103,10 +104,13 @@ module ActiveSupport
|
|
103
104
|
|
104
105
|
class InvalidSignature < StandardError; end
|
105
106
|
|
107
|
+
SEPARATOR = "--" # :nodoc:
|
108
|
+
SEPARATOR_LENGTH = SEPARATOR.length # :nodoc:
|
109
|
+
|
106
110
|
def initialize(secret, digest: nil, serializer: nil)
|
107
111
|
raise ArgumentError, "Secret should not be nil." unless secret
|
108
112
|
@secret = secret
|
109
|
-
@digest = digest || "SHA1"
|
113
|
+
@digest = digest&.to_s || "SHA1"
|
110
114
|
@serializer = serializer || Marshal
|
111
115
|
end
|
112
116
|
|
@@ -120,10 +124,8 @@ module ActiveSupport
|
|
120
124
|
# tampered_message = signed_message.chop # editing the message invalidates the signature
|
121
125
|
# verifier.valid_message?(tampered_message) # => false
|
122
126
|
def valid_message?(signed_message)
|
123
|
-
|
124
|
-
|
125
|
-
data, digest = signed_message.split("--")
|
126
|
-
data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
|
127
|
+
data, digest = get_data_and_digest_from(signed_message)
|
128
|
+
digest_matches_data?(digest, data)
|
127
129
|
end
|
128
130
|
|
129
131
|
# Decodes the signed message using the +MessageVerifier+'s secret.
|
@@ -148,9 +150,9 @@ module ActiveSupport
|
|
148
150
|
# incompatible_message = "test--dad7b06c94abba8d46a15fafaef56c327665d5ff"
|
149
151
|
# verifier.verified(incompatible_message) # => TypeError: incompatible marshal file format
|
150
152
|
def verified(signed_message, purpose: nil, **)
|
151
|
-
|
153
|
+
data, digest = get_data_and_digest_from(signed_message)
|
154
|
+
if digest_matches_data?(digest, data)
|
152
155
|
begin
|
153
|
-
data = signed_message.split("--")[0]
|
154
156
|
message = Messages::Metadata.verify(decode(data), purpose)
|
155
157
|
@serializer.load(message) if message
|
156
158
|
rescue ArgumentError => argument_error
|
@@ -185,7 +187,7 @@ module ActiveSupport
|
|
185
187
|
# verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772"
|
186
188
|
def generate(value, expires_at: nil, expires_in: nil, purpose: nil)
|
187
189
|
data = encode(Messages::Metadata.wrap(@serializer.dump(value), expires_at: expires_at, expires_in: expires_in, purpose: purpose))
|
188
|
-
"#{data}
|
190
|
+
"#{data}#{SEPARATOR}#{generate_digest(data)}"
|
189
191
|
end
|
190
192
|
|
191
193
|
private
|
@@ -198,8 +200,38 @@ module ActiveSupport
|
|
198
200
|
end
|
199
201
|
|
200
202
|
def generate_digest(data)
|
201
|
-
|
202
|
-
|
203
|
+
OpenSSL::HMAC.hexdigest(@digest, @secret, data)
|
204
|
+
end
|
205
|
+
|
206
|
+
def digest_length_in_hex
|
207
|
+
# In hexadecimal (AKA base16) it takes 4 bits to represent a character,
|
208
|
+
# hence we multiply the digest's length (in bytes) by 8 to get it in
|
209
|
+
# bits and divide by 4 to get its number of characters it hex. Well, 8
|
210
|
+
# divided by 4 is 2.
|
211
|
+
@digest_length_in_hex ||= OpenSSL::Digest.new(@digest).digest_length * 2
|
212
|
+
end
|
213
|
+
|
214
|
+
def separator_index_for(signed_message)
|
215
|
+
index = signed_message.length - digest_length_in_hex - SEPARATOR_LENGTH
|
216
|
+
return if index.negative? || signed_message[index, SEPARATOR_LENGTH] != SEPARATOR
|
217
|
+
|
218
|
+
index
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_data_and_digest_from(signed_message)
|
222
|
+
return if signed_message.nil? || !signed_message.valid_encoding? || signed_message.empty?
|
223
|
+
|
224
|
+
separator_index = separator_index_for(signed_message)
|
225
|
+
return if separator_index.nil?
|
226
|
+
|
227
|
+
data = signed_message[0...separator_index]
|
228
|
+
digest = signed_message[separator_index + SEPARATOR_LENGTH..-1]
|
229
|
+
|
230
|
+
[data, digest]
|
231
|
+
end
|
232
|
+
|
233
|
+
def digest_matches_data?(digest, data)
|
234
|
+
data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
|
203
235
|
end
|
204
236
|
end
|
205
237
|
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require "time"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
module Messages
|
7
|
-
class Metadata
|
6
|
+
module Messages # :nodoc:
|
7
|
+
class Metadata # :nodoc:
|
8
8
|
def initialize(message, expires_at = nil, purpose = nil)
|
9
9
|
@message, @purpose = message, purpose
|
10
10
|
@expires_at = expires_at.is_a?(String) ? parse_expires_at(expires_at) : expires_at
|
@@ -3,11 +3,10 @@
|
|
3
3
|
require "active_support/json"
|
4
4
|
require "active_support/core_ext/string/access"
|
5
5
|
require "active_support/core_ext/string/behavior"
|
6
|
-
require "active_support/core_ext/symbol/starts_ends_with"
|
7
6
|
require "active_support/core_ext/module/delegation"
|
8
7
|
|
9
|
-
module ActiveSupport
|
10
|
-
module Multibyte
|
8
|
+
module ActiveSupport # :nodoc:
|
9
|
+
module Multibyte # :nodoc:
|
11
10
|
# Chars enables you to work transparently with UTF-8 encoding in the Ruby
|
12
11
|
# String class without having extensive knowledge about the encoding. A
|
13
12
|
# Chars object accepts a string upon initialization and proxies String
|
@@ -103,7 +102,7 @@ module ActiveSupport #:nodoc:
|
|
103
102
|
#
|
104
103
|
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
|
105
104
|
def reverse
|
106
|
-
chars(@wrapped_string.
|
105
|
+
chars(@wrapped_string.grapheme_clusters.reverse.join)
|
107
106
|
end
|
108
107
|
|
109
108
|
# Limits the byte size of the string to a number of bytes without breaking
|
@@ -126,16 +125,16 @@ module ActiveSupport #:nodoc:
|
|
126
125
|
|
127
126
|
# Performs canonical decomposition on all the characters.
|
128
127
|
#
|
129
|
-
# 'é'.length # =>
|
130
|
-
# 'é'.mb_chars.decompose.to_s.length # =>
|
128
|
+
# 'é'.length # => 1
|
129
|
+
# 'é'.mb_chars.decompose.to_s.length # => 2
|
131
130
|
def decompose
|
132
131
|
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack("U*"))
|
133
132
|
end
|
134
133
|
|
135
134
|
# Performs composition on all the characters.
|
136
135
|
#
|
137
|
-
# 'é'.length # =>
|
138
|
-
# 'é'.mb_chars.compose.to_s.length # =>
|
136
|
+
# 'é'.length # => 1
|
137
|
+
# 'é'.mb_chars.compose.to_s.length # => 1
|
139
138
|
def compose
|
140
139
|
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack("U*"))
|
141
140
|
end
|
@@ -143,9 +142,9 @@ module ActiveSupport #:nodoc:
|
|
143
142
|
# Returns the number of grapheme clusters in the string.
|
144
143
|
#
|
145
144
|
# 'क्षि'.mb_chars.length # => 4
|
146
|
-
# 'क्षि'.mb_chars.grapheme_length # =>
|
145
|
+
# 'क्षि'.mb_chars.grapheme_length # => 2
|
147
146
|
def grapheme_length
|
148
|
-
@wrapped_string.
|
147
|
+
@wrapped_string.grapheme_clusters.length
|
149
148
|
end
|
150
149
|
|
151
150
|
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
|
@@ -157,7 +156,7 @@ module ActiveSupport #:nodoc:
|
|
157
156
|
chars(Unicode.tidy_bytes(@wrapped_string, force))
|
158
157
|
end
|
159
158
|
|
160
|
-
def as_json(options = nil)
|
159
|
+
def as_json(options = nil) # :nodoc:
|
161
160
|
to_s.as_json(options)
|
162
161
|
end
|
163
162
|
|
@@ -8,18 +8,6 @@ module ActiveSupport
|
|
8
8
|
# The Unicode version that is supported by the implementation
|
9
9
|
UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
|
10
10
|
|
11
|
-
def default_normalization_form
|
12
|
-
ActiveSupport::Deprecation.warn(
|
13
|
-
"ActiveSupport::Multibyte::Unicode.default_normalization_form is deprecated and will be removed in Rails 7.0."
|
14
|
-
)
|
15
|
-
end
|
16
|
-
|
17
|
-
def default_normalization_form=(_)
|
18
|
-
ActiveSupport::Deprecation.warn(
|
19
|
-
"ActiveSupport::Multibyte::Unicode.default_normalization_form= is deprecated and will be removed in Rails 7.0."
|
20
|
-
)
|
21
|
-
end
|
22
|
-
|
23
11
|
# Decompose composed characters to the decomposed form.
|
24
12
|
def decompose(type, codepoints)
|
25
13
|
if type == :compatibility
|
@@ -7,6 +7,16 @@ require "active_support/core_ext/object/try"
|
|
7
7
|
|
8
8
|
module ActiveSupport
|
9
9
|
module Notifications
|
10
|
+
class InstrumentationSubscriberError < RuntimeError
|
11
|
+
attr_reader :exceptions
|
12
|
+
|
13
|
+
def initialize(exceptions)
|
14
|
+
@exceptions = exceptions
|
15
|
+
exception_class_names = exceptions.map { |e| e.class.name }
|
16
|
+
super "Exception(s) occurred within instrumentation subscribers: #{exception_class_names.join(', ')}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
10
20
|
# This is a default queue implementation that ships with Notifications.
|
11
21
|
# It just pushes events to all registered log subscribers.
|
12
22
|
#
|
@@ -24,12 +34,15 @@ module ActiveSupport
|
|
24
34
|
def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
|
25
35
|
subscriber = Subscribers.new(pattern, callable || block, monotonic)
|
26
36
|
synchronize do
|
27
|
-
|
37
|
+
case pattern
|
38
|
+
when String
|
28
39
|
@string_subscribers[pattern] << subscriber
|
29
40
|
@listeners_for.delete(pattern)
|
30
|
-
|
41
|
+
when NilClass, Regexp
|
31
42
|
@other_subscribers << subscriber
|
32
43
|
@listeners_for.clear
|
44
|
+
else
|
45
|
+
raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
|
33
46
|
end
|
34
47
|
end
|
35
48
|
subscriber
|
@@ -56,15 +69,40 @@ module ActiveSupport
|
|
56
69
|
end
|
57
70
|
|
58
71
|
def start(name, id, payload)
|
59
|
-
listeners_for(name)
|
72
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.start(name, id, payload) }
|
60
73
|
end
|
61
74
|
|
62
75
|
def finish(name, id, payload, listeners = listeners_for(name))
|
63
|
-
listeners
|
76
|
+
iterate_guarding_exceptions(listeners) { |s| s.finish(name, id, payload) }
|
64
77
|
end
|
65
78
|
|
66
79
|
def publish(name, *args)
|
67
|
-
listeners_for(name)
|
80
|
+
iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, *args) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def publish_event(event)
|
84
|
+
iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def iterate_guarding_exceptions(listeners)
|
88
|
+
exceptions = nil
|
89
|
+
|
90
|
+
listeners.each do |s|
|
91
|
+
yield s
|
92
|
+
rescue Exception => e
|
93
|
+
exceptions ||= []
|
94
|
+
exceptions << e
|
95
|
+
end
|
96
|
+
|
97
|
+
if exceptions
|
98
|
+
if exceptions.size == 1
|
99
|
+
raise exceptions.first
|
100
|
+
else
|
101
|
+
raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
listeners
|
68
106
|
end
|
69
107
|
|
70
108
|
def listeners_for(name)
|
@@ -91,33 +129,30 @@ module ActiveSupport
|
|
91
129
|
if listener.respond_to?(:start) && listener.respond_to?(:finish)
|
92
130
|
subscriber_class = Evented
|
93
131
|
else
|
94
|
-
# Doing
|
95
|
-
# `proc {
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
132
|
+
# Doing this to detect a single argument block or callable
|
133
|
+
# like `proc { |x| }` vs `proc { |*x| }`, `proc { |**x| }`,
|
134
|
+
# or `proc { |x, **y| }`
|
135
|
+
procish = listener.respond_to?(:parameters) ? listener : listener.method(:call)
|
136
|
+
|
137
|
+
if procish.arity == 1 && procish.parameters.length == 1
|
138
|
+
subscriber_class = EventObject
|
101
139
|
end
|
102
140
|
end
|
103
141
|
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.wrap_all(pattern, subscriber)
|
108
|
-
unless pattern
|
109
|
-
AllMessages.new(subscriber)
|
110
|
-
else
|
111
|
-
subscriber
|
112
|
-
end
|
142
|
+
subscriber_class.new(pattern, listener)
|
113
143
|
end
|
114
144
|
|
115
|
-
class Matcher
|
145
|
+
class Matcher # :nodoc:
|
116
146
|
attr_reader :pattern, :exclusions
|
117
147
|
|
118
148
|
def self.wrap(pattern)
|
119
|
-
|
120
|
-
|
149
|
+
if String === pattern
|
150
|
+
pattern
|
151
|
+
elsif pattern.nil?
|
152
|
+
AllMessages.new
|
153
|
+
else
|
154
|
+
new(pattern)
|
155
|
+
end
|
121
156
|
end
|
122
157
|
|
123
158
|
def initialize(pattern)
|
@@ -132,15 +167,26 @@ module ActiveSupport
|
|
132
167
|
def ===(name)
|
133
168
|
pattern === name && !exclusions.include?(name)
|
134
169
|
end
|
170
|
+
|
171
|
+
class AllMessages
|
172
|
+
def ===(name)
|
173
|
+
true
|
174
|
+
end
|
175
|
+
|
176
|
+
def unsubscribe!(*)
|
177
|
+
false
|
178
|
+
end
|
179
|
+
end
|
135
180
|
end
|
136
181
|
|
137
|
-
class Evented
|
182
|
+
class Evented # :nodoc:
|
138
183
|
attr_reader :pattern
|
139
184
|
|
140
185
|
def initialize(pattern, delegate)
|
141
186
|
@pattern = Matcher.wrap(pattern)
|
142
187
|
@delegate = delegate
|
143
188
|
@can_publish = delegate.respond_to?(:publish)
|
189
|
+
@can_publish_event = delegate.respond_to?(:publish_event)
|
144
190
|
end
|
145
191
|
|
146
192
|
def publish(name, *args)
|
@@ -149,6 +195,14 @@ module ActiveSupport
|
|
149
195
|
end
|
150
196
|
end
|
151
197
|
|
198
|
+
def publish_event(event)
|
199
|
+
if @can_publish_event
|
200
|
+
@delegate.publish_event event
|
201
|
+
else
|
202
|
+
publish(event.name, event.time, event.end, event.transaction_id, event.payload)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
152
206
|
def start(name, id, payload)
|
153
207
|
@delegate.start name, id, payload
|
154
208
|
end
|
@@ -161,10 +215,6 @@ module ActiveSupport
|
|
161
215
|
pattern === name
|
162
216
|
end
|
163
217
|
|
164
|
-
def matches?(name)
|
165
|
-
pattern && pattern === name
|
166
|
-
end
|
167
|
-
|
168
218
|
def unsubscribe!(name)
|
169
219
|
pattern.unsubscribe!(name)
|
170
220
|
end
|
@@ -176,12 +226,12 @@ module ActiveSupport
|
|
176
226
|
end
|
177
227
|
|
178
228
|
def start(name, id, payload)
|
179
|
-
timestack =
|
229
|
+
timestack = IsolatedExecutionState[:_timestack] ||= []
|
180
230
|
timestack.push Time.now
|
181
231
|
end
|
182
232
|
|
183
233
|
def finish(name, id, payload)
|
184
|
-
timestack =
|
234
|
+
timestack = IsolatedExecutionState[:_timestack]
|
185
235
|
started = timestack.pop
|
186
236
|
@delegate.call(name, started, Time.now, id, payload)
|
187
237
|
end
|
@@ -193,66 +243,42 @@ module ActiveSupport
|
|
193
243
|
end
|
194
244
|
|
195
245
|
def start(name, id, payload)
|
196
|
-
timestack =
|
197
|
-
timestack.push
|
246
|
+
timestack = IsolatedExecutionState[:_timestack_monotonic] ||= []
|
247
|
+
timestack.push Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
198
248
|
end
|
199
249
|
|
200
250
|
def finish(name, id, payload)
|
201
|
-
timestack =
|
251
|
+
timestack = IsolatedExecutionState[:_timestack_monotonic]
|
202
252
|
started = timestack.pop
|
203
|
-
@delegate.call(name, started,
|
253
|
+
@delegate.call(name, started, Process.clock_gettime(Process::CLOCK_MONOTONIC), id, payload)
|
204
254
|
end
|
205
255
|
end
|
206
256
|
|
207
257
|
class EventObject < Evented
|
208
258
|
def start(name, id, payload)
|
209
|
-
stack =
|
259
|
+
stack = IsolatedExecutionState[:_event_stack] ||= []
|
210
260
|
event = build_event name, id, payload
|
211
261
|
event.start!
|
212
262
|
stack.push event
|
213
263
|
end
|
214
264
|
|
215
265
|
def finish(name, id, payload)
|
216
|
-
stack =
|
266
|
+
stack = IsolatedExecutionState[:_event_stack]
|
217
267
|
event = stack.pop
|
218
268
|
event.payload = payload
|
219
269
|
event.finish!
|
220
270
|
@delegate.call event
|
221
271
|
end
|
222
272
|
|
273
|
+
def publish_event(event)
|
274
|
+
@delegate.call event
|
275
|
+
end
|
276
|
+
|
223
277
|
private
|
224
278
|
def build_event(name, id, payload)
|
225
279
|
ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
|
226
280
|
end
|
227
281
|
end
|
228
|
-
|
229
|
-
class AllMessages # :nodoc:
|
230
|
-
def initialize(delegate)
|
231
|
-
@delegate = delegate
|
232
|
-
end
|
233
|
-
|
234
|
-
def start(name, id, payload)
|
235
|
-
@delegate.start name, id, payload
|
236
|
-
end
|
237
|
-
|
238
|
-
def finish(name, id, payload)
|
239
|
-
@delegate.finish name, id, payload
|
240
|
-
end
|
241
|
-
|
242
|
-
def publish(name, *args)
|
243
|
-
@delegate.publish name, *args
|
244
|
-
end
|
245
|
-
|
246
|
-
def subscribed_to?(name)
|
247
|
-
true
|
248
|
-
end
|
249
|
-
|
250
|
-
def unsubscribe!(*)
|
251
|
-
false
|
252
|
-
end
|
253
|
-
|
254
|
-
alias :matches? :===
|
255
|
-
end
|
256
282
|
end
|
257
283
|
end
|
258
284
|
end
|