activesupport 6.0.3.7 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +220 -533
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +18 -11
- data/lib/active_support/cache/mem_cache_store.rb +143 -37
- data/lib/active_support/cache/memory_store.rb +56 -28
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +63 -88
- data/lib/active_support/cache/strategy/local_cache.rb +46 -57
- data/lib/active_support/cache.rb +273 -82
- data/lib/active_support/callbacks.rb +226 -118
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +49 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +9 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +9 -7
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +21 -40
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +4 -4
- data/lib/active_support/core_ext/date/conversions.rb +5 -4
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +139 -15
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/conversions.rb +2 -2
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/except.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +2 -2
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +40 -36
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +79 -72
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +42 -26
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +39 -5
- data/lib/active_support/core_ext/string/inquiry.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +69 -45
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +26 -6
- data/lib/active_support/core_ext/time/conversions.rb +6 -3
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +4 -19
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -23
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +39 -16
- 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 -764
- data/lib/active_support/deprecation/behaviors.rb +19 -3
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +6 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +177 -64
- 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 +24 -10
- data/lib/active_support/duration.rb +134 -55
- data/lib/active_support/encrypted_configuration.rb +11 -1
- data/lib/active_support/encrypted_file.rb +20 -3
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +70 -134
- 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 +30 -4
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +51 -25
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +24 -9
- data/lib/active_support/inflector/methods.rb +29 -49
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/isolated_execution_state.rb +56 -0
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +8 -4
- data/lib/active_support/key_generator.rb +19 -2
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber.rb +21 -3
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -21
- data/lib/active_support/message_encryptor.rb +12 -10
- data/lib/active_support/message_verifier.rb +50 -18
- data/lib/active_support/messages/metadata.rb +11 -3
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +13 -52
- data/lib/active_support/multibyte/unicode.rb +1 -87
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +110 -69
- data/lib/active_support/notifications/instrumenter.rb +37 -29
- data/lib/active_support/notifications.rb +47 -26
- data/lib/active_support/number_helper/number_converter.rb +2 -4
- data/lib/active_support/number_helper/number_to_currency_converter.rb +10 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +29 -16
- data/lib/active_support/option_merger.rb +9 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +21 -11
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/rescuable.rb +6 -6
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +2 -2
- data/lib/active_support/subscriber.rb +19 -25
- data/lib/active_support/tagged_logging.rb +31 -6
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +49 -12
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +53 -5
- data/lib/active_support/time_with_zone.rb +120 -55
- data/lib/active_support/values/time_zone.rb +49 -18
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- 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 +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +29 -1
- metadata +46 -45
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -10,56 +10,36 @@ module ActiveSupport
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def round(number)
|
13
|
+
precision = absolute_precision(number)
|
13
14
|
return number unless precision
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
else
|
18
|
-
round_without_significant(number)
|
19
|
-
end
|
15
|
+
|
16
|
+
rounded_number = convert_to_decimal(number).round(precision, options.fetch(:round_mode, :default).to_sym)
|
17
|
+
rounded_number.zero? ? rounded_number.abs : rounded_number # prevent showing negative zeros
|
20
18
|
end
|
21
19
|
|
22
20
|
def digit_count(number)
|
23
21
|
return 1 if number.zero?
|
24
|
-
(Math.log10(
|
22
|
+
(Math.log10(number.abs) + 1).floor
|
25
23
|
end
|
26
24
|
|
27
25
|
private
|
28
|
-
def round_without_significant(number)
|
29
|
-
number = number.round(precision)
|
30
|
-
number = number.to_i if precision == 0 && number.finite?
|
31
|
-
number = number.abs if number.zero? # prevent showing negative zeros
|
32
|
-
number
|
33
|
-
end
|
34
|
-
|
35
|
-
def round_significant(number)
|
36
|
-
return 0 if number.zero?
|
37
|
-
digits = digit_count(number)
|
38
|
-
multiplier = 10**(digits - precision)
|
39
|
-
(number / BigDecimal(multiplier.to_f.to_s)).round * multiplier
|
40
|
-
end
|
41
|
-
|
42
26
|
def convert_to_decimal(number)
|
43
27
|
case number
|
44
28
|
when Float, String
|
45
29
|
BigDecimal(number.to_s)
|
46
30
|
when Rational
|
47
|
-
BigDecimal(number, digit_count(number.to_i) + precision)
|
31
|
+
BigDecimal(number, digit_count(number.to_i) + options[:precision])
|
48
32
|
else
|
49
33
|
number.to_d
|
50
34
|
end
|
51
35
|
end
|
52
36
|
|
53
|
-
def
|
54
|
-
options[:precision]
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
def absolute_number(number)
|
62
|
-
number.respond_to?(:abs) ? number.abs : number.to_d.abs
|
37
|
+
def absolute_precision(number)
|
38
|
+
if options[:significant] && options[:precision] > 0
|
39
|
+
options[:precision] - digit_count(convert_to_decimal(number))
|
40
|
+
else
|
41
|
+
options[:precision]
|
42
|
+
end
|
63
43
|
end
|
64
44
|
end
|
65
45
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/dependencies/autoload"
|
4
|
-
|
5
3
|
module ActiveSupport
|
6
4
|
module NumberHelper
|
7
5
|
extend ActiveSupport::Autoload
|
@@ -73,6 +71,8 @@ module ActiveSupport
|
|
73
71
|
# (defaults to current locale).
|
74
72
|
# * <tt>:precision</tt> - Sets the level of precision (defaults
|
75
73
|
# to 2).
|
74
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
75
|
+
# (defaults to :default. See BigDecimal::mode)
|
76
76
|
# * <tt>:unit</tt> - Sets the denomination of the currency
|
77
77
|
# (defaults to "$").
|
78
78
|
# * <tt>:separator</tt> - Sets the separator between the units
|
@@ -99,8 +99,6 @@ module ActiveSupport
|
|
99
99
|
# number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
|
100
100
|
# number_to_currency('123a456') # => "$123a456"
|
101
101
|
#
|
102
|
-
# number_to_currency("123a456", raise: true) # => InvalidNumberError
|
103
|
-
#
|
104
102
|
# number_to_currency(-0.456789, precision: 0)
|
105
103
|
# # => "$0"
|
106
104
|
# number_to_currency(-1234567890.50, negative_format: '(%u%n)')
|
@@ -111,6 +109,8 @@ module ActiveSupport
|
|
111
109
|
# # => "1234567890,50 £"
|
112
110
|
# number_to_currency(1234567890.50, strip_insignificant_zeros: true)
|
113
111
|
# # => "$1,234,567,890.5"
|
112
|
+
# number_to_currency(1234567890.50, precision: 0, round_mode: :up)
|
113
|
+
# # => "$1,234,567,891"
|
114
114
|
def number_to_currency(number, options = {})
|
115
115
|
NumberToCurrencyConverter.convert(number, options)
|
116
116
|
end
|
@@ -124,6 +124,8 @@ module ActiveSupport
|
|
124
124
|
# (defaults to current locale).
|
125
125
|
# * <tt>:precision</tt> - Sets the precision of the number
|
126
126
|
# (defaults to 3). Keeps the number's precision if +nil+.
|
127
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
128
|
+
# (defaults to :default. See BigDecimal::mode)
|
127
129
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
128
130
|
# of significant_digits. If +false+, the number of fractional
|
129
131
|
# digits (defaults to +false+).
|
@@ -139,15 +141,16 @@ module ActiveSupport
|
|
139
141
|
#
|
140
142
|
# ==== Examples
|
141
143
|
#
|
142
|
-
# number_to_percentage(100)
|
143
|
-
# number_to_percentage('98')
|
144
|
-
# number_to_percentage(100, precision: 0)
|
145
|
-
# number_to_percentage(1000, delimiter: '.', separator: ',')
|
146
|
-
# number_to_percentage(302.24398923423, precision: 5)
|
147
|
-
# number_to_percentage(1000, locale: :fr)
|
148
|
-
# number_to_percentage(1000, precision: nil)
|
149
|
-
# number_to_percentage('98a')
|
150
|
-
# number_to_percentage(100, format: '%n %')
|
144
|
+
# number_to_percentage(100) # => "100.000%"
|
145
|
+
# number_to_percentage('98') # => "98.000%"
|
146
|
+
# number_to_percentage(100, precision: 0) # => "100%"
|
147
|
+
# number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
|
148
|
+
# number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
|
149
|
+
# number_to_percentage(1000, locale: :fr) # => "1000,000%"
|
150
|
+
# number_to_percentage(1000, precision: nil) # => "1000%"
|
151
|
+
# number_to_percentage('98a') # => "98a%"
|
152
|
+
# number_to_percentage(100, format: '%n %') # => "100.000 %"
|
153
|
+
# number_to_percentage(302.24398923423, precision: 5, round_mode: :down) # => "302.24398%"
|
151
154
|
def number_to_percentage(number, options = {})
|
152
155
|
NumberToPercentageConverter.convert(number, options)
|
153
156
|
end
|
@@ -198,6 +201,8 @@ module ActiveSupport
|
|
198
201
|
# (defaults to current locale).
|
199
202
|
# * <tt>:precision</tt> - Sets the precision of the number
|
200
203
|
# (defaults to 3). Keeps the number's precision if +nil+.
|
204
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
205
|
+
# (defaults to :default. See BigDecimal::mode)
|
201
206
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
202
207
|
# of significant_digits. If +false+, the number of fractional
|
203
208
|
# digits (defaults to +false+).
|
@@ -219,6 +224,7 @@ module ActiveSupport
|
|
219
224
|
# number_to_rounded(111.2345, precision: 1, significant: true) # => "100"
|
220
225
|
# number_to_rounded(13, precision: 5, significant: true) # => "13.000"
|
221
226
|
# number_to_rounded(13, precision: nil) # => "13"
|
227
|
+
# number_to_rounded(389.32314, precision: 0, round_mode: :up) # => "390"
|
222
228
|
# number_to_rounded(111.234, locale: :fr) # => "111,234"
|
223
229
|
#
|
224
230
|
# number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true)
|
@@ -232,7 +238,7 @@ module ActiveSupport
|
|
232
238
|
end
|
233
239
|
|
234
240
|
# Formats the bytes in +number+ into a more understandable
|
235
|
-
# representation (e.g., giving it 1500 yields 1.
|
241
|
+
# representation (e.g., giving it 1500 yields 1.46 KB). This
|
236
242
|
# method is useful for reporting file sizes to users. You can
|
237
243
|
# customize the format in the +options+ hash.
|
238
244
|
#
|
@@ -245,6 +251,8 @@ module ActiveSupport
|
|
245
251
|
# (defaults to current locale).
|
246
252
|
# * <tt>:precision</tt> - Sets the precision of the number
|
247
253
|
# (defaults to 3).
|
254
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
255
|
+
# (defaults to :default. See BigDecimal::mode)
|
248
256
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
249
257
|
# of significant_digits. If +false+, the number of fractional
|
250
258
|
# digits (defaults to +true+)
|
@@ -268,6 +276,7 @@ module ActiveSupport
|
|
268
276
|
# number_to_human_size(1234567890123456789) # => "1.07 EB"
|
269
277
|
# number_to_human_size(1234567, precision: 2) # => "1.2 MB"
|
270
278
|
# number_to_human_size(483989, precision: 2) # => "470 KB"
|
279
|
+
# number_to_human_size(483989, precision: 2, round_mode: :up) # => "480 KB"
|
271
280
|
# number_to_human_size(1234567, precision: 2, separator: ',') # => "1,2 MB"
|
272
281
|
# number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
|
273
282
|
# number_to_human_size(524288000, precision: 5) # => "500 MB"
|
@@ -276,7 +285,7 @@ module ActiveSupport
|
|
276
285
|
end
|
277
286
|
|
278
287
|
# Pretty prints (formats and approximates) a number in a way it
|
279
|
-
# is more readable by humans (
|
288
|
+
# is more readable by humans (e.g.: 1200000000 becomes "1.2
|
280
289
|
# Billion"). This is useful for numbers that can get very large
|
281
290
|
# (and too hard to read).
|
282
291
|
#
|
@@ -284,7 +293,7 @@ module ActiveSupport
|
|
284
293
|
# size.
|
285
294
|
#
|
286
295
|
# You can also define your own unit-quantifier names if you want
|
287
|
-
# to use other decimal units (
|
296
|
+
# to use other decimal units (e.g.: 1500 becomes "1.5
|
288
297
|
# kilometers", 0.150 becomes "150 milliliters", etc). You may
|
289
298
|
# define a wide range of unit quantifiers, even fractional ones
|
290
299
|
# (centi, deci, mili, etc).
|
@@ -295,6 +304,8 @@ module ActiveSupport
|
|
295
304
|
# (defaults to current locale).
|
296
305
|
# * <tt>:precision</tt> - Sets the precision of the number
|
297
306
|
# (defaults to 3).
|
307
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
308
|
+
# (defaults to :default. See BigDecimal::mode)
|
298
309
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
299
310
|
# of significant_digits. If +false+, the number of fractional
|
300
311
|
# digits (defaults to +true+)
|
@@ -332,6 +343,8 @@ module ActiveSupport
|
|
332
343
|
# number_to_human(1234567890123456789) # => "1230 Quadrillion"
|
333
344
|
# number_to_human(489939, precision: 2) # => "490 Thousand"
|
334
345
|
# number_to_human(489939, precision: 4) # => "489.9 Thousand"
|
346
|
+
# number_to_human(489939, precision: 2
|
347
|
+
# , round_mode: :down) # => "480 Thousand"
|
335
348
|
# number_to_human(1234567, precision: 4,
|
336
349
|
# significant: false) # => "1.2346 Million"
|
337
350
|
# number_to_human(1234567, precision: 1,
|
@@ -3,9 +3,9 @@
|
|
3
3
|
require "active_support/core_ext/hash/deep_merge"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
class OptionMerger
|
6
|
+
class OptionMerger # :nodoc:
|
7
7
|
instance_methods.each do |method|
|
8
|
-
undef_method(method)
|
8
|
+
undef_method(method) unless method.start_with?("__", "instance_eval", "class", "object_id")
|
9
9
|
end
|
10
10
|
|
11
11
|
def initialize(context, options)
|
@@ -24,22 +24,15 @@ module ActiveSupport
|
|
24
24
|
options = @options
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if RUBY_VERSION >= "2.7"
|
31
|
-
def invoke_method(method, arguments, options, &block)
|
32
|
-
if options
|
33
|
-
@context.__send__(method, *arguments, **options, &block)
|
34
|
-
else
|
35
|
-
@context.__send__(method, *arguments, &block)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
else
|
39
|
-
def invoke_method(method, arguments, options, &block)
|
40
|
-
arguments << options if options
|
27
|
+
if options
|
28
|
+
@context.__send__(method, *arguments, **options, &block)
|
29
|
+
else
|
41
30
|
@context.__send__(method, *arguments, &block)
|
42
31
|
end
|
43
32
|
end
|
33
|
+
|
34
|
+
def respond_to_missing?(*arguments)
|
35
|
+
@context.respond_to?(*arguments)
|
36
|
+
end
|
44
37
|
end
|
45
38
|
end
|
@@ -21,7 +21,7 @@ module ActiveSupport
|
|
21
21
|
#
|
22
22
|
# <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
|
23
23
|
# with other implementations.
|
24
|
-
class OrderedHash < ::Hash
|
24
|
+
class OrderedHash < ::Hash # :nodoc:
|
25
25
|
def to_yaml_type
|
26
26
|
"!tag:yaml.org,2002:omap"
|
27
27
|
end
|
@@ -3,7 +3,9 @@
|
|
3
3
|
require "active_support/core_ext/object/blank"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
#
|
6
|
+
# +OrderedOptions+ inherits from +Hash+ and provides dynamic accessor methods.
|
7
|
+
#
|
8
|
+
# With a +Hash+, key-value pairs are typically managed like this:
|
7
9
|
#
|
8
10
|
# h = {}
|
9
11
|
# h[:boy] = 'John'
|
@@ -12,7 +14,7 @@ module ActiveSupport
|
|
12
14
|
# h[:girl] # => 'Mary'
|
13
15
|
# h[:dog] # => nil
|
14
16
|
#
|
15
|
-
# Using +OrderedOptions+, the above code
|
17
|
+
# Using +OrderedOptions+, the above code can be written as:
|
16
18
|
#
|
17
19
|
# h = ActiveSupport::OrderedOptions.new
|
18
20
|
# h.boy = 'John'
|
@@ -60,6 +62,10 @@ module ActiveSupport
|
|
60
62
|
def extractable_options?
|
61
63
|
true
|
62
64
|
end
|
65
|
+
|
66
|
+
def inspect
|
67
|
+
"#<#{self.class.name} #{super}>"
|
68
|
+
end
|
63
69
|
end
|
64
70
|
|
65
71
|
# +InheritableOptions+ provides a constructor to build an +OrderedOptions+
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/duplicable"
|
4
|
-
require "active_support/core_ext/array/extract"
|
5
4
|
|
6
5
|
module ActiveSupport
|
7
6
|
# +ParameterFilter+ allows you to specify keys for sensitive data from
|
@@ -17,12 +16,17 @@ module ActiveSupport
|
|
17
16
|
# ActiveSupport::ParameterFilter.new([:foo, "bar"])
|
18
17
|
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
19
18
|
#
|
19
|
+
# ActiveSupport::ParameterFilter.new([/\Apin\z/i, /\Apin_/i])
|
20
|
+
# => replaces the value for the exact (case-insensitive) key 'pin' and all
|
21
|
+
# (case-insensitive) keys beginning with 'pin_', with "[FILTERED]".
|
22
|
+
# Does not match keys with 'pin' as a substring, such as 'shipping_id'.
|
23
|
+
#
|
20
24
|
# ActiveSupport::ParameterFilter.new(["credit_card.code"])
|
21
25
|
# => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
|
22
26
|
# change { file: { code: "xxxx"} }
|
23
27
|
#
|
24
28
|
# ActiveSupport::ParameterFilter.new([-> (k, v) do
|
25
|
-
# v.reverse! if
|
29
|
+
# v.reverse! if /secret/i.match?(k)
|
26
30
|
# end])
|
27
31
|
# => reverses the value to all keys matching /secret/i
|
28
32
|
class ParameterFilter
|
@@ -34,7 +38,7 @@ module ActiveSupport
|
|
34
38
|
#
|
35
39
|
# ==== Options
|
36
40
|
#
|
37
|
-
# * <tt>:mask</tt> - A replaced object when filtered. Defaults to
|
41
|
+
# * <tt>:mask</tt> - A replaced object when filtered. Defaults to <tt>"[FILTERED]"</tt>.
|
38
42
|
def initialize(filters = [], mask: FILTERED)
|
39
43
|
@filters = filters
|
40
44
|
@mask = mask
|
@@ -59,24 +63,30 @@ module ActiveSupport
|
|
59
63
|
def self.compile(filters, mask:)
|
60
64
|
return lambda { |params| params.dup } if filters.empty?
|
61
65
|
|
62
|
-
strings, regexps, blocks = [], [], []
|
66
|
+
strings, regexps, blocks, deep_regexps, deep_strings = [], [], [], nil, nil
|
63
67
|
|
64
68
|
filters.each do |item|
|
65
69
|
case item
|
66
70
|
when Proc
|
67
71
|
blocks << item
|
68
72
|
when Regexp
|
69
|
-
|
73
|
+
if item.to_s.include?("\\.")
|
74
|
+
(deep_regexps ||= []) << item
|
75
|
+
else
|
76
|
+
regexps << item
|
77
|
+
end
|
70
78
|
else
|
71
|
-
|
79
|
+
s = Regexp.escape(item.to_s)
|
80
|
+
if s.include?("\\.")
|
81
|
+
(deep_strings ||= []) << s
|
82
|
+
else
|
83
|
+
strings << s
|
84
|
+
end
|
72
85
|
end
|
73
86
|
end
|
74
87
|
|
75
|
-
deep_regexps = regexps.extract! { |r| r.to_s.include?("\\.") }
|
76
|
-
deep_strings = strings.extract! { |s| s.include?("\\.") }
|
77
|
-
|
78
88
|
regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
|
79
|
-
deep_regexps << Regexp.new(deep_strings.join("|"), true)
|
89
|
+
(deep_regexps ||= []) << Regexp.new(deep_strings.join("|"), true) if deep_strings&.any?
|
80
90
|
|
81
91
|
new regexps, deep_regexps, blocks, mask: mask
|
82
92
|
end
|
@@ -85,7 +95,7 @@ module ActiveSupport
|
|
85
95
|
|
86
96
|
def initialize(regexps, deep_regexps, blocks, mask:)
|
87
97
|
@regexps = regexps
|
88
|
-
@deep_regexps = deep_regexps
|
98
|
+
@deep_regexps = deep_regexps&.any? ? deep_regexps : nil
|
89
99
|
@blocks = blocks
|
90
100
|
@mask = mask
|
91
101
|
end
|
@@ -40,7 +40,11 @@ module ActiveSupport
|
|
40
40
|
# If the class has an initializer, it must accept no arguments.
|
41
41
|
module PerThreadRegistry
|
42
42
|
def self.extended(object)
|
43
|
-
|
43
|
+
ActiveSupport::Deprecation.warn(<<~MSG)
|
44
|
+
ActiveSupport::PerThreadRegistry is deprecated and will be removed in Rails 7.1.
|
45
|
+
Use `Module#thread_mattr_accessor` instead.
|
46
|
+
MSG
|
47
|
+
object.instance_variable_set :@per_thread_registry_key, object.name.freeze
|
44
48
|
end
|
45
49
|
|
46
50
|
def instance
|
@@ -56,5 +60,6 @@ module ActiveSupport
|
|
56
60
|
|
57
61
|
send(name, *args, &block)
|
58
62
|
end
|
63
|
+
ruby2_keywords(:method_missing)
|
59
64
|
end
|
60
65
|
end
|
data/lib/active_support/rails.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# This is private interface.
|
3
|
+
# This is a private interface.
|
4
4
|
#
|
5
5
|
# Rails components cherry pick from Active Support as needed, but there are a
|
6
6
|
# few features that are used for sure in some way or another and it is not worth
|
@@ -13,9 +13,6 @@
|
|
13
13
|
# Defines Object#blank? and Object#present?.
|
14
14
|
require "active_support/core_ext/object/blank"
|
15
15
|
|
16
|
-
# Rails own autoload, eager_load, etc.
|
17
|
-
require "active_support/dependencies/autoload"
|
18
|
-
|
19
16
|
# Support for ClassMethods and the included macro.
|
20
17
|
require "active_support/concern"
|
21
18
|
|
@@ -6,9 +6,25 @@ require "active_support/i18n_railtie"
|
|
6
6
|
module ActiveSupport
|
7
7
|
class Railtie < Rails::Railtie # :nodoc:
|
8
8
|
config.active_support = ActiveSupport::OrderedOptions.new
|
9
|
+
config.active_support.disable_to_s_conversion = false
|
9
10
|
|
10
11
|
config.eager_load_namespaces << ActiveSupport
|
11
12
|
|
13
|
+
initializer "active_support.isolation_level" do |app|
|
14
|
+
if level = app.config.active_support.delete(:isolation_level)
|
15
|
+
ActiveSupport::IsolatedExecutionState.isolation_level = level
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
initializer "active_support.remove_deprecated_time_with_zone_name" do |app|
|
20
|
+
config.after_initialize do
|
21
|
+
if app.config.active_support.remove_deprecated_time_with_zone_name
|
22
|
+
require "active_support/time_with_zone"
|
23
|
+
TimeWithZone.singleton_class.remove_method(:name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
12
28
|
initializer "active_support.set_authenticated_message_encryption" do |app|
|
13
29
|
config.after_initialize do
|
14
30
|
unless app.config.active_support.use_authenticated_message_encryption.nil?
|
@@ -18,15 +34,50 @@ module ActiveSupport
|
|
18
34
|
end
|
19
35
|
end
|
20
36
|
|
37
|
+
initializer "active_support.reset_execution_context" do |app|
|
38
|
+
app.reloader.before_class_unload { ActiveSupport::ExecutionContext.clear }
|
39
|
+
app.executor.to_run { ActiveSupport::ExecutionContext.clear }
|
40
|
+
app.executor.to_complete { ActiveSupport::ExecutionContext.clear }
|
41
|
+
end
|
42
|
+
|
21
43
|
initializer "active_support.reset_all_current_attributes_instances" do |app|
|
44
|
+
executor_around_test_case = app.config.active_support.executor_around_test_case
|
45
|
+
|
22
46
|
app.reloader.before_class_unload { ActiveSupport::CurrentAttributes.clear_all }
|
23
47
|
app.executor.to_run { ActiveSupport::CurrentAttributes.reset_all }
|
24
48
|
app.executor.to_complete { ActiveSupport::CurrentAttributes.reset_all }
|
49
|
+
|
50
|
+
ActiveSupport.on_load(:active_support_test_case) do
|
51
|
+
if executor_around_test_case
|
52
|
+
require "active_support/executor/test_helper"
|
53
|
+
include ActiveSupport::Executor::TestHelper
|
54
|
+
else
|
55
|
+
require "active_support/current_attributes/test_helper"
|
56
|
+
include ActiveSupport::CurrentAttributes::TestHelper
|
57
|
+
|
58
|
+
require "active_support/execution_context/test_helper"
|
59
|
+
include ActiveSupport::ExecutionContext::TestHelper
|
60
|
+
end
|
61
|
+
end
|
25
62
|
end
|
26
63
|
|
27
64
|
initializer "active_support.deprecation_behavior" do |app|
|
28
|
-
if
|
29
|
-
ActiveSupport::Deprecation.
|
65
|
+
if app.config.active_support.report_deprecations == false
|
66
|
+
ActiveSupport::Deprecation.silenced = true
|
67
|
+
ActiveSupport::Deprecation.behavior = :silence
|
68
|
+
ActiveSupport::Deprecation.disallowed_behavior = :silence
|
69
|
+
else
|
70
|
+
if deprecation = app.config.active_support.deprecation
|
71
|
+
ActiveSupport::Deprecation.behavior = deprecation
|
72
|
+
end
|
73
|
+
|
74
|
+
if disallowed_deprecation = app.config.active_support.disallowed_deprecation
|
75
|
+
ActiveSupport::Deprecation.disallowed_behavior = disallowed_deprecation
|
76
|
+
end
|
77
|
+
|
78
|
+
if disallowed_warnings = app.config.active_support.disallowed_deprecation_warnings
|
79
|
+
ActiveSupport::Deprecation.disallowed_warnings = disallowed_warnings
|
80
|
+
end
|
30
81
|
end
|
31
82
|
end
|
32
83
|
|
@@ -62,17 +113,38 @@ module ActiveSupport
|
|
62
113
|
end
|
63
114
|
end
|
64
115
|
|
116
|
+
initializer "active_support.set_error_reporter" do |app|
|
117
|
+
ActiveSupport.error_reporter = app.executor.error_reporter
|
118
|
+
end
|
119
|
+
|
65
120
|
initializer "active_support.set_configs" do |app|
|
66
121
|
app.config.active_support.each do |k, v|
|
67
122
|
k = "#{k}="
|
68
|
-
ActiveSupport.
|
123
|
+
ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
|
69
124
|
end
|
70
125
|
end
|
71
126
|
|
72
127
|
initializer "active_support.set_hash_digest_class" do |app|
|
73
128
|
config.after_initialize do
|
74
|
-
if app.config.active_support.
|
75
|
-
ActiveSupport::Digest.hash_digest_class =
|
129
|
+
if klass = app.config.active_support.hash_digest_class
|
130
|
+
ActiveSupport::Digest.hash_digest_class = klass
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
initializer "active_support.set_key_generator_hash_digest_class" do |app|
|
136
|
+
config.after_initialize do
|
137
|
+
if klass = app.config.active_support.key_generator_hash_digest_class
|
138
|
+
ActiveSupport::KeyGenerator.hash_digest_class = klass
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
initializer "active_support.set_rfc4122_namespaced_uuids" do |app|
|
144
|
+
config.after_initialize do
|
145
|
+
if app.config.active_support.use_rfc4122_namespaced_uuids
|
146
|
+
require "active_support/core_ext/digest"
|
147
|
+
::Digest::UUID.use_rfc4122_namespaced_uuids = app.config.active_support.use_rfc4122_namespaced_uuids
|
76
148
|
end
|
77
149
|
end
|
78
150
|
end
|
@@ -14,12 +14,12 @@ module ActiveSupport
|
|
14
14
|
end
|
15
15
|
|
16
16
|
module ClassMethods
|
17
|
-
#
|
17
|
+
# Registers exception classes with a handler to be called by <tt>rescue_with_handler</tt>.
|
18
18
|
#
|
19
19
|
# <tt>rescue_from</tt> receives a series of exception classes or class
|
20
|
-
# names, and a trailing <tt>:with</tt>
|
21
|
-
#
|
22
|
-
# be given.
|
20
|
+
# names, and an exception handler specified by a trailing <tt>:with</tt>
|
21
|
+
# option containing the name of a method or a Proc object. Alternatively, a block
|
22
|
+
# can be given as the handler.
|
23
23
|
#
|
24
24
|
# Handlers that take one argument will be called with the exception, so
|
25
25
|
# that the exception can be inspected when dealing with it.
|
@@ -100,7 +100,7 @@ module ActiveSupport
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
def handler_for_rescue(exception, object: self)
|
103
|
+
def handler_for_rescue(exception, object: self) # :nodoc:
|
104
104
|
case rescuer = find_rescue_handler(exception)
|
105
105
|
when Symbol
|
106
106
|
method = object.method(rescuer)
|
@@ -167,7 +167,7 @@ module ActiveSupport
|
|
167
167
|
|
168
168
|
# Internal handler lookup. Delegates to class method. Some libraries call
|
169
169
|
# this directly, so keeping it around for compatibility.
|
170
|
-
def handler_for_rescue(exception)
|
170
|
+
def handler_for_rescue(exception) # :nodoc:
|
171
171
|
self.class.handler_for_rescue exception, object: self
|
172
172
|
end
|
173
173
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/security_utils"
|
4
|
+
require "active_support/messages/rotator"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
# The ActiveSupport::SecureCompareRotator is a wrapper around +ActiveSupport::SecurityUtils.secure_compare+
|
8
|
+
# and allows you to rotate a previously defined value to a new one.
|
9
|
+
#
|
10
|
+
# It can be used as follow:
|
11
|
+
#
|
12
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
|
13
|
+
# rotator.rotate('previous_production_value')
|
14
|
+
# rotator.secure_compare!('previous_production_value')
|
15
|
+
#
|
16
|
+
# One real use case example would be to rotate a basic auth credentials:
|
17
|
+
#
|
18
|
+
# class MyController < ApplicationController
|
19
|
+
# def authenticate_request
|
20
|
+
# rotator = ActiveSupport::SecureCompareRotator.new('new_password')
|
21
|
+
# rotator.rotate('old_password')
|
22
|
+
#
|
23
|
+
# authenticate_or_request_with_http_basic do |username, password|
|
24
|
+
# rotator.secure_compare!(password)
|
25
|
+
# rescue ActiveSupport::SecureCompareRotator::InvalidMatch
|
26
|
+
# false
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
class SecureCompareRotator
|
31
|
+
include SecurityUtils
|
32
|
+
prepend Messages::Rotator
|
33
|
+
|
34
|
+
InvalidMatch = Class.new(StandardError)
|
35
|
+
|
36
|
+
def initialize(value, **_options)
|
37
|
+
@value = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def secure_compare!(other_value, on_rotation: @on_rotation)
|
41
|
+
secure_compare(@value, other_value) ||
|
42
|
+
run_rotations(on_rotation) { |wrapper| wrapper.secure_compare!(other_value) } ||
|
43
|
+
raise(InvalidMatch)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def build_rotation(previous_value, _options)
|
48
|
+
self.class.new(previous_value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|