activesupport 7.2.3.1 → 8.1.4.1
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 +584 -234
- data/lib/active_support/backtrace_cleaner.rb +72 -1
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/cache/file_store.rb +13 -2
- data/lib/active_support/cache/mem_cache_store.rb +17 -14
- data/lib/active_support/cache/memory_store.rb +9 -3
- data/lib/active_support/cache/redis_cache_store.rb +51 -34
- data/lib/active_support/cache/strategy/local_cache.rb +17 -8
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +86 -18
- data/lib/active_support/callbacks.rb +25 -11
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -3
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +0 -16
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +24 -18
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/date/conversions.rb +2 -0
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +8 -3
- data/lib/active_support/core_ext/erb/util.rb +3 -3
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/attr_internal.rb +3 -4
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +24 -11
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +2 -14
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/range/sole.rb +2 -0
- data/lib/active_support/core_ext/range.rb +4 -5
- data/lib/active_support/core_ext/string/filters.rb +2 -0
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/multibyte.rb +10 -1
- data/lib/active_support/core_ext/string/output_safety.rb +27 -13
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +11 -2
- data/lib/active_support/core_ext/time/compatibility.rb +2 -27
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +13 -10
- data/lib/active_support/delegation.rb +25 -44
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -2
- data/lib/active_support/deprecation/reporting.rb +4 -21
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration.rb +20 -16
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/error_reporter.rb +76 -2
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -2
- data/lib/active_support/execution_context.rb +75 -7
- data/lib/active_support/file_update_checker.rb +7 -5
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +44 -24
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +34 -16
- data/lib/active_support/inflector/methods.rb +6 -22
- data/lib/active_support/inflector/transliterate.rb +18 -10
- data/lib/active_support/isolated_execution_state.rb +17 -17
- data/lib/active_support/json/decoding.rb +9 -3
- data/lib/active_support/json/encoding.rb +149 -19
- data/lib/active_support/log_subscriber.rb +2 -6
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- data/lib/active_support/message_encryptors.rb +52 -0
- data/lib/active_support/message_pack/extensions.rb +23 -1
- data/lib/active_support/message_verifiers.rb +52 -0
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +5 -0
- data/lib/active_support/messages/serializer_with_fallback.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +8 -1
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +64 -43
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/notifications.rb +2 -2
- data/lib/active_support/number_helper/number_converter.rb +4 -1
- data/lib/active_support/number_helper/number_to_currency_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -4
- data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -7
- data/lib/active_support/number_helper/rounding_helper.rb +1 -1
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/ordered_options.rb +2 -2
- data/lib/active_support/railtie.rb +32 -9
- data/lib/active_support/security_utils.rb +4 -5
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +0 -5
- data/lib/active_support/syntax_error_proxy.rb +9 -1
- data/lib/active_support/tagged_logging.rb +5 -0
- data/lib/active_support/test_case.rb +67 -6
- data/lib/active_support/testing/assertions.rb +118 -27
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/error_reporter_assertions.rb +17 -0
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/worker.rb +7 -1
- data/lib/active_support/testing/parallelization.rb +17 -0
- data/lib/active_support/testing/tests_without_assertions.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +9 -4
- data/lib/active_support/time_with_zone.rb +36 -23
- data/lib/active_support/values/time_zone.rb +22 -13
- data/lib/active_support/xml_mini.rb +1 -2
- data/lib/active_support.rb +21 -9
- metadata +33 -17
- data/lib/active_support/core_ext/range/each.rb +0 -24
- data/lib/active_support/proxy_object.rb +0 -20
|
@@ -14,13 +14,19 @@ module ActiveSupport
|
|
|
14
14
|
DATETIME_REGEX = /\A(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)\z/
|
|
15
15
|
|
|
16
16
|
class << self
|
|
17
|
-
# Parses a JSON string (JavaScript Object Notation) into a
|
|
17
|
+
# Parses a JSON string (JavaScript Object Notation) into a Ruby object.
|
|
18
18
|
# See http://www.json.org for more info.
|
|
19
19
|
#
|
|
20
20
|
# ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
|
|
21
21
|
# # => {"team" => "rails", "players" => "36"}
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
# ActiveSupport::JSON.decode("2.39")
|
|
23
|
+
# # => 2.39
|
|
24
|
+
def decode(json, options = nil)
|
|
25
|
+
data = if options
|
|
26
|
+
::JSON.parse(json, **options)
|
|
27
|
+
else
|
|
28
|
+
::JSON.parse(json)
|
|
29
|
+
end
|
|
24
30
|
|
|
25
31
|
if ActiveSupport.parse_json_times
|
|
26
32
|
convert_dates_from(data)
|
|
@@ -8,6 +8,7 @@ module ActiveSupport
|
|
|
8
8
|
delegate :use_standard_json_time_format, :use_standard_json_time_format=,
|
|
9
9
|
:time_precision, :time_precision=,
|
|
10
10
|
:escape_html_entities_in_json, :escape_html_entities_in_json=,
|
|
11
|
+
:escape_js_separators_in_json, :escape_js_separators_in_json=,
|
|
11
12
|
:json_encoder, :json_encoder=,
|
|
12
13
|
to: :'ActiveSupport::JSON::Encoding'
|
|
13
14
|
end
|
|
@@ -20,8 +21,8 @@ module ActiveSupport
|
|
|
20
21
|
# ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
|
|
21
22
|
# # => "{\"team\":\"rails\",\"players\":\"36\"}"
|
|
22
23
|
#
|
|
23
|
-
#
|
|
24
|
-
# U+2028 (Line Separator) and U+2029 (Paragraph Separator):
|
|
24
|
+
# By default, it generates JSON that is safe to include in JavaScript, as
|
|
25
|
+
# it escapes U+2028 (Line Separator) and U+2029 (Paragraph Separator):
|
|
25
26
|
#
|
|
26
27
|
# ActiveSupport::JSON.encode({ key: "\u2028" })
|
|
27
28
|
# # => "{\"key\":\"\\u2028\"}"
|
|
@@ -32,18 +33,45 @@ module ActiveSupport
|
|
|
32
33
|
# ActiveSupport::JSON.encode({ key: "<>&" })
|
|
33
34
|
# # => "{\"key\":\"\\u003c\\u003e\\u0026\"}"
|
|
34
35
|
#
|
|
35
|
-
# This can be changed with the +escape_html_entities+ option, or the
|
|
36
|
+
# This behavior can be changed with the +escape_html_entities+ option, or the
|
|
36
37
|
# global escape_html_entities_in_json configuration option.
|
|
37
38
|
#
|
|
38
39
|
# ActiveSupport::JSON.encode({ key: "<>&" }, escape_html_entities: false)
|
|
39
40
|
# # => "{\"key\":\"<>&\"}"
|
|
41
|
+
#
|
|
42
|
+
# For performance reasons, you can set the +escape+ option to false,
|
|
43
|
+
# which will skip all escaping:
|
|
44
|
+
#
|
|
45
|
+
# ActiveSupport::JSON.encode({ key: "\u2028<>&" }, escape: false)
|
|
46
|
+
# # => "{\"key\":\"\u2028<>&\"}"
|
|
40
47
|
def encode(value, options = nil)
|
|
41
|
-
|
|
48
|
+
if options.nil? || options.empty?
|
|
49
|
+
Encoding.encode_without_options(value)
|
|
50
|
+
elsif options == { escape: false }.freeze
|
|
51
|
+
Encoding.encode_without_escape(value)
|
|
52
|
+
else
|
|
53
|
+
Encoding.json_encoder.new(options).encode(value)
|
|
54
|
+
end
|
|
42
55
|
end
|
|
43
56
|
alias_method :dump, :encode
|
|
44
57
|
end
|
|
45
58
|
|
|
46
59
|
module Encoding # :nodoc:
|
|
60
|
+
U2028 = -"\u2028".b
|
|
61
|
+
U2029 = -"\u2029".b
|
|
62
|
+
|
|
63
|
+
ESCAPED_CHARS = {
|
|
64
|
+
U2028 => '\u2028'.b,
|
|
65
|
+
U2029 => '\u2029'.b,
|
|
66
|
+
">".b => '\u003e'.b,
|
|
67
|
+
"<".b => '\u003c'.b,
|
|
68
|
+
"&".b => '\u0026'.b,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
HTML_ENTITIES_REGEX = Regexp.union(*(ESCAPED_CHARS.keys - [U2028, U2029]))
|
|
72
|
+
FULL_ESCAPE_REGEX = Regexp.union(*ESCAPED_CHARS.keys)
|
|
73
|
+
JS_SEPARATORS_REGEX = Regexp.union(U2028, U2029)
|
|
74
|
+
|
|
47
75
|
class JSONGemEncoder # :nodoc:
|
|
48
76
|
attr_reader :options
|
|
49
77
|
|
|
@@ -54,21 +82,23 @@ module ActiveSupport
|
|
|
54
82
|
# Encode the given object into a JSON string
|
|
55
83
|
def encode(value)
|
|
56
84
|
unless options.empty?
|
|
57
|
-
value = value.as_json(options.dup)
|
|
85
|
+
value = value.as_json(options.dup.freeze)
|
|
58
86
|
end
|
|
59
87
|
json = stringify(jsonify(value))
|
|
60
88
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if Encoding.escape_html_entities_in_json
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
89
|
+
return json unless @options.fetch(:escape, true)
|
|
90
|
+
|
|
91
|
+
json.force_encoding(::Encoding::BINARY)
|
|
92
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
|
93
|
+
if Encoding.escape_js_separators_in_json
|
|
94
|
+
json.gsub!(FULL_ESCAPE_REGEX, ESCAPED_CHARS)
|
|
95
|
+
else
|
|
96
|
+
json.gsub!(HTML_ENTITIES_REGEX, ESCAPED_CHARS)
|
|
97
|
+
end
|
|
98
|
+
elsif Encoding.escape_js_separators_in_json
|
|
99
|
+
json.gsub!(JS_SEPARATORS_REGEX, ESCAPED_CHARS)
|
|
68
100
|
end
|
|
69
|
-
json.
|
|
70
|
-
json.gsub!("\u2029", '\u2029')
|
|
71
|
-
json
|
|
101
|
+
json.force_encoding(::Encoding::UTF_8)
|
|
72
102
|
end
|
|
73
103
|
|
|
74
104
|
private
|
|
@@ -101,14 +131,87 @@ module ActiveSupport
|
|
|
101
131
|
when Array
|
|
102
132
|
value.map { |v| jsonify(v) }
|
|
103
133
|
else
|
|
104
|
-
|
|
134
|
+
if defined?(::JSON::Fragment) && ::JSON::Fragment === value
|
|
135
|
+
value
|
|
136
|
+
else
|
|
137
|
+
jsonify value.as_json
|
|
138
|
+
end
|
|
105
139
|
end
|
|
106
140
|
end
|
|
107
141
|
|
|
108
142
|
# Encode a "jsonified" Ruby data structure using the JSON gem
|
|
109
143
|
def stringify(jsonified)
|
|
110
|
-
::JSON.generate(jsonified
|
|
144
|
+
::JSON.generate(jsonified)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# ruby/json 2.14.x yields non-String keys but doesn't let us know it's a key
|
|
149
|
+
if defined?(::JSON::Coder) && Gem::Version.new(::JSON::VERSION) >= Gem::Version.new("2.15.2")
|
|
150
|
+
class JSONGemCoderEncoder # :nodoc:
|
|
151
|
+
JSON_NATIVE_TYPES = [Hash, Array, Float, String, Symbol, Integer, NilClass, TrueClass, FalseClass, ::JSON::Fragment].freeze
|
|
152
|
+
CODER = ::JSON::Coder.new do |value, is_key|
|
|
153
|
+
# Serialize non-String/Symbol keys via #to_s based on the key's own type,
|
|
154
|
+
# mirroring the legacy `jsonify` encoder. (#as_json is intentionally not
|
|
155
|
+
# consulted here: Time#as_json returns an ISO8601 String, yet the key must
|
|
156
|
+
# still be emitted via #to_s for backward compatibility.)
|
|
157
|
+
if is_key
|
|
158
|
+
# Keep compatibility by calling to_s on non-String keys
|
|
159
|
+
if Symbol === value
|
|
160
|
+
next value # Symbol#to_s needlessly allocate a string.
|
|
161
|
+
else
|
|
162
|
+
next value.to_s
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
json_value = value.as_json
|
|
167
|
+
|
|
168
|
+
# Handle objects returning self from as_json
|
|
169
|
+
if json_value.equal?(value)
|
|
170
|
+
next ::JSON::Fragment.new(::JSON.generate(json_value))
|
|
171
|
+
end
|
|
172
|
+
# Handle objects not returning JSON-native types from as_json
|
|
173
|
+
count = 5
|
|
174
|
+
until JSON_NATIVE_TYPES.include?(json_value.class)
|
|
175
|
+
raise SystemStackError if count == 0
|
|
176
|
+
json_value = json_value.as_json
|
|
177
|
+
count -= 1
|
|
178
|
+
end
|
|
179
|
+
json_value
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def initialize(options = nil)
|
|
184
|
+
if options
|
|
185
|
+
options = options.dup
|
|
186
|
+
@escape = options.delete(:escape) { true }
|
|
187
|
+
@options = options.freeze
|
|
188
|
+
else
|
|
189
|
+
@escape = true
|
|
190
|
+
@options = {}.freeze
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Encode the given object into a JSON string
|
|
195
|
+
def encode(value)
|
|
196
|
+
value = value.as_json(@options) unless @options.empty?
|
|
197
|
+
|
|
198
|
+
json = CODER.dump(value)
|
|
199
|
+
|
|
200
|
+
return json unless @escape
|
|
201
|
+
|
|
202
|
+
json.force_encoding(::Encoding::BINARY)
|
|
203
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
|
204
|
+
if Encoding.escape_js_separators_in_json
|
|
205
|
+
json.gsub!(FULL_ESCAPE_REGEX, ESCAPED_CHARS)
|
|
206
|
+
else
|
|
207
|
+
json.gsub!(HTML_ENTITIES_REGEX, ESCAPED_CHARS)
|
|
208
|
+
end
|
|
209
|
+
elsif Encoding.escape_js_separators_in_json
|
|
210
|
+
json.gsub!(JS_SEPARATORS_REGEX, ESCAPED_CHARS)
|
|
211
|
+
end
|
|
212
|
+
json.force_encoding(::Encoding::UTF_8)
|
|
111
213
|
end
|
|
214
|
+
end
|
|
112
215
|
end
|
|
113
216
|
|
|
114
217
|
class << self
|
|
@@ -120,18 +223,45 @@ module ActiveSupport
|
|
|
120
223
|
# as a safety measure.
|
|
121
224
|
attr_accessor :escape_html_entities_in_json
|
|
122
225
|
|
|
226
|
+
# If true, encode LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029)
|
|
227
|
+
# as escaped unicode sequences ('\u2028' and '\u2029').
|
|
228
|
+
# Historically these characters were not valid inside JavaScript strings
|
|
229
|
+
# but that changed in ECMAScript 2019. As such it's no longer a concern in
|
|
230
|
+
# modern browsers: https://caniuse.com/mdn-javascript_builtins_json_json_superset.
|
|
231
|
+
attr_accessor :escape_js_separators_in_json
|
|
232
|
+
|
|
123
233
|
# Sets the precision of encoded time values.
|
|
124
234
|
# Defaults to 3 (equivalent to millisecond precision)
|
|
125
235
|
attr_accessor :time_precision
|
|
126
236
|
|
|
127
237
|
# Sets the encoder used by \Rails to encode Ruby objects into JSON strings
|
|
128
238
|
# in +Object#to_json+ and +ActiveSupport::JSON.encode+.
|
|
129
|
-
|
|
239
|
+
attr_reader :json_encoder
|
|
240
|
+
|
|
241
|
+
def json_encoder=(encoder)
|
|
242
|
+
@json_encoder = encoder
|
|
243
|
+
@encoder_without_options = encoder.new
|
|
244
|
+
@encoder_without_escape = encoder.new(escape: false)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def encode_without_options(value) # :nodoc:
|
|
248
|
+
@encoder_without_options.encode(value)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def encode_without_escape(value) # :nodoc:
|
|
252
|
+
@encoder_without_escape.encode(value)
|
|
253
|
+
end
|
|
130
254
|
end
|
|
131
255
|
|
|
132
256
|
self.use_standard_json_time_format = true
|
|
133
257
|
self.escape_html_entities_in_json = true
|
|
134
|
-
self.
|
|
258
|
+
self.escape_js_separators_in_json = true
|
|
259
|
+
self.json_encoder =
|
|
260
|
+
if defined?(JSONGemCoderEncoder)
|
|
261
|
+
JSONGemCoderEncoder
|
|
262
|
+
else
|
|
263
|
+
JSONGemEncoder
|
|
264
|
+
end
|
|
135
265
|
self.time_precision = 3
|
|
136
266
|
end
|
|
137
267
|
end
|
|
@@ -149,12 +149,6 @@ module ActiveSupport
|
|
|
149
149
|
log_exception(event.name, e)
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
-
def publish_event(event)
|
|
153
|
-
super if logger
|
|
154
|
-
rescue => e
|
|
155
|
-
log_exception(event.name, e)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
152
|
attr_writer :event_levels # :nodoc:
|
|
159
153
|
|
|
160
154
|
private
|
|
@@ -184,6 +178,8 @@ module ActiveSupport
|
|
|
184
178
|
end
|
|
185
179
|
|
|
186
180
|
def log_exception(name, e)
|
|
181
|
+
ActiveSupport.error_reporter.report(e, source: name)
|
|
182
|
+
|
|
187
183
|
if logger
|
|
188
184
|
logger.error "Could not log #{name.inspect} event. #{e.class}: #{e.message} #{e.backtrace}"
|
|
189
185
|
end
|
|
@@ -7,6 +7,11 @@ module ActiveSupport
|
|
|
7
7
|
module LoggerThreadSafeLevel # :nodoc:
|
|
8
8
|
extend ActiveSupport::Concern
|
|
9
9
|
|
|
10
|
+
def initialize(...)
|
|
11
|
+
super
|
|
12
|
+
@local_level_key = :"logger_thread_safe_level_#{object_id}"
|
|
13
|
+
end
|
|
14
|
+
|
|
10
15
|
def local_level
|
|
11
16
|
IsolatedExecutionState[local_level_key]
|
|
12
17
|
end
|
|
@@ -40,8 +45,6 @@ module ActiveSupport
|
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
private
|
|
43
|
-
|
|
44
|
-
@local_level_key ||= :"logger_thread_safe_level_#{object_id}"
|
|
45
|
-
end
|
|
48
|
+
attr_reader :local_level_key
|
|
46
49
|
end
|
|
47
50
|
end
|
|
@@ -26,6 +26,9 @@ module ActiveSupport
|
|
|
26
26
|
# as the first rotation and <tt>transitional = true</tt>. Then, after all
|
|
27
27
|
# servers have been updated, perform a second rolling deploy with
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
|
+
#
|
|
30
|
+
#--
|
|
31
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#transitional
|
|
29
32
|
|
|
30
33
|
##
|
|
31
34
|
# :singleton-method: new
|
|
@@ -43,6 +46,9 @@ module ActiveSupport
|
|
|
43
46
|
# end
|
|
44
47
|
#
|
|
45
48
|
# encryptors.rotate(base: "...")
|
|
49
|
+
#
|
|
50
|
+
#--
|
|
51
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#initialize
|
|
46
52
|
|
|
47
53
|
##
|
|
48
54
|
# :method: []
|
|
@@ -51,12 +57,18 @@ module ActiveSupport
|
|
|
51
57
|
# Returns a MessageEncryptor configured with a secret derived from the
|
|
52
58
|
# given +salt+, and options from #rotate. MessageEncryptor instances will
|
|
53
59
|
# be memoized, so the same +salt+ will return the same instance.
|
|
60
|
+
#
|
|
61
|
+
#--
|
|
62
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#[]
|
|
54
63
|
|
|
55
64
|
##
|
|
56
65
|
# :method: []=
|
|
57
66
|
# :call-seq: []=(salt, encryptor)
|
|
58
67
|
#
|
|
59
68
|
# Overrides a MessageEncryptor instance associated with a given +salt+.
|
|
69
|
+
#
|
|
70
|
+
#--
|
|
71
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#[]=
|
|
60
72
|
|
|
61
73
|
##
|
|
62
74
|
# :method: rotate
|
|
@@ -106,18 +118,55 @@ module ActiveSupport
|
|
|
106
118
|
#
|
|
107
119
|
# # Uses `serializer: Marshal, url_safe: false`.
|
|
108
120
|
# encryptors[:baz]
|
|
121
|
+
#
|
|
122
|
+
#--
|
|
123
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#rotate
|
|
124
|
+
|
|
125
|
+
##
|
|
126
|
+
# :method: prepend
|
|
127
|
+
# :call-seq:
|
|
128
|
+
# prepend(**options)
|
|
129
|
+
# prepend(&block)
|
|
130
|
+
#
|
|
131
|
+
# Just like #rotate, but prepends the given options or block to the list of
|
|
132
|
+
# option sets.
|
|
133
|
+
#
|
|
134
|
+
# This can be useful when you have an already-configured +MessageEncryptors+
|
|
135
|
+
# instance, but you want to override the way messages are encrypted.
|
|
136
|
+
#
|
|
137
|
+
# module ThirdParty
|
|
138
|
+
# ENCRYPTORS = ActiveSupport::MessageEncryptors.new { ... }.
|
|
139
|
+
# rotate(serializer: Marshal, url_safe: true).
|
|
140
|
+
# rotate(serializer: Marshal, url_safe: false)
|
|
141
|
+
# end
|
|
142
|
+
#
|
|
143
|
+
# ThirdParty.ENCRYPTORS.prepend(serializer: JSON, url_safe: true)
|
|
144
|
+
#
|
|
145
|
+
# # Uses `serializer: JSON, url_safe: true`.
|
|
146
|
+
# # Falls back to `serializer: Marshal, url_safe: true` or
|
|
147
|
+
# # `serializer: Marshal, url_safe: false`.
|
|
148
|
+
# ThirdParty.ENCRYPTORS[:foo]
|
|
149
|
+
#
|
|
150
|
+
#--
|
|
151
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#prepend
|
|
109
152
|
|
|
110
153
|
##
|
|
111
154
|
# :method: rotate_defaults
|
|
112
155
|
# :call-seq: rotate_defaults
|
|
113
156
|
#
|
|
114
157
|
# Invokes #rotate with the default options.
|
|
158
|
+
#
|
|
159
|
+
#--
|
|
160
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#rotate_defaults
|
|
115
161
|
|
|
116
162
|
##
|
|
117
163
|
# :method: clear_rotations
|
|
118
164
|
# :call-seq: clear_rotations
|
|
119
165
|
#
|
|
120
166
|
# Clears the list of option sets.
|
|
167
|
+
#
|
|
168
|
+
#--
|
|
169
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#clear_rotations
|
|
121
170
|
|
|
122
171
|
##
|
|
123
172
|
# :method: on_rotation
|
|
@@ -129,6 +178,9 @@ module ActiveSupport
|
|
|
129
178
|
# For example, this callback could log each time it is called, and thus
|
|
130
179
|
# indicate whether old option sets are still in use or can be removed from
|
|
131
180
|
# rotation.
|
|
181
|
+
#
|
|
182
|
+
#--
|
|
183
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#on_rotation
|
|
132
184
|
|
|
133
185
|
##
|
|
134
186
|
private
|
|
@@ -4,9 +4,10 @@ require "bigdecimal"
|
|
|
4
4
|
require "date"
|
|
5
5
|
require "ipaddr"
|
|
6
6
|
require "pathname"
|
|
7
|
-
require "uri
|
|
7
|
+
require "uri"
|
|
8
8
|
require "msgpack/bigint"
|
|
9
9
|
require "active_support/hash_with_indifferent_access"
|
|
10
|
+
require "active_support/core_ext/string/output_safety"
|
|
10
11
|
require "active_support/time"
|
|
11
12
|
|
|
12
13
|
module ActiveSupport
|
|
@@ -102,6 +103,11 @@ module ActiveSupport
|
|
|
102
103
|
packer: method(:write_hash_with_indifferent_access),
|
|
103
104
|
unpacker: method(:read_hash_with_indifferent_access),
|
|
104
105
|
recursive: true
|
|
106
|
+
|
|
107
|
+
registry.register_type 18, ActiveSupport::SafeBuffer,
|
|
108
|
+
packer: method(:write_safe_buffer),
|
|
109
|
+
unpacker: method(:read_safe_buffer),
|
|
110
|
+
recursive: true
|
|
105
111
|
end
|
|
106
112
|
|
|
107
113
|
def install_unregistered_type_error(registry)
|
|
@@ -242,6 +248,22 @@ module ActiveSupport
|
|
|
242
248
|
ActiveSupport::HashWithIndifferentAccess.new(unpacker.read)
|
|
243
249
|
end
|
|
244
250
|
|
|
251
|
+
def write_safe_buffer(buffer, packer)
|
|
252
|
+
unless buffer.html_safe?
|
|
253
|
+
packer.write(false)
|
|
254
|
+
end
|
|
255
|
+
packer.write(buffer.to_str)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def read_safe_buffer(unpacker)
|
|
259
|
+
string_or_safe = unpacker.read
|
|
260
|
+
if string_or_safe
|
|
261
|
+
ActiveSupport::SafeBuffer.new(string_or_safe)
|
|
262
|
+
else
|
|
263
|
+
unpacker.read
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
245
267
|
def raise_unserializable(object, *)
|
|
246
268
|
raise UnserializableObjectError, "Unsupported type #{object.class} for object #{object.inspect}"
|
|
247
269
|
end
|
|
@@ -26,6 +26,9 @@ module ActiveSupport
|
|
|
26
26
|
# as the first rotation and <tt>transitional = true</tt>. Then, after all
|
|
27
27
|
# servers have been updated, perform a second rolling deploy with
|
|
28
28
|
# <tt>transitional = false</tt>.
|
|
29
|
+
#
|
|
30
|
+
#--
|
|
31
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#transitional
|
|
29
32
|
|
|
30
33
|
##
|
|
31
34
|
# :singleton-method: new
|
|
@@ -42,6 +45,9 @@ module ActiveSupport
|
|
|
42
45
|
# end
|
|
43
46
|
#
|
|
44
47
|
# verifiers.rotate(base: "...")
|
|
48
|
+
#
|
|
49
|
+
#--
|
|
50
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#initialize
|
|
45
51
|
|
|
46
52
|
##
|
|
47
53
|
# :method: []
|
|
@@ -50,12 +56,18 @@ module ActiveSupport
|
|
|
50
56
|
# Returns a MessageVerifier configured with a secret derived from the
|
|
51
57
|
# given +salt+, and options from #rotate. MessageVerifier instances will
|
|
52
58
|
# be memoized, so the same +salt+ will return the same instance.
|
|
59
|
+
#
|
|
60
|
+
#--
|
|
61
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#[]
|
|
53
62
|
|
|
54
63
|
##
|
|
55
64
|
# :method: []=
|
|
56
65
|
# :call-seq: []=(salt, verifier)
|
|
57
66
|
#
|
|
58
67
|
# Overrides a MessageVerifier instance associated with a given +salt+.
|
|
68
|
+
#
|
|
69
|
+
#--
|
|
70
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#[]=
|
|
59
71
|
|
|
60
72
|
##
|
|
61
73
|
# :method: rotate
|
|
@@ -104,18 +116,55 @@ module ActiveSupport
|
|
|
104
116
|
#
|
|
105
117
|
# # Uses `serializer: Marshal, url_safe: false`.
|
|
106
118
|
# verifiers[:baz]
|
|
119
|
+
#
|
|
120
|
+
#--
|
|
121
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#rotate
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# :method: prepend
|
|
125
|
+
# :call-seq:
|
|
126
|
+
# prepend(**options)
|
|
127
|
+
# prepend(&block)
|
|
128
|
+
#
|
|
129
|
+
# Just like #rotate, but prepends the given options or block to the list of
|
|
130
|
+
# option sets.
|
|
131
|
+
#
|
|
132
|
+
# This can be useful when you have an already-configured +MessageVerifiers+
|
|
133
|
+
# instance, but you want to override the way messages are signed.
|
|
134
|
+
#
|
|
135
|
+
# module ThirdParty
|
|
136
|
+
# VERIFIERS = ActiveSupport::MessageVerifiers.new { ... }.
|
|
137
|
+
# rotate(serializer: Marshal, url_safe: true).
|
|
138
|
+
# rotate(serializer: Marshal, url_safe: false)
|
|
139
|
+
# end
|
|
140
|
+
#
|
|
141
|
+
# ThirdParty.VERIFIERS.prepend(serializer: JSON, url_safe: true)
|
|
142
|
+
#
|
|
143
|
+
# # Uses `serializer: JSON, url_safe: true`.
|
|
144
|
+
# # Falls back to `serializer: Marshal, url_safe: true` or
|
|
145
|
+
# # `serializer: Marshal, url_safe: false`.
|
|
146
|
+
# ThirdParty.VERIFIERS[:foo]
|
|
147
|
+
#
|
|
148
|
+
#--
|
|
149
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#prepend
|
|
107
150
|
|
|
108
151
|
##
|
|
109
152
|
# :method: rotate_defaults
|
|
110
153
|
# :call-seq: rotate_defaults
|
|
111
154
|
#
|
|
112
155
|
# Invokes #rotate with the default options.
|
|
156
|
+
#
|
|
157
|
+
#--
|
|
158
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#rotate_defaults
|
|
113
159
|
|
|
114
160
|
##
|
|
115
161
|
# :method: clear_rotations
|
|
116
162
|
# :call-seq: clear_rotations
|
|
117
163
|
#
|
|
118
164
|
# Clears the list of option sets.
|
|
165
|
+
#
|
|
166
|
+
#--
|
|
167
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#clear_rotations
|
|
119
168
|
|
|
120
169
|
##
|
|
121
170
|
# :method: on_rotation
|
|
@@ -127,6 +176,9 @@ module ActiveSupport
|
|
|
127
176
|
# For example, this callback could log each time it is called, and thus
|
|
128
177
|
# indicate whether old option sets are still in use or can be removed from
|
|
129
178
|
# rotation.
|
|
179
|
+
#
|
|
180
|
+
#--
|
|
181
|
+
# Implemented by ActiveSupport::Messages::RotationCoordinator#on_rotation
|
|
130
182
|
|
|
131
183
|
##
|
|
132
184
|
private
|
|
@@ -32,6 +32,15 @@ module ActiveSupport
|
|
|
32
32
|
self
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def prepend(**options, &block)
|
|
36
|
+
raise ArgumentError, "Options cannot be specified when using a block" if block && !options.empty?
|
|
37
|
+
changing_configuration!
|
|
38
|
+
|
|
39
|
+
@rotate_options.unshift(block || options)
|
|
40
|
+
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
35
44
|
def rotate_defaults
|
|
36
45
|
rotate()
|
|
37
46
|
end
|
|
@@ -53,7 +53,14 @@ module ActiveSupport # :nodoc:
|
|
|
53
53
|
delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
|
|
54
54
|
|
|
55
55
|
# Creates a new Chars instance by wrapping _string_.
|
|
56
|
-
def initialize(string)
|
|
56
|
+
def initialize(string, deprecation: true)
|
|
57
|
+
if deprecation
|
|
58
|
+
ActiveSupport.deprecator.warn(
|
|
59
|
+
"ActiveSupport::Multibyte::Chars is deprecated and will be removed in Rails 8.2. " \
|
|
60
|
+
"Use normal string methods instead."
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
57
64
|
@wrapped_string = string
|
|
58
65
|
if string.encoding != Encoding::UTF_8
|
|
59
66
|
@wrapped_string = @wrapped_string.dup
|
|
@@ -12,6 +12,10 @@ module ActiveSupport # :nodoc:
|
|
|
12
12
|
#
|
|
13
13
|
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
|
|
14
14
|
def self.proxy_class=(klass)
|
|
15
|
+
ActiveSupport.deprecator.warn(
|
|
16
|
+
"ActiveSupport::Multibyte.proxy_class= is deprecated and will be removed in Rails 8.2. " \
|
|
17
|
+
"Use normal string methods instead."
|
|
18
|
+
)
|
|
15
19
|
@proxy_class = klass
|
|
16
20
|
end
|
|
17
21
|
|