activesupport 6.1.0 → 7.1.5.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 +1075 -325
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -7
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +32 -7
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +53 -20
- data/lib/active_support/cache/mem_cache_store.rb +201 -62
- data/lib/active_support/cache/memory_store.rb +86 -24
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +186 -193
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +63 -71
- data/lib/active_support/cache.rb +487 -249
- data/lib/active_support/callbacks.rb +227 -105
- data/lib/active_support/code_generator.rb +70 -0
- data/lib/active_support/concern.rb +9 -7
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +18 -5
- data/lib/active_support/configuration_file.rb +7 -2
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +15 -13
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +37 -26
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
- data/lib/active_support/core_ext/digest/uuid.rb +30 -13
- data/lib/active_support/core_ext/enumerable.rb +85 -83
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +1 -2
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +8 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +81 -43
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
- data/lib/active_support/core_ext/object/duplicable.rb +31 -11
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +49 -27
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +25 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +34 -13
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +17 -10
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +85 -165
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +30 -8
- data/lib/active_support/core_ext/time/conversions.rb +15 -13
- data/lib/active_support/core_ext/time/zones.rb +12 -28
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes.rb +47 -20
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +66 -40
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +6 -8
- data/lib/active_support/deprecation/instance_delegator.rb +31 -4
- data/lib/active_support/deprecation/method_wrappers.rb +9 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
- data/lib/active_support/deprecation/reporting.rb +43 -26
- data/lib/active_support/deprecation.rb +32 -5
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -72
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -3
- data/lib/active_support/duration.rb +83 -52
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +29 -13
- data/lib/active_support/environment_inquirer.rb +23 -3
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +203 -0
- data/lib/active_support/evented_file_update_checker.rb +20 -7
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +44 -22
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +28 -11
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +44 -19
- data/lib/active_support/html_safe_translation.rb +53 -0
- data/lib/active_support/i18n.rb +2 -1
- data/lib/active_support/i18n_railtie.rb +21 -14
- data/lib/active_support/inflector/inflections.rb +25 -7
- data/lib/active_support/inflector/methods.rb +50 -64
- data/lib/active_support/inflector/transliterate.rb +4 -2
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +27 -45
- data/lib/active_support/key_generator.rb +31 -6
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +4 -2
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +97 -35
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_thread_safe_level.rb +11 -34
- data/lib/active_support/message_encryptor.rb +206 -56
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +235 -84
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +112 -46
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +12 -11
- data/lib/active_support/multibyte/unicode.rb +9 -49
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +304 -114
- data/lib/active_support/notifications/instrumenter.rb +117 -35
- data/lib/active_support/notifications.rb +25 -25
- data/lib/active_support/number_helper/number_converter.rb +14 -7
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -4
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
- data/lib/active_support/number_helper/rounding_helper.rb +2 -6
- data/lib/active_support/number_helper.rb +379 -319
- data/lib/active_support/option_merger.rb +10 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +15 -1
- data/lib/active_support/parameter_filter.rb +105 -81
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/railtie.rb +83 -21
- data/lib/active_support/reloader.rb +13 -5
- data/lib/active_support/rescuable.rb +18 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +18 -11
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/string_inquirer.rb +3 -3
- data/lib/active_support/subscriber.rb +11 -40
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +65 -25
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +61 -15
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +53 -2
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +30 -29
- data/lib/active_support/testing/method_call_assertions.rb +24 -11
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +4 -6
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +49 -16
- data/lib/active_support/time_with_zone.rb +39 -28
- data/lib/active_support/values/time_zone.rb +50 -18
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +4 -11
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +5 -5
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +2 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +28 -1
- metadata +150 -18
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -29
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -3,8 +3,11 @@
|
|
3
3
|
require "active_support/core_ext/hash/keys"
|
4
4
|
require "active_support/core_ext/hash/reverse_merge"
|
5
5
|
require "active_support/core_ext/hash/except"
|
6
|
+
require "active_support/core_ext/hash/slice"
|
6
7
|
|
7
8
|
module ActiveSupport
|
9
|
+
# = \Hash With Indifferent Access
|
10
|
+
#
|
8
11
|
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
|
9
12
|
# to be the same.
|
10
13
|
#
|
@@ -36,7 +39,7 @@ module ActiveSupport
|
|
36
39
|
#
|
37
40
|
# but this class is intended for use cases where strings or symbols are the
|
38
41
|
# expected keys and it is convenient to understand both as the same. For
|
39
|
-
# example the +params+ hash in Ruby on Rails.
|
42
|
+
# example the +params+ hash in Ruby on \Rails.
|
40
43
|
#
|
41
44
|
# Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
|
42
45
|
#
|
@@ -44,7 +47,7 @@ module ActiveSupport
|
|
44
47
|
#
|
45
48
|
# which may be handy.
|
46
49
|
#
|
47
|
-
# To access this class outside of Rails, require the core extension with:
|
50
|
+
# To access this class outside of \Rails, require the core extension with:
|
48
51
|
#
|
49
52
|
# require "active_support/core_ext/hash/indifferent_access"
|
50
53
|
#
|
@@ -64,7 +67,7 @@ module ActiveSupport
|
|
64
67
|
self
|
65
68
|
end
|
66
69
|
|
67
|
-
def initialize(constructor =
|
70
|
+
def initialize(constructor = nil)
|
68
71
|
if constructor.respond_to?(:to_hash)
|
69
72
|
super()
|
70
73
|
update(constructor)
|
@@ -72,6 +75,8 @@ module ActiveSupport
|
|
72
75
|
hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
|
73
76
|
self.default = hash.default if hash.default
|
74
77
|
self.default_proc = hash.default_proc if hash.default_proc
|
78
|
+
elsif constructor.nil?
|
79
|
+
super()
|
75
80
|
else
|
76
81
|
super(constructor)
|
77
82
|
end
|
@@ -110,10 +115,10 @@ module ActiveSupport
|
|
110
115
|
# hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
|
111
116
|
#
|
112
117
|
# The arguments can be either an
|
113
|
-
#
|
118
|
+
# +ActiveSupport::HashWithIndifferentAccess+ or a regular +Hash+.
|
114
119
|
# In either case the merge respects the semantics of indifferent access.
|
115
120
|
#
|
116
|
-
# If the argument is a regular hash with keys +:key+ and
|
121
|
+
# If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
|
117
122
|
# of the values end up in the receiver, but which one is unspecified.
|
118
123
|
#
|
119
124
|
# When given a block, the value for duplicated keys will be determined
|
@@ -215,8 +220,12 @@ module ActiveSupport
|
|
215
220
|
# hash.default # => nil
|
216
221
|
# hash.default('foo') # => 'foo'
|
217
222
|
# hash.default(:foo) # => 'foo'
|
218
|
-
def default(
|
219
|
-
|
223
|
+
def default(key = (no_key = true))
|
224
|
+
if no_key
|
225
|
+
super()
|
226
|
+
else
|
227
|
+
super(convert_key(key))
|
228
|
+
end
|
220
229
|
end
|
221
230
|
|
222
231
|
# Returns an array of the values at the specified indices:
|
@@ -226,7 +235,8 @@ module ActiveSupport
|
|
226
235
|
# hash[:b] = 'y'
|
227
236
|
# hash.values_at('a', 'b') # => ["x", "y"]
|
228
237
|
def values_at(*keys)
|
229
|
-
|
238
|
+
keys.map! { |key| convert_key(key) }
|
239
|
+
super
|
230
240
|
end
|
231
241
|
|
232
242
|
# Returns an array of the values at the specified indices, but also
|
@@ -239,7 +249,8 @@ module ActiveSupport
|
|
239
249
|
# hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
|
240
250
|
# hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
|
241
251
|
def fetch_values(*indices, &block)
|
242
|
-
|
252
|
+
indices.map! { |key| convert_key(key) }
|
253
|
+
super
|
243
254
|
end
|
244
255
|
|
245
256
|
# Returns a shallow copy of the hash.
|
@@ -293,8 +304,12 @@ module ActiveSupport
|
|
293
304
|
super(convert_key(key))
|
294
305
|
end
|
295
306
|
|
307
|
+
# Returns a hash with indifferent access that includes everything except given keys.
|
308
|
+
# hash = { a: "x", b: "y", c: 10 }.with_indifferent_access
|
309
|
+
# hash.except(:a, "b") # => {c: 10}.with_indifferent_access
|
310
|
+
# hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
|
296
311
|
def except(*keys)
|
297
|
-
|
312
|
+
dup.except!(*keys)
|
298
313
|
end
|
299
314
|
alias_method :without, :except
|
300
315
|
|
@@ -319,21 +334,31 @@ module ActiveSupport
|
|
319
334
|
dup.tap { |hash| hash.reject!(*args, &block) }
|
320
335
|
end
|
321
336
|
|
322
|
-
def transform_values(
|
337
|
+
def transform_values(&block)
|
323
338
|
return to_enum(:transform_values) unless block_given?
|
324
|
-
dup.tap { |hash| hash.transform_values!(
|
339
|
+
dup.tap { |hash| hash.transform_values!(&block) }
|
325
340
|
end
|
326
341
|
|
327
|
-
|
328
|
-
|
329
|
-
|
342
|
+
NOT_GIVEN = Object.new # :nodoc:
|
343
|
+
|
344
|
+
def transform_keys(hash = NOT_GIVEN, &block)
|
345
|
+
return to_enum(:transform_keys) if NOT_GIVEN.equal?(hash) && !block_given?
|
346
|
+
dup.tap { |h| h.transform_keys!(hash, &block) }
|
330
347
|
end
|
331
348
|
|
332
|
-
def transform_keys!
|
333
|
-
return
|
334
|
-
|
335
|
-
|
349
|
+
def transform_keys!(hash = NOT_GIVEN, &block)
|
350
|
+
return to_enum(:transform_keys!) if NOT_GIVEN.equal?(hash) && !block_given?
|
351
|
+
|
352
|
+
if hash.nil?
|
353
|
+
super
|
354
|
+
elsif NOT_GIVEN.equal?(hash)
|
355
|
+
keys.each { |key| self[yield(key)] = delete(key) }
|
356
|
+
elsif block_given?
|
357
|
+
keys.each { |key| self[hash[key] || yield(key)] = delete(key) }
|
358
|
+
else
|
359
|
+
keys.each { |key| self[hash[key] || key] = delete(key) }
|
336
360
|
end
|
361
|
+
|
337
362
|
self
|
338
363
|
end
|
339
364
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module HtmlSafeTranslation # :nodoc:
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def translate(key, **options)
|
8
|
+
if html_safe_translation_key?(key)
|
9
|
+
html_safe_options = html_escape_translation_options(options)
|
10
|
+
|
11
|
+
exception = false
|
12
|
+
exception_handler = ->(*args) do
|
13
|
+
exception = true
|
14
|
+
I18n.exception_handler.call(*args)
|
15
|
+
end
|
16
|
+
translation = I18n.translate(key, **html_safe_options, exception_handler: exception_handler)
|
17
|
+
if exception
|
18
|
+
translation
|
19
|
+
else
|
20
|
+
html_safe_translation(translation)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
I18n.translate(key, **options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def html_safe_translation_key?(key)
|
28
|
+
/(?:_|\b)html\z/.match?(key)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def html_escape_translation_options(options)
|
33
|
+
options.each do |name, value|
|
34
|
+
unless i18n_option?(name) || (name == :count && value.is_a?(Numeric))
|
35
|
+
options[name] = ERB::Util.html_escape(value.to_s)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def i18n_option?(name)
|
41
|
+
(@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def html_safe_translation(translation)
|
46
|
+
if translation.respond_to?(:map)
|
47
|
+
translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
|
48
|
+
else
|
49
|
+
translation.respond_to?(:html_safe) ? translation.html_safe : translation
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/active_support/i18n.rb
CHANGED
@@ -5,8 +5,9 @@ require "active_support/core_ext/hash/except"
|
|
5
5
|
require "active_support/core_ext/hash/slice"
|
6
6
|
begin
|
7
7
|
require "i18n"
|
8
|
+
require "i18n/backend/fallbacks"
|
8
9
|
rescue LoadError => e
|
9
|
-
|
10
|
+
warn "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
|
10
11
|
raise e
|
11
12
|
end
|
12
13
|
require "active_support/lazy_load_hooks"
|
@@ -49,7 +49,7 @@ module I18n
|
|
49
49
|
when :load_path
|
50
50
|
I18n.load_path += value
|
51
51
|
when :raise_on_missing_translations
|
52
|
-
|
52
|
+
setup_raise_on_missing_translations_config(app)
|
53
53
|
else
|
54
54
|
I18n.public_send("#{setting}=", value)
|
55
55
|
end
|
@@ -60,28 +60,35 @@ module I18n
|
|
60
60
|
# Restore available locales check so it will take place from now on.
|
61
61
|
I18n.enforce_available_locales = enforce_available_locales
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
I18n.load_path.
|
66
|
-
|
67
|
-
|
63
|
+
if app.config.reloading_enabled?
|
64
|
+
directories = watched_dirs_with_extensions(reloadable_paths)
|
65
|
+
reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
|
66
|
+
I18n.load_path.keep_if { |p| File.exist?(p) }
|
67
|
+
I18n.load_path |= reloadable_paths.flat_map(&:existent)
|
68
|
+
end
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
app.reloaders << reloader
|
71
|
+
app.reloader.to_run do
|
72
|
+
reloader.execute_if_updated { require_unload_lock! }
|
73
|
+
end
|
74
|
+
reloader.execute
|
72
75
|
end
|
73
|
-
reloader.execute
|
74
76
|
|
75
77
|
@i18n_inited = true
|
76
78
|
end
|
77
79
|
|
78
|
-
def self.
|
80
|
+
def self.setup_raise_on_missing_translations_config(app)
|
79
81
|
ActiveSupport.on_load(:action_view) do
|
80
|
-
|
82
|
+
ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
|
81
83
|
end
|
82
84
|
|
83
|
-
|
84
|
-
|
85
|
+
if app.config.i18n.raise_on_missing_translations &&
|
86
|
+
I18n.exception_handler.is_a?(I18n::ExceptionHandler) # Only override the i18n gem's default exception handler.
|
87
|
+
|
88
|
+
I18n.exception_handler = ->(exception, *) {
|
89
|
+
exception = exception.to_exception if exception.is_a?(I18n::MissingTranslation)
|
90
|
+
raise exception
|
91
|
+
}
|
85
92
|
end
|
86
93
|
end
|
87
94
|
|
@@ -7,6 +7,8 @@ module ActiveSupport
|
|
7
7
|
module Inflector
|
8
8
|
extend self
|
9
9
|
|
10
|
+
# = Active Support \Inflections
|
11
|
+
#
|
10
12
|
# A singleton instance of this class is yielded by Inflector.inflections,
|
11
13
|
# which can then be used to specify additional inflection rules. If passed
|
12
14
|
# an optional locale, rules for other languages can be specified. The
|
@@ -16,13 +18,13 @@ module ActiveSupport
|
|
16
18
|
# inflect.plural /^(ox)$/i, '\1\2en'
|
17
19
|
# inflect.singular /^(ox)en/i, '\1'
|
18
20
|
#
|
19
|
-
# inflect.irregular '
|
21
|
+
# inflect.irregular 'cactus', 'cacti'
|
20
22
|
#
|
21
23
|
# inflect.uncountable 'equipment'
|
22
24
|
# end
|
23
25
|
#
|
24
26
|
# New rules are added at the top. So in the example above, the irregular
|
25
|
-
# rule for
|
27
|
+
# rule for cactus will now be the first of the pluralization and
|
26
28
|
# singularization rules that is runs. This guarantees that your rules run
|
27
29
|
# before any of the rules that may already have been loaded.
|
28
30
|
class Inflections
|
@@ -64,6 +66,13 @@ module ActiveSupport
|
|
64
66
|
@__instance__[locale] ||= new
|
65
67
|
end
|
66
68
|
|
69
|
+
def self.instance_or_fallback(locale)
|
70
|
+
I18n.fallbacks[locale].each do |k|
|
71
|
+
return @__instance__[k] if @__instance__.key?(k)
|
72
|
+
end
|
73
|
+
instance(locale)
|
74
|
+
end
|
75
|
+
|
67
76
|
attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms
|
68
77
|
|
69
78
|
attr_reader :acronyms_camelize_regex, :acronyms_underscore_regex # :nodoc:
|
@@ -160,7 +169,7 @@ module ActiveSupport
|
|
160
169
|
# regular expressions. You simply pass the irregular in singular and
|
161
170
|
# plural form.
|
162
171
|
#
|
163
|
-
# irregular '
|
172
|
+
# irregular 'cactus', 'cacti'
|
164
173
|
# irregular 'person', 'people'
|
165
174
|
def irregular(singular, plural)
|
166
175
|
@uncountables.delete(singular)
|
@@ -215,15 +224,24 @@ module ActiveSupport
|
|
215
224
|
# Clears the loaded inflections within a given scope (default is
|
216
225
|
# <tt>:all</tt>). Give the scope as a symbol of the inflection type, the
|
217
226
|
# options are: <tt>:plurals</tt>, <tt>:singulars</tt>, <tt>:uncountables</tt>,
|
218
|
-
# <tt>:humans</tt>.
|
227
|
+
# <tt>:humans</tt>, <tt>:acronyms</tt>.
|
219
228
|
#
|
220
229
|
# clear :all
|
221
230
|
# clear :plurals
|
222
231
|
def clear(scope = :all)
|
223
232
|
case scope
|
224
233
|
when :all
|
225
|
-
|
226
|
-
|
234
|
+
clear(:acronyms)
|
235
|
+
clear(:plurals)
|
236
|
+
clear(:singulars)
|
237
|
+
clear(:uncountables)
|
238
|
+
clear(:humans)
|
239
|
+
when :acronyms
|
240
|
+
@acronyms = {}
|
241
|
+
define_acronym_regex_patterns
|
242
|
+
when :uncountables
|
243
|
+
@uncountables = Uncountables.new
|
244
|
+
when :plurals, :singulars, :humans
|
227
245
|
instance_variable_set "@#{scope}", []
|
228
246
|
end
|
229
247
|
end
|
@@ -248,7 +266,7 @@ module ActiveSupport
|
|
248
266
|
if block_given?
|
249
267
|
yield Inflections.instance(locale)
|
250
268
|
else
|
251
|
-
Inflections.
|
269
|
+
Inflections.instance_or_fallback(locale)
|
252
270
|
end
|
253
271
|
end
|
254
272
|
end
|
@@ -1,15 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/inflections"
|
4
|
-
require "active_support/core_ext/object/blank"
|
5
4
|
|
6
5
|
module ActiveSupport
|
6
|
+
# = Active Support \Inflector
|
7
|
+
#
|
7
8
|
# The Inflector transforms words from singular to plural, class names to table
|
8
9
|
# names, modularized class names to ones without, and class names to foreign
|
9
10
|
# keys. The default inflections for pluralization, singularization, and
|
10
11
|
# uncountable words are kept in inflections.rb.
|
11
12
|
#
|
12
|
-
# The Rails core team has stated patches for the inflections library will not
|
13
|
+
# The \Rails core team has stated patches for the inflections library will not
|
13
14
|
# be accepted in order to avoid breaking legacy applications which may be
|
14
15
|
# relying on errant inflections. If you discover an incorrect inflection and
|
15
16
|
# require it for your application or wish to define rules for languages other
|
@@ -68,13 +69,19 @@ module ActiveSupport
|
|
68
69
|
# camelize(underscore('SSLError')) # => "SslError"
|
69
70
|
def camelize(term, uppercase_first_letter = true)
|
70
71
|
string = term.to_s
|
71
|
-
|
72
|
-
|
72
|
+
# String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
|
73
|
+
if !uppercase_first_letter || uppercase_first_letter == :lower
|
74
|
+
string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
|
75
|
+
elsif string.match?(/\A[a-z\d]*\z/)
|
76
|
+
return inflections.acronyms[string]&.dup || string.capitalize
|
73
77
|
else
|
74
|
-
string = string.sub(
|
78
|
+
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
|
79
|
+
end
|
80
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
|
81
|
+
word = $2
|
82
|
+
substituted = inflections.acronyms[word] || word.capitalize! || word
|
83
|
+
$1 ? "::#{substituted}" : substituted
|
75
84
|
end
|
76
|
-
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
77
|
-
string.gsub!("/", "::")
|
78
85
|
string
|
79
86
|
end
|
80
87
|
|
@@ -90,11 +97,10 @@ module ActiveSupport
|
|
90
97
|
#
|
91
98
|
# camelize(underscore('SSLError')) # => "SslError"
|
92
99
|
def underscore(camel_cased_word)
|
93
|
-
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
100
|
+
return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
|
94
101
|
word = camel_cased_word.to_s.gsub("::", "/")
|
95
102
|
word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
|
96
|
-
word.gsub!(/([A-Z
|
97
|
-
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
103
|
+
word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
|
98
104
|
word.tr!("-", "_")
|
99
105
|
word.downcase!
|
100
106
|
word
|
@@ -106,7 +112,7 @@ module ActiveSupport
|
|
106
112
|
#
|
107
113
|
# * Applies human inflection rules to the argument.
|
108
114
|
# * Deletes leading underscores, if any.
|
109
|
-
# * Removes
|
115
|
+
# * Removes an "_id" suffix if present.
|
110
116
|
# * Replaces underscores with spaces, if any.
|
111
117
|
# * Downcases all words except acronyms.
|
112
118
|
# * Capitalizes the first word.
|
@@ -120,7 +126,7 @@ module ActiveSupport
|
|
120
126
|
# humanize('author_id') # => "Author"
|
121
127
|
# humanize('author_id', capitalize: false) # => "author"
|
122
128
|
# humanize('_id') # => "Id"
|
123
|
-
# humanize('author_id', keep_id_suffix: true) # => "Author
|
129
|
+
# humanize('author_id', keep_id_suffix: true) # => "Author id"
|
124
130
|
#
|
125
131
|
# If "SSL" was defined to be an acronym:
|
126
132
|
#
|
@@ -131,42 +137,53 @@ module ActiveSupport
|
|
131
137
|
|
132
138
|
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
|
133
139
|
|
134
|
-
result.sub!(/\A_+/, "")
|
135
|
-
unless keep_id_suffix
|
136
|
-
result.delete_suffix!("_id")
|
137
|
-
end
|
138
140
|
result.tr!("_", " ")
|
141
|
+
result.lstrip!
|
142
|
+
if !keep_id_suffix && lower_case_and_underscored_word&.end_with?("_id")
|
143
|
+
result.delete_suffix!(" id")
|
144
|
+
end
|
139
145
|
|
140
|
-
result.gsub!(/([a-z\d]
|
141
|
-
|
146
|
+
result.gsub!(/([a-z\d]+)/i) do |match|
|
147
|
+
match.downcase!
|
148
|
+
inflections.acronyms[match] || match
|
142
149
|
end
|
143
150
|
|
144
151
|
if capitalize
|
145
|
-
result.sub!(/\A\w/)
|
152
|
+
result.sub!(/\A\w/) do |match|
|
153
|
+
match.upcase!
|
154
|
+
match
|
155
|
+
end
|
146
156
|
end
|
147
157
|
|
148
158
|
result
|
149
159
|
end
|
150
160
|
|
151
|
-
# Converts
|
161
|
+
# Converts the first character in the string to uppercase.
|
152
162
|
#
|
153
163
|
# upcase_first('what a Lovely Day') # => "What a Lovely Day"
|
154
164
|
# upcase_first('w') # => "W"
|
155
165
|
# upcase_first('') # => ""
|
156
166
|
def upcase_first(string)
|
157
|
-
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
|
167
|
+
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +""
|
168
|
+
end
|
169
|
+
|
170
|
+
# Converts the first character in the string to lowercase.
|
171
|
+
#
|
172
|
+
# downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
|
173
|
+
# downcase_first('I') # => "i"
|
174
|
+
# downcase_first('') # => ""
|
175
|
+
def downcase_first(string)
|
176
|
+
string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
|
158
177
|
end
|
159
178
|
|
160
179
|
# Capitalizes all the words and replaces some characters in the string to
|
161
180
|
# create a nicer looking title. +titleize+ is meant for creating pretty
|
162
|
-
# output. It is not used in the Rails internals.
|
181
|
+
# output. It is not used in the \Rails internals.
|
163
182
|
#
|
164
183
|
# The trailing '_id','Id'.. can be kept and capitalized by setting the
|
165
184
|
# optional parameter +keep_id_suffix+ to true.
|
166
185
|
# By default, this parameter is false.
|
167
186
|
#
|
168
|
-
# +titleize+ is also aliased as +titlecase+.
|
169
|
-
#
|
170
187
|
# titleize('man from the boondocks') # => "Man From The Boondocks"
|
171
188
|
# titleize('x-men: the last stand') # => "X Men: The Last Stand"
|
172
189
|
# titleize('TheManWithoutAPast') # => "The Man Without A Past"
|
@@ -178,7 +195,7 @@ module ActiveSupport
|
|
178
195
|
end
|
179
196
|
end
|
180
197
|
|
181
|
-
# Creates the name of a table like Rails does for models to table names.
|
198
|
+
# Creates the name of a table like \Rails does for models to table names.
|
182
199
|
# This method uses the #pluralize method on the last word in the string.
|
183
200
|
#
|
184
201
|
# tableize('RawScaledScorer') # => "raw_scaled_scorers"
|
@@ -188,9 +205,9 @@ module ActiveSupport
|
|
188
205
|
pluralize(underscore(class_name))
|
189
206
|
end
|
190
207
|
|
191
|
-
# Creates a class name from a plural table name like Rails does for table
|
192
|
-
# names to models. Note that this returns a string and not a Class (To
|
193
|
-
# convert to an actual class follow +classify+ with #constantize)
|
208
|
+
# Creates a class name from a plural table name like \Rails does for table
|
209
|
+
# names to models. Note that this returns a string and not a Class. (To
|
210
|
+
# convert to an actual class follow +classify+ with #constantize.)
|
194
211
|
#
|
195
212
|
# classify('ham_and_eggs') # => "HamAndEgg"
|
196
213
|
# classify('posts') # => "Post"
|
@@ -221,7 +238,7 @@ module ActiveSupport
|
|
221
238
|
def demodulize(path)
|
222
239
|
path = path.to_s
|
223
240
|
if i = path.rindex("::")
|
224
|
-
path[(i + 2)
|
241
|
+
path[(i + 2), path.length]
|
225
242
|
else
|
226
243
|
path
|
227
244
|
end
|
@@ -270,38 +287,7 @@ module ActiveSupport
|
|
270
287
|
# NameError is raised when the name is not in CamelCase or the constant is
|
271
288
|
# unknown.
|
272
289
|
def constantize(camel_cased_word)
|
273
|
-
|
274
|
-
Object.const_get(camel_cased_word)
|
275
|
-
else
|
276
|
-
names = camel_cased_word.split("::")
|
277
|
-
|
278
|
-
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
279
|
-
Object.const_get(camel_cased_word) if names.empty?
|
280
|
-
|
281
|
-
# Remove the first blank element in case of '::ClassName' notation.
|
282
|
-
names.shift if names.size > 1 && names.first.empty?
|
283
|
-
|
284
|
-
names.inject(Object) do |constant, name|
|
285
|
-
if constant == Object
|
286
|
-
constant.const_get(name)
|
287
|
-
else
|
288
|
-
candidate = constant.const_get(name)
|
289
|
-
next candidate if constant.const_defined?(name, false)
|
290
|
-
next candidate unless Object.const_defined?(name)
|
291
|
-
|
292
|
-
# Go down the ancestors to check if it is owned directly. The check
|
293
|
-
# stops when we reach Object or the end of ancestors tree.
|
294
|
-
constant = constant.ancestors.inject(constant) do |const, ancestor|
|
295
|
-
break const if ancestor == Object
|
296
|
-
break ancestor if ancestor.const_defined?(name, false)
|
297
|
-
const
|
298
|
-
end
|
299
|
-
|
300
|
-
# owner is in Object, so raise
|
301
|
-
constant.const_get(name, false)
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
290
|
+
Object.const_get(camel_cased_word)
|
305
291
|
end
|
306
292
|
|
307
293
|
# Tries to find a constant with the name specified in the argument string.
|
@@ -371,7 +357,7 @@ module ActiveSupport
|
|
371
357
|
def const_regexp(camel_cased_word)
|
372
358
|
parts = camel_cased_word.split("::")
|
373
359
|
|
374
|
-
return Regexp.escape(camel_cased_word) if parts.
|
360
|
+
return Regexp.escape(camel_cased_word) if parts.empty?
|
375
361
|
|
376
362
|
last = parts.pop
|
377
363
|
|
@@ -385,8 +371,8 @@ module ActiveSupport
|
|
385
371
|
# If passed an optional +locale+ parameter, the uncountables will be
|
386
372
|
# found for that locale.
|
387
373
|
#
|
388
|
-
#
|
389
|
-
#
|
374
|
+
# apply_inflections('post', inflections.plurals, :en) # => "posts"
|
375
|
+
# apply_inflections('posts', inflections.singulars, :en) # => "post"
|
390
376
|
def apply_inflections(word, rules, locale = :en)
|
391
377
|
result = word.to_s.dup
|
392
378
|
|
@@ -59,13 +59,15 @@ module ActiveSupport
|
|
59
59
|
# transliterate('Jürgen', locale: :de)
|
60
60
|
# # => "Juergen"
|
61
61
|
#
|
62
|
-
# Transliteration is restricted to UTF-8, US-ASCII and GB18030 strings
|
62
|
+
# Transliteration is restricted to UTF-8, US-ASCII, and GB18030 strings.
|
63
63
|
# Other encodings will raise an ArgumentError.
|
64
64
|
def transliterate(string, replacement = "?", locale: nil)
|
65
|
-
string = string.dup if string.frozen?
|
66
65
|
raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
|
67
66
|
raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
|
68
67
|
|
68
|
+
return string.dup if string.ascii_only?
|
69
|
+
string = string.dup if string.frozen?
|
70
|
+
|
69
71
|
input_encoding = string.encoding
|
70
72
|
|
71
73
|
# US-ASCII is a subset of UTF-8 so we'll force encoding as UTF-8 if
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fiber"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
module IsolatedExecutionState # :nodoc:
|
7
|
+
@isolation_level = nil
|
8
|
+
|
9
|
+
Thread.attr_accessor :active_support_execution_state
|
10
|
+
Fiber.attr_accessor :active_support_execution_state
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :isolation_level, :scope
|
14
|
+
|
15
|
+
def isolation_level=(level)
|
16
|
+
return if level == @isolation_level
|
17
|
+
|
18
|
+
unless %i(thread fiber).include?(level)
|
19
|
+
raise ArgumentError, "isolation_level must be `:thread` or `:fiber`, got: `#{level.inspect}`"
|
20
|
+
end
|
21
|
+
|
22
|
+
clear if @isolation_level
|
23
|
+
|
24
|
+
@scope =
|
25
|
+
case level
|
26
|
+
when :thread; Thread
|
27
|
+
when :fiber; Fiber
|
28
|
+
end
|
29
|
+
|
30
|
+
@isolation_level = level
|
31
|
+
end
|
32
|
+
|
33
|
+
def unique_id
|
34
|
+
self[:__id__] ||= Object.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def [](key)
|
38
|
+
state[key]
|
39
|
+
end
|
40
|
+
|
41
|
+
def []=(key, value)
|
42
|
+
state[key] = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def key?(key)
|
46
|
+
state.key?(key)
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete(key)
|
50
|
+
state.delete(key)
|
51
|
+
end
|
52
|
+
|
53
|
+
def clear
|
54
|
+
state.clear
|
55
|
+
end
|
56
|
+
|
57
|
+
def context
|
58
|
+
scope.current
|
59
|
+
end
|
60
|
+
|
61
|
+
def share_with(other)
|
62
|
+
# Action Controller streaming spawns a new thread and copy thread locals.
|
63
|
+
# We do the same here for backward compatibility, but this is very much a hack
|
64
|
+
# and streaming should be rethought.
|
65
|
+
context.active_support_execution_state = other.active_support_execution_state.dup
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def state
|
70
|
+
context.active_support_execution_state ||= {}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
self.isolation_level = :thread
|
75
|
+
end
|
76
|
+
end
|