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
|
@@ -2,8 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveSupport
|
|
4
4
|
module ExecutionContext # :nodoc:
|
|
5
|
+
class Record # :nodoc:
|
|
6
|
+
attr_reader :store, :current_attributes_instances
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@store = {}
|
|
10
|
+
@current_attributes_instances = {}
|
|
11
|
+
@stack = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def push
|
|
15
|
+
@stack << @store << @current_attributes_instances
|
|
16
|
+
@store = {}
|
|
17
|
+
@current_attributes_instances = {}
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def pop
|
|
22
|
+
@current_attributes_instances = @stack.pop
|
|
23
|
+
@store = @stack.pop
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def flush
|
|
28
|
+
@stack = Array.new(@stack.size) { {} }
|
|
29
|
+
@store = {}
|
|
30
|
+
@current_attributes_instances = {}
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
5
35
|
@after_change_callbacks = []
|
|
36
|
+
|
|
37
|
+
# Execution context nesting should only legitimately happen during test
|
|
38
|
+
# because the test case itself is wrapped in an executor, and it might call
|
|
39
|
+
# into a controller or job which should be executed with their own fresh context.
|
|
40
|
+
# However in production this should never happen, and for extra safety we make sure to
|
|
41
|
+
# fully clear the state at the end of the request or job cycle.
|
|
42
|
+
@nestable = false
|
|
43
|
+
|
|
6
44
|
class << self
|
|
45
|
+
attr_accessor :nestable
|
|
46
|
+
|
|
7
47
|
def after_change(&block)
|
|
8
48
|
@after_change_callbacks << block
|
|
9
49
|
end
|
|
@@ -14,9 +54,11 @@ module ActiveSupport
|
|
|
14
54
|
options.symbolize_keys!
|
|
15
55
|
keys = options.keys
|
|
16
56
|
|
|
17
|
-
store =
|
|
57
|
+
store = record.store
|
|
18
58
|
|
|
19
|
-
previous_context =
|
|
59
|
+
previous_context = if block_given?
|
|
60
|
+
keys.zip(store.values_at(*keys)).to_h
|
|
61
|
+
end
|
|
20
62
|
|
|
21
63
|
store.merge!(options)
|
|
22
64
|
@after_change_callbacks.each(&:call)
|
|
@@ -32,21 +74,47 @@ module ActiveSupport
|
|
|
32
74
|
end
|
|
33
75
|
|
|
34
76
|
def []=(key, value)
|
|
35
|
-
store[key.to_sym] = value
|
|
77
|
+
record.store[key.to_sym] = value
|
|
36
78
|
@after_change_callbacks.each(&:call)
|
|
37
79
|
end
|
|
38
80
|
|
|
39
81
|
def to_h
|
|
40
|
-
store.dup
|
|
82
|
+
record.store.dup
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def push
|
|
86
|
+
if @nestable
|
|
87
|
+
record.push
|
|
88
|
+
else
|
|
89
|
+
clear
|
|
90
|
+
end
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def pop
|
|
95
|
+
if @nestable
|
|
96
|
+
record.pop
|
|
97
|
+
else
|
|
98
|
+
clear
|
|
99
|
+
end
|
|
100
|
+
self
|
|
41
101
|
end
|
|
42
102
|
|
|
43
103
|
def clear
|
|
44
|
-
|
|
104
|
+
IsolatedExecutionState[:active_support_execution_context] = nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def flush
|
|
108
|
+
record.flush
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def current_attributes_instances
|
|
112
|
+
record.current_attributes_instances
|
|
45
113
|
end
|
|
46
114
|
|
|
47
115
|
private
|
|
48
|
-
def
|
|
49
|
-
IsolatedExecutionState[:active_support_execution_context] ||=
|
|
116
|
+
def record
|
|
117
|
+
IsolatedExecutionState[:active_support_execution_context] ||= Record.new
|
|
50
118
|
end
|
|
51
119
|
end
|
|
52
120
|
end
|
|
@@ -46,8 +46,11 @@ module ActiveSupport
|
|
|
46
46
|
raise ArgumentError, "A block is required to initialize a FileUpdateChecker"
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
@
|
|
49
|
+
gem_paths = Gem.path
|
|
50
|
+
@files = files.reject { |file| File.expand_path(file).start_with?(*gem_paths) }.freeze
|
|
51
|
+
|
|
52
|
+
@globs = compile_glob(dirs)&.reject { |dir| dir.start_with?(*gem_paths) }
|
|
53
|
+
|
|
51
54
|
@block = block
|
|
52
55
|
|
|
53
56
|
@watched = nil
|
|
@@ -103,7 +106,7 @@ module ActiveSupport
|
|
|
103
106
|
def watched
|
|
104
107
|
@watched || begin
|
|
105
108
|
all = @files.select { |f| File.exist?(f) }
|
|
106
|
-
all.concat(Dir[
|
|
109
|
+
all.concat(Dir[*@globs]) if @globs
|
|
107
110
|
all.tap(&:uniq!)
|
|
108
111
|
end
|
|
109
112
|
end
|
|
@@ -145,10 +148,9 @@ module ActiveSupport
|
|
|
145
148
|
hash.freeze # Freeze so changes aren't accidentally pushed
|
|
146
149
|
return if hash.empty?
|
|
147
150
|
|
|
148
|
-
|
|
151
|
+
hash.map do |key, value|
|
|
149
152
|
"#{escape(key)}/**/*#{compile_ext(value)}"
|
|
150
153
|
end
|
|
151
|
-
"{#{globs.join(",")}}"
|
|
152
154
|
end
|
|
153
155
|
|
|
154
156
|
def escape(key)
|
data/lib/active_support/gzip.rb
CHANGED
|
@@ -68,15 +68,15 @@ module ActiveSupport
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def initialize(constructor = nil)
|
|
71
|
-
if constructor.
|
|
71
|
+
if constructor.nil?
|
|
72
|
+
super()
|
|
73
|
+
elsif constructor.respond_to?(:to_hash)
|
|
72
74
|
super()
|
|
73
75
|
update(constructor)
|
|
74
76
|
|
|
75
77
|
hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
|
|
76
|
-
self.default = hash.default
|
|
78
|
+
self.default = hash.default unless hash.default.nil?
|
|
77
79
|
self.default_proc = hash.default_proc if hash.default_proc
|
|
78
|
-
elsif constructor.nil?
|
|
79
|
-
super()
|
|
80
80
|
else
|
|
81
81
|
super(constructor)
|
|
82
82
|
end
|
|
@@ -95,11 +95,27 @@ module ActiveSupport
|
|
|
95
95
|
# hash[:key] = 'value'
|
|
96
96
|
#
|
|
97
97
|
# This value can be later fetched using either +:key+ or <tt>'key'</tt>.
|
|
98
|
+
#
|
|
99
|
+
# If the value is a Hash or contains one or multiple Hashes, they will be
|
|
100
|
+
# converted to +HashWithIndifferentAccess+.
|
|
98
101
|
def []=(key, value)
|
|
99
102
|
regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
|
|
100
103
|
end
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
# Assigns a new value to the hash:
|
|
106
|
+
#
|
|
107
|
+
# hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
108
|
+
# hash[:key] = 'value'
|
|
109
|
+
#
|
|
110
|
+
# This value can be later fetched using either +:key+ or <tt>'key'</tt>.
|
|
111
|
+
#
|
|
112
|
+
# If the value is a Hash or contains one or multiple Hashes, they will be
|
|
113
|
+
# converted to +HashWithIndifferentAccess+. unless `convert_value: false`
|
|
114
|
+
# is set.
|
|
115
|
+
def store(key, value, convert_value: true)
|
|
116
|
+
value = convert_value(value, conversion: :assignment) if convert_value
|
|
117
|
+
regular_writer(convert_key(key), value)
|
|
118
|
+
end
|
|
103
119
|
|
|
104
120
|
# Updates the receiver in-place, merging in the hashes passed as arguments:
|
|
105
121
|
#
|
|
@@ -279,13 +295,13 @@ module ActiveSupport
|
|
|
279
295
|
# hash['a'] = nil
|
|
280
296
|
# hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
|
|
281
297
|
def reverse_merge(other_hash)
|
|
282
|
-
super(
|
|
298
|
+
super(cast(other_hash))
|
|
283
299
|
end
|
|
284
300
|
alias_method :with_defaults, :reverse_merge
|
|
285
301
|
|
|
286
302
|
# Same semantics as +reverse_merge+ but modifies the receiver in-place.
|
|
287
303
|
def reverse_merge!(other_hash)
|
|
288
|
-
super(
|
|
304
|
+
super(cast(other_hash))
|
|
289
305
|
end
|
|
290
306
|
alias_method :with_defaults!, :reverse_merge!
|
|
291
307
|
|
|
@@ -294,7 +310,7 @@ module ActiveSupport
|
|
|
294
310
|
# h = { "a" => 100, "b" => 200 }
|
|
295
311
|
# h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
|
|
296
312
|
def replace(other_hash)
|
|
297
|
-
super(
|
|
313
|
+
super(cast(other_hash))
|
|
298
314
|
end
|
|
299
315
|
|
|
300
316
|
# Removes the specified key from the hash.
|
|
@@ -311,10 +327,6 @@ module ActiveSupport
|
|
|
311
327
|
end
|
|
312
328
|
alias_method :without, :except
|
|
313
329
|
|
|
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
330
|
undef :symbolize_keys!
|
|
319
331
|
undef :deep_symbolize_keys!
|
|
320
332
|
def symbolize_keys; to_hash.symbolize_keys! end
|
|
@@ -326,6 +338,7 @@ module ActiveSupport
|
|
|
326
338
|
return to_enum(:select) unless block_given?
|
|
327
339
|
dup.tap { |hash| hash.select!(*args, &block) }
|
|
328
340
|
end
|
|
341
|
+
alias_method :filter, :select
|
|
329
342
|
|
|
330
343
|
def reject(*args, &block)
|
|
331
344
|
return to_enum(:reject) unless block_given?
|
|
@@ -381,13 +394,9 @@ module ActiveSupport
|
|
|
381
394
|
|
|
382
395
|
# Convert to a regular hash with string keys.
|
|
383
396
|
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
|
|
397
|
+
copy = Hash[self]
|
|
398
|
+
copy.transform_values! { |v| convert_value_to_hash(v) }
|
|
399
|
+
copy_defaults(copy)
|
|
391
400
|
end
|
|
392
401
|
|
|
393
402
|
def to_proc
|
|
@@ -395,17 +404,17 @@ module ActiveSupport
|
|
|
395
404
|
end
|
|
396
405
|
|
|
397
406
|
private
|
|
407
|
+
def cast(other)
|
|
408
|
+
self.class === other ? other : self.class.new(other)
|
|
409
|
+
end
|
|
410
|
+
|
|
398
411
|
def convert_key(key)
|
|
399
412
|
Symbol === key ? key.name : key
|
|
400
413
|
end
|
|
401
414
|
|
|
402
415
|
def convert_value(value, conversion: nil)
|
|
403
416
|
if value.is_a? Hash
|
|
404
|
-
|
|
405
|
-
value.to_hash
|
|
406
|
-
else
|
|
407
|
-
value.nested_under_indifferent_access
|
|
408
|
-
end
|
|
417
|
+
value.nested_under_indifferent_access
|
|
409
418
|
elsif value.is_a?(Array)
|
|
410
419
|
if conversion != :assignment || value.frozen?
|
|
411
420
|
value = value.dup
|
|
@@ -416,6 +425,17 @@ module ActiveSupport
|
|
|
416
425
|
end
|
|
417
426
|
end
|
|
418
427
|
|
|
428
|
+
def convert_value_to_hash(value)
|
|
429
|
+
if value.is_a? Hash
|
|
430
|
+
value.to_hash
|
|
431
|
+
elsif value.is_a?(Array)
|
|
432
|
+
value.map { |e| convert_value_to_hash(e) }
|
|
433
|
+
else
|
|
434
|
+
value
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
|
|
419
439
|
def copy_defaults(target)
|
|
420
440
|
if default_proc
|
|
421
441
|
target.default_proc = default_proc.dup
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "active_support"
|
|
4
4
|
require "active_support/core_ext/array/wrap"
|
|
5
|
+
require "rails/railtie"
|
|
5
6
|
|
|
6
7
|
# :enddoc:
|
|
7
8
|
|
|
@@ -14,15 +15,18 @@ module I18n
|
|
|
14
15
|
|
|
15
16
|
config.eager_load_namespaces << I18n
|
|
16
17
|
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
config.
|
|
18
|
+
# Make sure i18n is ready before eager loading, in case any eager loaded
|
|
19
|
+
# code needs it.
|
|
20
|
+
config.before_eager_load do |app|
|
|
20
21
|
I18n::Railtie.initialize_i18n(app)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
24
|
+
# i18n initialization needs to run after application initialization, since
|
|
25
|
+
# initializers may configure i18n.
|
|
26
|
+
#
|
|
27
|
+
# If the application eager loaded, this was done on before_eager_load. The
|
|
28
|
+
# hook is still OK, though, because initialize_i18n is idempotent.
|
|
29
|
+
config.after_initialize do |app|
|
|
26
30
|
I18n::Railtie.initialize_i18n(app)
|
|
27
31
|
end
|
|
28
32
|
|
|
@@ -49,7 +53,8 @@ module I18n
|
|
|
49
53
|
when :load_path
|
|
50
54
|
I18n.load_path += value
|
|
51
55
|
when :raise_on_missing_translations
|
|
52
|
-
|
|
56
|
+
strict = value == :strict
|
|
57
|
+
setup_raise_on_missing_translations_config(app, strict)
|
|
53
58
|
else
|
|
54
59
|
I18n.public_send("#{setting}=", value)
|
|
55
60
|
end
|
|
@@ -62,8 +67,8 @@ module I18n
|
|
|
62
67
|
|
|
63
68
|
if app.config.reloading_enabled?
|
|
64
69
|
directories = watched_dirs_with_extensions(reloadable_paths)
|
|
65
|
-
reloader = app.config.file_watcher.new(I18n.load_path
|
|
66
|
-
I18n.load_path.
|
|
70
|
+
reloader = app.config.file_watcher.new(I18n.load_path, 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
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "concurrent/map"
|
|
4
|
+
require "active_support/core_ext/module/delegation"
|
|
4
5
|
require "active_support/i18n"
|
|
5
6
|
|
|
6
7
|
module ActiveSupport
|
|
@@ -29,45 +30,61 @@ module ActiveSupport
|
|
|
29
30
|
# before any of the rules that may already have been loaded.
|
|
30
31
|
class Inflections
|
|
31
32
|
@__instance__ = Concurrent::Map.new
|
|
33
|
+
@__en_instance__ = nil
|
|
34
|
+
|
|
35
|
+
class Uncountables # :nodoc:
|
|
36
|
+
include Enumerable
|
|
37
|
+
|
|
38
|
+
delegate :each, :pop, :empty?, :to_s, :==, :to_a, :to_ary, to: :@members
|
|
32
39
|
|
|
33
|
-
class Uncountables < Array
|
|
34
40
|
def initialize
|
|
35
|
-
@
|
|
36
|
-
|
|
41
|
+
@members = []
|
|
42
|
+
@pattern = nil
|
|
37
43
|
end
|
|
38
44
|
|
|
39
45
|
def delete(entry)
|
|
40
|
-
|
|
41
|
-
@
|
|
46
|
+
@members.delete(entry)
|
|
47
|
+
@pattern = nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def <<(word)
|
|
51
|
+
word = word.downcase
|
|
52
|
+
@members << word
|
|
53
|
+
@pattern = nil
|
|
54
|
+
self
|
|
42
55
|
end
|
|
43
56
|
|
|
44
|
-
def
|
|
45
|
-
|
|
57
|
+
def flatten
|
|
58
|
+
@members.dup
|
|
46
59
|
end
|
|
47
60
|
|
|
48
61
|
def add(words)
|
|
49
62
|
words = words.flatten.map(&:downcase)
|
|
50
|
-
concat(words)
|
|
51
|
-
@
|
|
63
|
+
@members.concat(words)
|
|
64
|
+
@pattern = nil
|
|
52
65
|
self
|
|
53
66
|
end
|
|
54
67
|
|
|
55
68
|
def uncountable?(str)
|
|
56
|
-
@
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
private
|
|
60
|
-
def to_regex(string)
|
|
61
|
-
/\b#{::Regexp.escape(string)}\Z/i
|
|
69
|
+
if @pattern.nil?
|
|
70
|
+
members_pattern = Regexp.union(@members.map { |w| /#{Regexp.escape(w)}/i })
|
|
71
|
+
@pattern = /\b#{members_pattern}\Z/i
|
|
62
72
|
end
|
|
73
|
+
@pattern.match?(str)
|
|
74
|
+
end
|
|
63
75
|
end
|
|
64
76
|
|
|
65
77
|
def self.instance(locale = :en)
|
|
78
|
+
return @__en_instance__ ||= new if locale == :en
|
|
79
|
+
|
|
66
80
|
@__instance__[locale] ||= new
|
|
67
81
|
end
|
|
68
82
|
|
|
69
83
|
def self.instance_or_fallback(locale)
|
|
84
|
+
return @__en_instance__ ||= new if locale == :en
|
|
85
|
+
|
|
70
86
|
I18n.fallbacks[locale].each do |k|
|
|
87
|
+
return @__en_instance__ if k == :en && @__en_instance__
|
|
71
88
|
return @__instance__[k] if @__instance__.key?(k)
|
|
72
89
|
end
|
|
73
90
|
instance(locale)
|
|
@@ -248,7 +265,8 @@ module ActiveSupport
|
|
|
248
265
|
|
|
249
266
|
private
|
|
250
267
|
def define_acronym_regex_patterns
|
|
251
|
-
|
|
268
|
+
sorted_acronyms = @acronyms.empty? ? [] : @acronyms.values.sort_by { |a| -a.length }
|
|
269
|
+
@acronym_regex = sorted_acronyms.empty? ? /(?=a)b/ : /#{sorted_acronyms.join("|")}/
|
|
252
270
|
@acronyms_camelize_regex = /^(?:#{@acronym_regex}(?=\b|[A-Z_])|\w)/
|
|
253
271
|
@acronyms_underscore_regex = /(?:(?<=([A-Za-z\d]))|\b)(#{@acronym_regex})(?=\b|[^a-z])/
|
|
254
272
|
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
|
|
@@ -190,7 +190,7 @@ module ActiveSupport
|
|
|
190
190
|
# titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
|
|
191
191
|
# titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
|
|
192
192
|
def titleize(word, keep_id_suffix: false)
|
|
193
|
-
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])
|
|
193
|
+
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])\p{Lower}/) do |match|
|
|
194
194
|
match.capitalize
|
|
195
195
|
end
|
|
196
196
|
end
|
|
@@ -319,7 +319,8 @@ module ActiveSupport
|
|
|
319
319
|
e.name.to_s == camel_cased_word.to_s)
|
|
320
320
|
rescue LoadError => e
|
|
321
321
|
message = e.respond_to?(:original_message) ? e.original_message : e.message
|
|
322
|
-
|
|
322
|
+
constant_name = camel_cased_word.split("::").find { |part| !part.empty? } || camel_cased_word
|
|
323
|
+
raise unless message.include?("Unable to autoload constant #{constant_name}")
|
|
323
324
|
end
|
|
324
325
|
|
|
325
326
|
# Returns the suffix that should be added to a number to denote the position
|
|
@@ -349,23 +350,6 @@ module ActiveSupport
|
|
|
349
350
|
end
|
|
350
351
|
|
|
351
352
|
private
|
|
352
|
-
# Mounts a regular expression, returned as a string to ease interpolation,
|
|
353
|
-
# that will match part by part the given constant.
|
|
354
|
-
#
|
|
355
|
-
# const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
|
|
356
|
-
# const_regexp("::") # => "::"
|
|
357
|
-
def const_regexp(camel_cased_word)
|
|
358
|
-
parts = camel_cased_word.split("::")
|
|
359
|
-
|
|
360
|
-
return Regexp.escape(camel_cased_word) if parts.empty?
|
|
361
|
-
|
|
362
|
-
last = parts.pop
|
|
363
|
-
|
|
364
|
-
parts.reverse!.inject(last) do |acc, part|
|
|
365
|
-
part.empty? ? acc : "#{part}(::#{acc})?"
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
|
|
369
353
|
# Applies inflection rules for +singularize+ and +pluralize+.
|
|
370
354
|
#
|
|
371
355
|
# If passed an optional +locale+ parameter, the uncountables will be
|
|
@@ -66,7 +66,10 @@ module ActiveSupport
|
|
|
66
66
|
raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
|
|
67
67
|
|
|
68
68
|
return string.dup if string.ascii_only?
|
|
69
|
-
|
|
69
|
+
|
|
70
|
+
# Operate on a copy so the in-place force_encoding/encode! below never
|
|
71
|
+
# mutate the caller's (possibly non-frozen) string.
|
|
72
|
+
string = string.dup
|
|
70
73
|
|
|
71
74
|
input_encoding = string.encoding
|
|
72
75
|
|
|
@@ -105,6 +108,11 @@ module ActiveSupport
|
|
|
105
108
|
# parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
|
|
106
109
|
# parameterize("^très|Jolie__ ", separator: '_') # => "tres_jolie"
|
|
107
110
|
#
|
|
111
|
+
# To remove the unwanted characters instead of replacing them, pass an
|
|
112
|
+
# empty separator. +nil+ is treated the same way.
|
|
113
|
+
#
|
|
114
|
+
# parameterize("Donald E. Knuth", separator: '') # => "donaldeknuth"
|
|
115
|
+
#
|
|
108
116
|
# To preserve the case of the characters in a string, use the +preserve_case+ argument.
|
|
109
117
|
#
|
|
110
118
|
# parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
|
|
@@ -121,25 +129,25 @@ module ActiveSupport
|
|
|
121
129
|
# By default, this parameter is set to <tt>nil</tt> and it will use
|
|
122
130
|
# the configured <tt>I18n.locale</tt>.
|
|
123
131
|
def parameterize(string, separator: "-", preserve_case: false, locale: nil)
|
|
132
|
+
separator ||= ""
|
|
133
|
+
|
|
124
134
|
# Replace accented chars with their ASCII equivalents.
|
|
125
135
|
parameterized_string = transliterate(string, locale: locale)
|
|
126
136
|
|
|
127
137
|
# Turn unwanted chars into the separator.
|
|
128
138
|
parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator)
|
|
129
139
|
|
|
130
|
-
unless separator.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
unless separator.empty?
|
|
141
|
+
# No more than one of the separator in a row.
|
|
142
|
+
if separator.length == 1
|
|
143
|
+
parameterized_string.squeeze!(separator)
|
|
134
144
|
else
|
|
135
145
|
re_sep = Regexp.escape(separator)
|
|
136
|
-
|
|
137
|
-
re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
|
|
146
|
+
parameterized_string.gsub!(/#{re_sep}{2,}/, separator)
|
|
138
147
|
end
|
|
139
|
-
# No more than one of the separator in a row.
|
|
140
|
-
parameterized_string.gsub!(re_duplicate_separator, separator)
|
|
141
148
|
# Remove leading/trailing separator.
|
|
142
|
-
parameterized_string.
|
|
149
|
+
parameterized_string.delete_prefix!(separator)
|
|
150
|
+
parameterized_string.delete_suffix!(separator)
|
|
143
151
|
end
|
|
144
152
|
|
|
145
153
|
parameterized_string.downcase! unless preserve_case
|
|
@@ -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
|
|
@@ -30,45 +28,47 @@ module ActiveSupport
|
|
|
30
28
|
@isolation_level = level
|
|
31
29
|
end
|
|
32
30
|
|
|
33
|
-
def unique_id
|
|
34
|
-
self[:__id__] ||= Object.new
|
|
35
|
-
end
|
|
36
|
-
|
|
37
31
|
def [](key)
|
|
38
|
-
state
|
|
32
|
+
if state = @scope.current.active_support_execution_state
|
|
33
|
+
state[key]
|
|
34
|
+
end
|
|
39
35
|
end
|
|
40
36
|
|
|
41
37
|
def []=(key, value)
|
|
38
|
+
state = (@scope.current.active_support_execution_state ||= {})
|
|
42
39
|
state[key] = value
|
|
43
40
|
end
|
|
44
41
|
|
|
45
42
|
def key?(key)
|
|
46
|
-
|
|
43
|
+
@scope.current.active_support_execution_state&.key?(key)
|
|
47
44
|
end
|
|
48
45
|
|
|
49
46
|
def delete(key)
|
|
50
|
-
|
|
47
|
+
@scope.current.active_support_execution_state&.delete(key)
|
|
51
48
|
end
|
|
52
49
|
|
|
53
50
|
def clear
|
|
54
|
-
|
|
51
|
+
@scope.current.active_support_execution_state&.clear
|
|
55
52
|
end
|
|
56
53
|
|
|
57
54
|
def context
|
|
58
55
|
scope.current
|
|
59
56
|
end
|
|
60
57
|
|
|
61
|
-
def share_with(other)
|
|
58
|
+
def share_with(other, except: [], &block)
|
|
62
59
|
# Action Controller streaming spawns a new thread and copy thread locals.
|
|
63
60
|
# We do the same here for backward compatibility, but this is very much a hack
|
|
64
61
|
# and streaming should be rethought.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
def state
|
|
70
|
-
context.active_support_execution_state ||= {}
|
|
62
|
+
if state = other.active_support_execution_state
|
|
63
|
+
copied_state = state.dup
|
|
64
|
+
Array(except).each { |key| copied_state.delete(key) }
|
|
71
65
|
end
|
|
66
|
+
|
|
67
|
+
old_state, context.active_support_execution_state = context.active_support_execution_state, copied_state
|
|
68
|
+
block.call
|
|
69
|
+
ensure
|
|
70
|
+
context.active_support_execution_state = old_state
|
|
71
|
+
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
self.isolation_level = :thread
|