activesupport 7.2.3 → 8.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +191 -213
- data/lib/active_support/backtrace_cleaner.rb +1 -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 +12 -2
- data/lib/active_support/cache/mem_cache_store.rb +4 -1
- data/lib/active_support/cache/memory_store.rb +6 -2
- data/lib/active_support/cache/redis_cache_store.rb +6 -3
- data/lib/active_support/cache.rb +16 -11
- data/lib/active_support/callbacks.rb +5 -3
- 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 +6 -9
- data/lib/active_support/core_ext/class/attribute.rb +24 -18
- 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/enumerable.rb +8 -3
- 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/object/json.rb +16 -10
- data/lib/active_support/core_ext/object/to_query.rb +2 -1
- data/lib/active_support/core_ext/range/overlap.rb +3 -3
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +3 -1
- 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/conversions.rb +2 -0
- data/lib/active_support/delegation.rb +25 -44
- 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 +31 -1
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +15 -16
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +2 -1
- data/lib/active_support/inflector/methods.rb +3 -3
- data/lib/active_support/isolated_execution_state.rb +4 -4
- data/lib/active_support/json/decoding.rb +3 -1
- data/lib/active_support/json/encoding.rb +2 -2
- data/lib/active_support/logger_thread_safe_level.rb +6 -3
- data/lib/active_support/message_pack/extensions.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +0 -1
- data/lib/active_support/notifications/instrumenter.rb +1 -1
- data/lib/active_support/number_helper/number_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
- 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/test_case.rb +6 -0
- data/lib/active_support/testing/assertions.rb +84 -21
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/isolation.rb +0 -2
- data/lib/active_support/testing/parallelization/worker.rb +5 -1
- 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
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
|
-
|
|
5
3
|
module ActiveSupport
|
|
6
4
|
# Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
|
|
7
5
|
# option is not used.
|
|
@@ -136,11 +134,11 @@ module ActiveSupport
|
|
|
136
134
|
"def #{method_name}(#{definition})" <<
|
|
137
135
|
" _ = #{receiver}" <<
|
|
138
136
|
" _.#{method}(#{definition})" <<
|
|
139
|
-
"rescue NoMethodError => e" <<
|
|
137
|
+
"rescue ::NoMethodError => e" <<
|
|
140
138
|
" if _.nil? && e.name == :#{method}" <<
|
|
141
|
-
" raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
|
|
139
|
+
" ::Kernel.raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
|
|
142
140
|
" else" <<
|
|
143
|
-
" raise" <<
|
|
141
|
+
" ::Kernel.raise" <<
|
|
144
142
|
" end" <<
|
|
145
143
|
"end"
|
|
146
144
|
end
|
|
@@ -153,49 +151,32 @@ module ActiveSupport
|
|
|
153
151
|
target = target.to_s
|
|
154
152
|
target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target) || target == "__target"
|
|
155
153
|
|
|
156
|
-
if allow_nil
|
|
157
|
-
|
|
158
|
-
def respond_to_missing?(name, include_private = false)
|
|
159
|
-
# It may look like an oversight, but we deliberately do not pass
|
|
160
|
-
# +include_private+, because they do not get delegated.
|
|
161
|
-
|
|
162
|
-
return false if name == :marshal_dump || name == :_dump
|
|
163
|
-
#{target}.respond_to?(name) || super
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def method_missing(method, ...)
|
|
167
|
-
__target = #{target}
|
|
168
|
-
if __target.nil? && !nil.respond_to?(method)
|
|
169
|
-
nil
|
|
170
|
-
elsif __target.respond_to?(method)
|
|
171
|
-
__target.public_send(method, ...)
|
|
172
|
-
else
|
|
173
|
-
super
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
RUBY
|
|
154
|
+
nil_behavior = if allow_nil
|
|
155
|
+
"nil"
|
|
177
156
|
else
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
# It may look like an oversight, but we deliberately do not pass
|
|
181
|
-
# +include_private+, because they do not get delegated.
|
|
157
|
+
"::Kernel.raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')"
|
|
158
|
+
end
|
|
182
159
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
160
|
+
owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
161
|
+
def respond_to_missing?(name, include_private = false)
|
|
162
|
+
# It may look like an oversight, but we deliberately do not pass
|
|
163
|
+
# +include_private+, because they do not get delegated.
|
|
186
164
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
165
|
+
return false if name == :marshal_dump || name == :_dump
|
|
166
|
+
#{target}.respond_to?(name) || super
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def method_missing(method, ...)
|
|
170
|
+
__target = #{target}
|
|
171
|
+
if __target.nil? && !nil.respond_to?(method)
|
|
172
|
+
#{nil_behavior}
|
|
173
|
+
elsif __target.respond_to?(method)
|
|
174
|
+
__target.public_send(method, ...)
|
|
175
|
+
else
|
|
176
|
+
super
|
|
196
177
|
end
|
|
197
|
-
|
|
198
|
-
|
|
178
|
+
end
|
|
179
|
+
RUBY
|
|
199
180
|
end
|
|
200
181
|
end
|
|
201
182
|
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}"
|
|
@@ -240,5 +247,28 @@ module ActiveSupport
|
|
|
240
247
|
|
|
241
248
|
nil
|
|
242
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
|
|
243
273
|
end
|
|
244
274
|
end
|
|
@@ -311,10 +311,6 @@ module ActiveSupport
|
|
|
311
311
|
end
|
|
312
312
|
alias_method :without, :except
|
|
313
313
|
|
|
314
|
-
def stringify_keys!; self end
|
|
315
|
-
def deep_stringify_keys!; self end
|
|
316
|
-
def stringify_keys; dup end
|
|
317
|
-
def deep_stringify_keys; dup end
|
|
318
314
|
undef :symbolize_keys!
|
|
319
315
|
undef :deep_symbolize_keys!
|
|
320
316
|
def symbolize_keys; to_hash.symbolize_keys! end
|
|
@@ -381,13 +377,9 @@ module ActiveSupport
|
|
|
381
377
|
|
|
382
378
|
# Convert to a regular hash with string keys.
|
|
383
379
|
def to_hash
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
each do |key, value|
|
|
388
|
-
_new_hash[key] = convert_value(value, conversion: :to_hash)
|
|
389
|
-
end
|
|
390
|
-
_new_hash
|
|
380
|
+
copy = Hash[self]
|
|
381
|
+
copy.transform_values! { |v| convert_value_to_hash(v) }
|
|
382
|
+
copy_defaults(copy)
|
|
391
383
|
end
|
|
392
384
|
|
|
393
385
|
def to_proc
|
|
@@ -401,11 +393,7 @@ module ActiveSupport
|
|
|
401
393
|
|
|
402
394
|
def convert_value(value, conversion: nil)
|
|
403
395
|
if value.is_a? Hash
|
|
404
|
-
|
|
405
|
-
value.to_hash
|
|
406
|
-
else
|
|
407
|
-
value.nested_under_indifferent_access
|
|
408
|
-
end
|
|
396
|
+
value.nested_under_indifferent_access
|
|
409
397
|
elsif value.is_a?(Array)
|
|
410
398
|
if conversion != :assignment || value.frozen?
|
|
411
399
|
value = value.dup
|
|
@@ -416,6 +404,17 @@ module ActiveSupport
|
|
|
416
404
|
end
|
|
417
405
|
end
|
|
418
406
|
|
|
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
|
+
|
|
419
418
|
def copy_defaults(target)
|
|
420
419
|
if default_proc
|
|
421
420
|
target.default_proc = default_proc.dup
|
|
@@ -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
|
|
|
@@ -248,7 +248,8 @@ module ActiveSupport
|
|
|
248
248
|
|
|
249
249
|
private
|
|
250
250
|
def define_acronym_regex_patterns
|
|
251
|
-
|
|
251
|
+
sorted_acronyms = @acronyms.empty? ? [] : @acronyms.values.sort_by { |a| -a.length }
|
|
252
|
+
@acronym_regex = sorted_acronyms.empty? ? /(?=a)b/ : /#{sorted_acronyms.join("|")}/
|
|
252
253
|
@acronyms_camelize_regex = /^(?:#{@acronym_regex}(?=\b|[A-Z_])|\w)/
|
|
253
254
|
@acronyms_underscore_regex = /(?:(?<=([A-Za-z\d]))|\b)(#{@acronym_regex})(?=\b|[^a-z])/
|
|
254
255
|
end
|
|
@@ -119,7 +119,7 @@ module ActiveSupport
|
|
|
119
119
|
# The capitalization of the first word can be turned off by setting the
|
|
120
120
|
# +:capitalize+ option to false (default is true).
|
|
121
121
|
#
|
|
122
|
-
# The trailing '_id' can be kept
|
|
122
|
+
# The trailing '_id' can be kept by setting the
|
|
123
123
|
# optional parameter +keep_id_suffix+ to true (default is false).
|
|
124
124
|
#
|
|
125
125
|
# humanize('employee_salary') # => "Employee salary"
|
|
@@ -143,13 +143,13 @@ module ActiveSupport
|
|
|
143
143
|
result.delete_suffix!(" id")
|
|
144
144
|
end
|
|
145
145
|
|
|
146
|
-
result.gsub!(/([
|
|
146
|
+
result.gsub!(/([[[:alpha:]]\d]+)/i) do |match|
|
|
147
147
|
match.downcase!
|
|
148
148
|
inflections.acronyms[match] || match
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
if capitalize
|
|
152
|
-
result.sub!(/\A
|
|
152
|
+
result.sub!(/\A[[:alpha:]]/) do |match|
|
|
153
153
|
match.upcase!
|
|
154
154
|
match
|
|
155
155
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "fiber"
|
|
4
|
-
|
|
5
3
|
module ActiveSupport
|
|
6
4
|
module IsolatedExecutionState # :nodoc:
|
|
7
5
|
@isolation_level = nil
|
|
@@ -58,11 +56,13 @@ module ActiveSupport
|
|
|
58
56
|
scope.current
|
|
59
57
|
end
|
|
60
58
|
|
|
61
|
-
def share_with(other)
|
|
59
|
+
def share_with(other, except: [])
|
|
62
60
|
# Action Controller streaming spawns a new thread and copy thread locals.
|
|
63
61
|
# We do the same here for backward compatibility, but this is very much a hack
|
|
64
62
|
# and streaming should be rethought.
|
|
65
|
-
|
|
63
|
+
state = other.active_support_execution_state.dup
|
|
64
|
+
Array(except).each { |key| state.delete(key) }
|
|
65
|
+
context.active_support_execution_state = state
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
private
|
|
@@ -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
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
|
|
|
@@ -54,14 +54,14 @@ module ActiveSupport
|
|
|
54
54
|
# Encode the given object into a JSON string
|
|
55
55
|
def encode(value)
|
|
56
56
|
unless options.empty?
|
|
57
|
-
value = value.as_json(options.dup)
|
|
57
|
+
value = value.as_json(options.dup.freeze)
|
|
58
58
|
end
|
|
59
59
|
json = stringify(jsonify(value))
|
|
60
60
|
|
|
61
61
|
# Rails does more escaping than the JSON gem natively does (we
|
|
62
62
|
# escape \u2028 and \u2029 and optionally >, <, & to work around
|
|
63
63
|
# certain browser problems).
|
|
64
|
-
if Encoding.escape_html_entities_in_json
|
|
64
|
+
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
|
|
65
65
|
json.gsub!(">", '\u003e')
|
|
66
66
|
json.gsub!("<", '\u003c')
|
|
67
67
|
json.gsub!("&", '\u0026')
|
|
@@ -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
|
|
@@ -164,7 +164,7 @@ module ActiveSupport
|
|
|
164
164
|
@cpu_time_finish - @cpu_time_start
|
|
165
165
|
end
|
|
166
166
|
|
|
167
|
-
# Returns the idle time
|
|
167
|
+
# Returns the idle time (in milliseconds) passed between the call to
|
|
168
168
|
# #start! and the call to #finish!.
|
|
169
169
|
def idle_time
|
|
170
170
|
diff = duration - cpu_time
|
|
@@ -16,9 +16,24 @@ module ActiveSupport
|
|
|
16
16
|
private
|
|
17
17
|
def parts
|
|
18
18
|
left, right = number.to_s.split(".")
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
if delimiter_pattern
|
|
20
|
+
left.gsub!(delimiter_pattern) do |digit_to_delimit|
|
|
21
|
+
"#{digit_to_delimit}#{options[:delimiter]}"
|
|
22
|
+
end
|
|
23
|
+
else
|
|
24
|
+
left_parts = []
|
|
25
|
+
offset = left.size % 3
|
|
26
|
+
if offset > 0
|
|
27
|
+
left_parts << left[0, offset]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
(left.size / 3).times do |i|
|
|
31
|
+
left_parts << left[offset + (i * 3), 3]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
left = left_parts.join(options[:delimiter])
|
|
21
35
|
end
|
|
36
|
+
|
|
22
37
|
[left, right].compact
|
|
23
38
|
end
|
|
24
39
|
|
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActiveSupport
|
|
4
|
+
# = Number Helper
|
|
5
|
+
#
|
|
6
|
+
# Provides methods for formatting numbers into currencies, percentages,
|
|
7
|
+
# phone numbers, and more.
|
|
8
|
+
#
|
|
9
|
+
# Example usage in a class:
|
|
10
|
+
# class Topic
|
|
11
|
+
# include ActiveSupport::NumberHelper
|
|
12
|
+
#
|
|
13
|
+
# def price
|
|
14
|
+
# number_to_currency(@price)
|
|
15
|
+
# end
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# Example usage in a module:
|
|
19
|
+
# require "active_support/number_helper"
|
|
20
|
+
#
|
|
21
|
+
# module NumberFormatting
|
|
22
|
+
# def format_price(price)
|
|
23
|
+
# ActiveSupport::NumberHelper.number_to_currency(price)
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
4
26
|
module NumberHelper
|
|
5
27
|
extend ActiveSupport::Autoload
|
|
6
28
|
|
|
@@ -96,6 +96,12 @@ module ActiveSupport
|
|
|
96
96
|
config.eager_load_namespaces << TZInfo
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
initializer "active_support.to_time_preserves_timezone" do |app|
|
|
100
|
+
config.after_initialize do
|
|
101
|
+
ActiveSupport.to_time_preserves_timezone = app.config.active_support.to_time_preserves_timezone
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
99
105
|
# Sets the default week start
|
|
100
106
|
# If assigned value is not a valid day symbol (e.g. :sunday, :monday, ...), an exception will be raised.
|
|
101
107
|
initializer "active_support.initialize_beginning_of_week" do |app|
|