activesupport 7.2.2.2 → 8.0.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 +182 -162
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +61 -74
- data/lib/active_support/cache/file_store.rb +14 -4
- data/lib/active_support/cache/mem_cache_store.rb +13 -15
- data/lib/active_support/cache/memory_store.rb +9 -5
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +6 -3
- data/lib/active_support/cache/strategy/local_cache.rb +56 -20
- data/lib/active_support/cache.rb +19 -14
- data/lib/active_support/callbacks.rb +8 -5
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/core_ext/array/conversions.rb +3 -3
- data/lib/active_support/core_ext/benchmark.rb +7 -9
- data/lib/active_support/core_ext/class/attribute.rb +24 -20
- data/lib/active_support/core_ext/date/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +2 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +2 -2
- 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/module/attr_internal.rb +3 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/object/json.rb +15 -9
- data/lib/active_support/core_ext/object/to_query.rb +2 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- 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/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +14 -2
- data/lib/active_support/core_ext/time/compatibility.rb +9 -1
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/current_attributes.rb +14 -7
- data/lib/active_support/delegation.rb +0 -2
- data/lib/active_support/dependencies.rb +0 -1
- data/lib/active_support/deprecation/reporting.rb +0 -19
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/duration.rb +14 -10
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/error_reporter.rb +36 -3
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- 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 +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +34 -31
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/isolated_execution_state.rb +0 -2
- data/lib/active_support/json/decoding.rb +4 -2
- data/lib/active_support/json/encoding.rb +25 -7
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- 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/notifications/fanout.rb +0 -1
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/railtie.rb +6 -0
- data/lib/active_support/tagged_logging.rb +5 -0
- data/lib/active_support/testing/assertions.rb +79 -21
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/time_helpers.rb +2 -1
- data/lib/active_support/time_with_zone.rb +22 -13
- data/lib/active_support/values/time_zone.rb +11 -9
- data/lib/active_support.rb +10 -3
- metadata +22 -7
- data/lib/active_support/proxy_object.rb +0 -20
- data/lib/active_support/testing/strict_warnings.rb +0 -43
|
@@ -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
|
|
@@ -139,7 +139,6 @@ module ActiveSupport
|
|
|
139
139
|
|
|
140
140
|
def extract_callstack(callstack)
|
|
141
141
|
return [] if callstack.empty?
|
|
142
|
-
return _extract_callstack(callstack) if callstack.first.is_a? String
|
|
143
142
|
|
|
144
143
|
offending_line = callstack.find { |frame|
|
|
145
144
|
# Code generated with `eval` doesn't have an `absolute_path`, e.g. templates.
|
|
@@ -150,24 +149,6 @@ module ActiveSupport
|
|
|
150
149
|
[offending_line.path, offending_line.lineno, offending_line.label]
|
|
151
150
|
end
|
|
152
151
|
|
|
153
|
-
def _extract_callstack(callstack)
|
|
154
|
-
ActiveSupport.deprecator.warn(<<~MESSAGE)
|
|
155
|
-
Passing the result of `caller` to ActiveSupport::Deprecation#warn is deprecated and will be removed in Rails 8.0.
|
|
156
|
-
|
|
157
|
-
Please pass the result of `caller_locations` instead.
|
|
158
|
-
MESSAGE
|
|
159
|
-
|
|
160
|
-
offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first
|
|
161
|
-
|
|
162
|
-
if offending_line
|
|
163
|
-
if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
|
|
164
|
-
md.captures
|
|
165
|
-
else
|
|
166
|
-
offending_line
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
|
|
171
152
|
RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/" # :nodoc:
|
|
172
153
|
LIB_DIR = RbConfig::CONFIG["libdir"] # :nodoc:
|
|
173
154
|
|
|
@@ -68,7 +68,7 @@ module ActiveSupport
|
|
|
68
68
|
# and the second is a library name.
|
|
69
69
|
#
|
|
70
70
|
# ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
|
|
71
|
-
def initialize(deprecation_horizon = "8.
|
|
71
|
+
def initialize(deprecation_horizon = "8.1", gem_name = "Rails")
|
|
72
72
|
self.gem_name = gem_name
|
|
73
73
|
self.deprecation_horizon = deprecation_horizon
|
|
74
74
|
# By default, warnings are not silenced and debugging is off.
|
|
@@ -491,17 +491,21 @@ module ActiveSupport
|
|
|
491
491
|
if @parts.empty?
|
|
492
492
|
time.since(sign * value)
|
|
493
493
|
else
|
|
494
|
-
@parts.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
494
|
+
@parts.each do |type, number|
|
|
495
|
+
t = time
|
|
496
|
+
time =
|
|
497
|
+
if type == :seconds
|
|
498
|
+
t.since(sign * number)
|
|
499
|
+
elsif type == :minutes
|
|
500
|
+
t.since(sign * number * 60)
|
|
501
|
+
elsif type == :hours
|
|
502
|
+
t.since(sign * number * 3600)
|
|
503
|
+
else
|
|
504
|
+
t.advance(type => sign * number)
|
|
505
|
+
end
|
|
504
506
|
end
|
|
507
|
+
|
|
508
|
+
time
|
|
505
509
|
end
|
|
506
510
|
end
|
|
507
511
|
|
|
@@ -43,6 +43,12 @@ module ActiveSupport
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
class InvalidKeyError < RuntimeError
|
|
47
|
+
def initialize(content_path, key)
|
|
48
|
+
super "Key '#{key}' is invalid, it must respond to '#to_sym' from configuration in '#{content_path}'."
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
46
52
|
delegate_missing_to :options
|
|
47
53
|
|
|
48
54
|
def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:)
|
|
@@ -61,7 +67,11 @@ module ActiveSupport
|
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
def validate! # :nodoc:
|
|
64
|
-
deserialize(read)
|
|
70
|
+
deserialize(read).each_key do |key|
|
|
71
|
+
key.to_sym
|
|
72
|
+
rescue NoMethodError
|
|
73
|
+
raise InvalidKeyError.new(content_path, key)
|
|
74
|
+
end
|
|
65
75
|
end
|
|
66
76
|
|
|
67
77
|
# Returns the decrypted content as a Hash with symbolized keys.
|
|
@@ -73,7 +83,7 @@ module ActiveSupport
|
|
|
73
83
|
# # => { some_secret: 123, some_namespace: { another_secret: 789 } }
|
|
74
84
|
#
|
|
75
85
|
def config
|
|
76
|
-
@config ||= deserialize(read)
|
|
86
|
+
@config ||= deep_symbolize_keys(deserialize(read))
|
|
77
87
|
end
|
|
78
88
|
|
|
79
89
|
def inspect # :nodoc:
|
|
@@ -81,6 +91,14 @@ module ActiveSupport
|
|
|
81
91
|
end
|
|
82
92
|
|
|
83
93
|
private
|
|
94
|
+
def deep_symbolize_keys(hash)
|
|
95
|
+
hash.deep_transform_keys do |key|
|
|
96
|
+
key.to_sym
|
|
97
|
+
rescue NoMethodError
|
|
98
|
+
raise InvalidKeyError.new(content_path, key)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
84
102
|
def deep_transform(hash)
|
|
85
103
|
return hash unless hash.is_a?(Hash)
|
|
86
104
|
|
|
@@ -144,9 +144,9 @@ module ActiveSupport
|
|
|
144
144
|
#
|
|
145
145
|
def unexpected(error, severity: :warning, context: {}, source: DEFAULT_SOURCE)
|
|
146
146
|
error = RuntimeError.new(error) if error.is_a?(String)
|
|
147
|
-
error.set_backtrace(caller(1)) if error.backtrace.nil?
|
|
148
147
|
|
|
149
148
|
if @debug_mode
|
|
149
|
+
ensure_backtrace(error)
|
|
150
150
|
raise UnexpectedError, "#{error.class.name}: #{error.message}", error.backtrace, cause: error
|
|
151
151
|
else
|
|
152
152
|
report(error, handled: true, severity: severity, context: context, source: source)
|
|
@@ -207,8 +207,15 @@ module ActiveSupport
|
|
|
207
207
|
#
|
|
208
208
|
# Rails.error.report(error)
|
|
209
209
|
#
|
|
210
|
+
# The +error+ argument must be an instance of Exception.
|
|
211
|
+
#
|
|
212
|
+
# Rails.error.report(Exception.new("Something went wrong"))
|
|
213
|
+
#
|
|
214
|
+
# Otherwise you can use #unexpected to report an error which does accept a
|
|
215
|
+
# string argument.
|
|
210
216
|
def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
|
|
211
217
|
return if error.instance_variable_defined?(:@__rails_error_reported)
|
|
218
|
+
ensure_backtrace(error)
|
|
212
219
|
|
|
213
220
|
unless SEVERITIES.include?(severity)
|
|
214
221
|
raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
|
|
@@ -231,11 +238,37 @@ module ActiveSupport
|
|
|
231
238
|
end
|
|
232
239
|
end
|
|
233
240
|
|
|
234
|
-
|
|
235
|
-
error.
|
|
241
|
+
while error
|
|
242
|
+
unless error.frozen?
|
|
243
|
+
error.instance_variable_set(:@__rails_error_reported, true)
|
|
244
|
+
end
|
|
245
|
+
error = error.cause
|
|
236
246
|
end
|
|
237
247
|
|
|
238
248
|
nil
|
|
239
249
|
end
|
|
250
|
+
|
|
251
|
+
private
|
|
252
|
+
def ensure_backtrace(error)
|
|
253
|
+
return if error.frozen? # re-raising won't add a backtrace
|
|
254
|
+
return unless error.backtrace.nil?
|
|
255
|
+
|
|
256
|
+
begin
|
|
257
|
+
# We could use Exception#set_backtrace, but until Ruby 3.4
|
|
258
|
+
# it only support setting `Exception#backtrace` and not
|
|
259
|
+
# `Exception#backtrace_locations`. So raising the exception
|
|
260
|
+
# is a good way to build a real backtrace.
|
|
261
|
+
raise error
|
|
262
|
+
rescue error.class => error
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
count = 0
|
|
266
|
+
while error.backtrace_locations.first&.path == __FILE__
|
|
267
|
+
count += 1
|
|
268
|
+
error.backtrace_locations.shift
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
error.backtrace.shift(count)
|
|
272
|
+
end
|
|
240
273
|
end
|
|
241
274
|
end
|
|
@@ -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
|
|
@@ -313,10 +311,6 @@ module ActiveSupport
|
|
|
313
311
|
end
|
|
314
312
|
alias_method :without, :except
|
|
315
313
|
|
|
316
|
-
def stringify_keys!; self end
|
|
317
|
-
def deep_stringify_keys!; self end
|
|
318
|
-
def stringify_keys; dup end
|
|
319
|
-
def deep_stringify_keys; dup end
|
|
320
314
|
undef :symbolize_keys!
|
|
321
315
|
undef :deep_symbolize_keys!
|
|
322
316
|
def symbolize_keys; to_hash.symbolize_keys! end
|
|
@@ -342,21 +336,26 @@ module ActiveSupport
|
|
|
342
336
|
NOT_GIVEN = Object.new # :nodoc:
|
|
343
337
|
|
|
344
338
|
def transform_keys(hash = NOT_GIVEN, &block)
|
|
345
|
-
|
|
346
|
-
|
|
339
|
+
if NOT_GIVEN.equal?(hash)
|
|
340
|
+
if block_given?
|
|
341
|
+
self.class.new(super(&block))
|
|
342
|
+
else
|
|
343
|
+
to_enum(:transform_keys)
|
|
344
|
+
end
|
|
345
|
+
else
|
|
346
|
+
self.class.new(super)
|
|
347
|
+
end
|
|
347
348
|
end
|
|
348
349
|
|
|
349
350
|
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) }
|
|
351
|
+
if NOT_GIVEN.equal?(hash)
|
|
352
|
+
if block_given?
|
|
353
|
+
replace(copy_defaults(transform_keys(&block)))
|
|
354
|
+
else
|
|
355
|
+
return to_enum(:transform_keys!)
|
|
356
|
+
end
|
|
358
357
|
else
|
|
359
|
-
|
|
358
|
+
replace(copy_defaults(transform_keys(hash, &block)))
|
|
360
359
|
end
|
|
361
360
|
|
|
362
361
|
self
|
|
@@ -378,13 +377,9 @@ module ActiveSupport
|
|
|
378
377
|
|
|
379
378
|
# Convert to a regular hash with string keys.
|
|
380
379
|
def to_hash
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
each do |key, value|
|
|
385
|
-
_new_hash[key] = convert_value(value, conversion: :to_hash)
|
|
386
|
-
end
|
|
387
|
-
_new_hash
|
|
380
|
+
copy = Hash[self]
|
|
381
|
+
copy.transform_values! { |v| convert_value_to_hash(v) }
|
|
382
|
+
copy_defaults(copy)
|
|
388
383
|
end
|
|
389
384
|
|
|
390
385
|
def to_proc
|
|
@@ -398,11 +393,7 @@ module ActiveSupport
|
|
|
398
393
|
|
|
399
394
|
def convert_value(value, conversion: nil)
|
|
400
395
|
if value.is_a? Hash
|
|
401
|
-
|
|
402
|
-
value.to_hash
|
|
403
|
-
else
|
|
404
|
-
value.nested_under_indifferent_access
|
|
405
|
-
end
|
|
396
|
+
value.nested_under_indifferent_access
|
|
406
397
|
elsif value.is_a?(Array)
|
|
407
398
|
if conversion != :assignment || value.frozen?
|
|
408
399
|
value = value.dup
|
|
@@ -413,12 +404,24 @@ module ActiveSupport
|
|
|
413
404
|
end
|
|
414
405
|
end
|
|
415
406
|
|
|
416
|
-
def
|
|
407
|
+
def convert_value_to_hash(value)
|
|
408
|
+
if value.is_a? Hash
|
|
409
|
+
value.to_hash
|
|
410
|
+
elsif value.is_a?(Array)
|
|
411
|
+
value.map { |e| convert_value_to_hash(e) }
|
|
412
|
+
else
|
|
413
|
+
value
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def copy_defaults(target)
|
|
417
419
|
if default_proc
|
|
418
420
|
target.default_proc = default_proc.dup
|
|
419
421
|
else
|
|
420
422
|
target.default = default
|
|
421
423
|
end
|
|
424
|
+
target
|
|
422
425
|
end
|
|
423
426
|
|
|
424
427
|
def update_with_single_argument(other_hash, block)
|
|
@@ -14,15 +14,18 @@ module I18n
|
|
|
14
14
|
|
|
15
15
|
config.eager_load_namespaces << I18n
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
config.
|
|
17
|
+
# Make sure i18n is ready before eager loading, in case any eager loaded
|
|
18
|
+
# code needs it.
|
|
19
|
+
config.before_eager_load do |app|
|
|
20
20
|
I18n::Railtie.initialize_i18n(app)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
23
|
+
# i18n initialization needs to run after application initialization, since
|
|
24
|
+
# initializers may configure i18n.
|
|
25
|
+
#
|
|
26
|
+
# If the application eager loaded, this was done on before_eager_load. The
|
|
27
|
+
# hook is still OK, though, because initialize_i18n is idempotent.
|
|
28
|
+
config.after_initialize do |app|
|
|
26
29
|
I18n::Railtie.initialize_i18n(app)
|
|
27
30
|
end
|
|
28
31
|
|
|
@@ -49,7 +52,8 @@ module I18n
|
|
|
49
52
|
when :load_path
|
|
50
53
|
I18n.load_path += value
|
|
51
54
|
when :raise_on_missing_translations
|
|
52
|
-
|
|
55
|
+
strict = value == :strict
|
|
56
|
+
setup_raise_on_missing_translations_config(app, strict)
|
|
53
57
|
else
|
|
54
58
|
I18n.public_send("#{setting}=", value)
|
|
55
59
|
end
|
|
@@ -62,8 +66,9 @@ module I18n
|
|
|
62
66
|
|
|
63
67
|
if app.config.reloading_enabled?
|
|
64
68
|
directories = watched_dirs_with_extensions(reloadable_paths)
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
root_load_paths = I18n.load_path.select { |path| path.to_s.start_with?(Rails.root.to_s) }
|
|
70
|
+
reloader = app.config.file_watcher.new(root_load_paths, directories) do
|
|
71
|
+
I18n.load_path.delete_if { |path| path.to_s.start_with?(Rails.root.to_s) && !File.exist?(path) }
|
|
67
72
|
I18n.load_path |= reloadable_paths.flat_map(&:existent)
|
|
68
73
|
end
|
|
69
74
|
|
|
@@ -71,17 +76,20 @@ module I18n
|
|
|
71
76
|
app.reloader.to_run do
|
|
72
77
|
reloader.execute_if_updated { require_unload_lock! }
|
|
73
78
|
end
|
|
74
|
-
reloader.execute
|
|
75
79
|
end
|
|
76
80
|
|
|
77
81
|
@i18n_inited = true
|
|
78
82
|
end
|
|
79
83
|
|
|
80
|
-
def self.setup_raise_on_missing_translations_config(app)
|
|
84
|
+
def self.setup_raise_on_missing_translations_config(app, strict)
|
|
81
85
|
ActiveSupport.on_load(:action_view) do
|
|
82
86
|
ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
|
|
83
87
|
end
|
|
84
88
|
|
|
89
|
+
ActiveSupport.on_load(:active_model_translation) do
|
|
90
|
+
ActiveModel::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations if strict
|
|
91
|
+
end
|
|
92
|
+
|
|
85
93
|
if app.config.i18n.raise_on_missing_translations &&
|
|
86
94
|
I18n.exception_handler.is_a?(I18n::ExceptionHandler) # Only override the i18n gem's default exception handler.
|
|
87
95
|
|
|
@@ -14,11 +14,13 @@ 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
|
-
# => {"team" => "rails", "players" => "36"}
|
|
21
|
+
# # => {"team" => "rails", "players" => "36"}
|
|
22
|
+
# ActiveSupport::JSON.decode("2.39")
|
|
23
|
+
# # => 2.39
|
|
22
24
|
def decode(json)
|
|
23
25
|
data = ::JSON.parse(json, quirks_mode: true)
|
|
24
26
|
|
|
@@ -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
|
|
@@ -36,14 +54,14 @@ module ActiveSupport
|
|
|
36
54
|
# Encode the given object into a JSON string
|
|
37
55
|
def encode(value)
|
|
38
56
|
unless options.empty?
|
|
39
|
-
value = value.as_json(options.dup)
|
|
57
|
+
value = value.as_json(options.dup.freeze)
|
|
40
58
|
end
|
|
41
59
|
json = stringify(jsonify(value))
|
|
42
60
|
|
|
43
61
|
# Rails does more escaping than the JSON gem natively does (we
|
|
44
62
|
# escape \u2028 and \u2029 and optionally >, <, & to work around
|
|
45
63
|
# certain browser problems).
|
|
46
|
-
if Encoding.escape_html_entities_in_json
|
|
64
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
|
47
65
|
json.gsub!(">", '\u003e')
|
|
48
66
|
json.gsub!("<", '\u003c')
|
|
49
67
|
json.gsub!("&", '\u0026')
|
|
@@ -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.
|
|
@@ -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
|
|
@@ -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
|