activesupport 6.0.6.1 → 6.1.7.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +441 -455
- data/MIT-LICENSE +1 -1
- data/lib/active_support/array_inquirer.rb +4 -2
- data/lib/active_support/backtrace_cleaner.rb +3 -3
- data/lib/active_support/benchmarkable.rb +1 -1
- data/lib/active_support/cache/file_store.rb +3 -3
- data/lib/active_support/cache/mem_cache_store.rb +28 -18
- data/lib/active_support/cache/memory_store.rb +46 -26
- data/lib/active_support/cache/redis_cache_store.rb +25 -25
- data/lib/active_support/cache/strategy/local_cache.rb +20 -5
- data/lib/active_support/cache.rb +87 -40
- data/lib/active_support/callbacks.rb +65 -56
- data/lib/active_support/concern.rb +46 -2
- data/lib/active_support/configurable.rb +3 -3
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +17 -38
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- 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/digest/uuid.rb +1 -0
- data/lib/active_support/core_ext/enumerable.rb +76 -4
- 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/keys.rb +1 -1
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/marshal.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +38 -28
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +29 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/json.rb +12 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/range/compare_range.rb +9 -3
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
- 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/inflections.rb +38 -4
- 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 +7 -4
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +19 -0
- data/lib/active_support/core_ext/time/conversions.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +5 -1
- data/lib/active_support/core_ext.rb +1 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +9 -2
- data/lib/active_support/dependencies/zeitwerk_integration.rb +4 -1
- data/lib/active_support/dependencies.rb +37 -18
- data/lib/active_support/deprecation/behaviors.rb +15 -2
- 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 +3 -2
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +6 -1
- data/lib/active_support/descendants_tracker.rb +6 -2
- data/lib/active_support/digest.rb +2 -0
- data/lib/active_support/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/duration.rb +75 -25
- data/lib/active_support/encrypted_file.rb +27 -11
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +48 -24
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +1 -2
- data/lib/active_support/inflector/methods.rb +36 -33
- data/lib/active_support/inflector/transliterate.rb +4 -4
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +5 -1
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber.rb +8 -0
- 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 -12
- data/lib/active_support/message_encryptor.rb +4 -7
- data/lib/active_support/message_verifier.rb +5 -5
- 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 +4 -42
- data/lib/active_support/multibyte/unicode.rb +9 -83
- data/lib/active_support/notifications/fanout.rb +23 -8
- data/lib/active_support/notifications/instrumenter.rb +6 -15
- data/lib/active_support/notifications.rb +32 -5
- data/lib/active_support/number_helper/number_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 +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 -28
- data/lib/active_support/number_helper.rb +29 -14
- data/lib/active_support/option_merger.rb +2 -1
- data/lib/active_support/ordered_options.rb +8 -2
- data/lib/active_support/parameter_filter.rb +16 -11
- data/lib/active_support/per_thread_registry.rb +2 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/rescuable.rb +4 -4
- 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 +4 -2
- data/lib/active_support/subscriber.rb +12 -7
- data/lib/active_support/tagged_logging.rb +30 -5
- data/lib/active_support/testing/assertions.rb +18 -11
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +12 -95
- data/lib/active_support/testing/time_helpers.rb +40 -3
- data/lib/active_support/time_with_zone.rb +67 -43
- data/lib/active_support/values/time_zone.rb +22 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- data/lib/active_support.rb +13 -1
- metadata +34 -36
- 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/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
@@ -10,57 +10,41 @@ 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, BigDecimal.mode(BigDecimal::ROUND_MODE))
|
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]
|
37
|
+
def absolute_precision(number)
|
38
|
+
if significant && options[:precision] > 0
|
39
|
+
options[:precision] - digit_count(convert_to_decimal(number))
|
40
|
+
else
|
41
|
+
options[:precision]
|
42
|
+
end
|
55
43
|
end
|
56
44
|
|
57
45
|
def significant
|
58
46
|
options[:significant]
|
59
47
|
end
|
60
|
-
|
61
|
-
def absolute_number(number)
|
62
|
-
number.respond_to?(:abs) ? number.abs : number.to_d.abs
|
63
|
-
end
|
64
48
|
end
|
65
49
|
end
|
66
50
|
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
|
@@ -111,6 +111,8 @@ module ActiveSupport
|
|
111
111
|
# # => "1234567890,50 £"
|
112
112
|
# number_to_currency(1234567890.50, strip_insignificant_zeros: true)
|
113
113
|
# # => "$1,234,567,890.5"
|
114
|
+
# number_to_currency(1234567890.50, precision: 0, round_mode: :up)
|
115
|
+
# # => "$1,234,567,891"
|
114
116
|
def number_to_currency(number, options = {})
|
115
117
|
NumberToCurrencyConverter.convert(number, options)
|
116
118
|
end
|
@@ -124,6 +126,8 @@ module ActiveSupport
|
|
124
126
|
# (defaults to current locale).
|
125
127
|
# * <tt>:precision</tt> - Sets the precision of the number
|
126
128
|
# (defaults to 3). Keeps the number's precision if +nil+.
|
129
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
130
|
+
# (defaults to :default. See BigDecimal::mode)
|
127
131
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
128
132
|
# of significant_digits. If +false+, the number of fractional
|
129
133
|
# digits (defaults to +false+).
|
@@ -139,15 +143,16 @@ module ActiveSupport
|
|
139
143
|
#
|
140
144
|
# ==== Examples
|
141
145
|
#
|
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 %')
|
146
|
+
# number_to_percentage(100) # => "100.000%"
|
147
|
+
# number_to_percentage('98') # => "98.000%"
|
148
|
+
# number_to_percentage(100, precision: 0) # => "100%"
|
149
|
+
# number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
|
150
|
+
# number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
|
151
|
+
# number_to_percentage(1000, locale: :fr) # => "1000,000%"
|
152
|
+
# number_to_percentage(1000, precision: nil) # => "1000%"
|
153
|
+
# number_to_percentage('98a') # => "98a%"
|
154
|
+
# number_to_percentage(100, format: '%n %') # => "100.000 %"
|
155
|
+
# number_to_percentage(302.24398923423, precision: 5, round_mode: :down) # => "302.24398%"
|
151
156
|
def number_to_percentage(number, options = {})
|
152
157
|
NumberToPercentageConverter.convert(number, options)
|
153
158
|
end
|
@@ -198,6 +203,8 @@ module ActiveSupport
|
|
198
203
|
# (defaults to current locale).
|
199
204
|
# * <tt>:precision</tt> - Sets the precision of the number
|
200
205
|
# (defaults to 3). Keeps the number's precision if +nil+.
|
206
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
207
|
+
# (defaults to :default. See BigDecimal::mode)
|
201
208
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
202
209
|
# of significant_digits. If +false+, the number of fractional
|
203
210
|
# digits (defaults to +false+).
|
@@ -219,6 +226,7 @@ module ActiveSupport
|
|
219
226
|
# number_to_rounded(111.2345, precision: 1, significant: true) # => "100"
|
220
227
|
# number_to_rounded(13, precision: 5, significant: true) # => "13.000"
|
221
228
|
# number_to_rounded(13, precision: nil) # => "13"
|
229
|
+
# number_to_rounded(389.32314, precision: 0, round_mode: :up) # => "390"
|
222
230
|
# number_to_rounded(111.234, locale: :fr) # => "111,234"
|
223
231
|
#
|
224
232
|
# number_to_rounded(13, precision: 5, significant: true, strip_insignificant_zeros: true)
|
@@ -232,7 +240,7 @@ module ActiveSupport
|
|
232
240
|
end
|
233
241
|
|
234
242
|
# Formats the bytes in +number+ into a more understandable
|
235
|
-
# representation (e.g., giving it 1500 yields 1.
|
243
|
+
# representation (e.g., giving it 1500 yields 1.46 KB). This
|
236
244
|
# method is useful for reporting file sizes to users. You can
|
237
245
|
# customize the format in the +options+ hash.
|
238
246
|
#
|
@@ -245,6 +253,8 @@ module ActiveSupport
|
|
245
253
|
# (defaults to current locale).
|
246
254
|
# * <tt>:precision</tt> - Sets the precision of the number
|
247
255
|
# (defaults to 3).
|
256
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
257
|
+
# (defaults to :default. See BigDecimal::mode)
|
248
258
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
249
259
|
# of significant_digits. If +false+, the number of fractional
|
250
260
|
# digits (defaults to +true+)
|
@@ -268,6 +278,7 @@ module ActiveSupport
|
|
268
278
|
# number_to_human_size(1234567890123456789) # => "1.07 EB"
|
269
279
|
# number_to_human_size(1234567, precision: 2) # => "1.2 MB"
|
270
280
|
# number_to_human_size(483989, precision: 2) # => "470 KB"
|
281
|
+
# number_to_human_size(483989, precision: 2, round_mode: :up) # => "480 KB"
|
271
282
|
# number_to_human_size(1234567, precision: 2, separator: ',') # => "1,2 MB"
|
272
283
|
# number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
|
273
284
|
# number_to_human_size(524288000, precision: 5) # => "500 MB"
|
@@ -276,7 +287,7 @@ module ActiveSupport
|
|
276
287
|
end
|
277
288
|
|
278
289
|
# Pretty prints (formats and approximates) a number in a way it
|
279
|
-
# is more readable by humans (
|
290
|
+
# is more readable by humans (e.g.: 1200000000 becomes "1.2
|
280
291
|
# Billion"). This is useful for numbers that can get very large
|
281
292
|
# (and too hard to read).
|
282
293
|
#
|
@@ -284,7 +295,7 @@ module ActiveSupport
|
|
284
295
|
# size.
|
285
296
|
#
|
286
297
|
# You can also define your own unit-quantifier names if you want
|
287
|
-
# to use other decimal units (
|
298
|
+
# to use other decimal units (e.g.: 1500 becomes "1.5
|
288
299
|
# kilometers", 0.150 becomes "150 milliliters", etc). You may
|
289
300
|
# define a wide range of unit quantifiers, even fractional ones
|
290
301
|
# (centi, deci, mili, etc).
|
@@ -295,6 +306,8 @@ module ActiveSupport
|
|
295
306
|
# (defaults to current locale).
|
296
307
|
# * <tt>:precision</tt> - Sets the precision of the number
|
297
308
|
# (defaults to 3).
|
309
|
+
# * <tt>:round_mode</tt> - Determine how rounding is performed
|
310
|
+
# (defaults to :default. See BigDecimal::mode)
|
298
311
|
# * <tt>:significant</tt> - If +true+, precision will be the number
|
299
312
|
# of significant_digits. If +false+, the number of fractional
|
300
313
|
# digits (defaults to +true+)
|
@@ -332,6 +345,8 @@ module ActiveSupport
|
|
332
345
|
# number_to_human(1234567890123456789) # => "1230 Quadrillion"
|
333
346
|
# number_to_human(489939, precision: 2) # => "490 Thousand"
|
334
347
|
# number_to_human(489939, precision: 4) # => "489.9 Thousand"
|
348
|
+
# number_to_human(489939, precision: 2
|
349
|
+
# , round_mode: :down) # => "480 Thousand"
|
335
350
|
# number_to_human(1234567, precision: 4,
|
336
351
|
# significant: false) # => "1.2346 Million"
|
337
352
|
# number_to_human(1234567, precision: 1,
|
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/hash/deep_merge"
|
4
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
class OptionMerger #:nodoc:
|
7
8
|
instance_methods.each do |method|
|
8
|
-
undef_method(method)
|
9
|
+
undef_method(method) unless method.start_with?("__", "instance_eval", "class", "object_id")
|
9
10
|
end
|
10
11
|
|
11
12
|
def initialize(context, options)
|
@@ -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
|
@@ -22,7 +21,7 @@ module ActiveSupport
|
|
22
21
|
# change { file: { code: "xxxx"} }
|
23
22
|
#
|
24
23
|
# ActiveSupport::ParameterFilter.new([-> (k, v) do
|
25
|
-
# v.reverse! if
|
24
|
+
# v.reverse! if /secret/i.match?(k)
|
26
25
|
# end])
|
27
26
|
# => reverses the value to all keys matching /secret/i
|
28
27
|
class ParameterFilter
|
@@ -34,7 +33,7 @@ module ActiveSupport
|
|
34
33
|
#
|
35
34
|
# ==== Options
|
36
35
|
#
|
37
|
-
# * <tt>:mask</tt> - A replaced object when filtered. Defaults to
|
36
|
+
# * <tt>:mask</tt> - A replaced object when filtered. Defaults to <tt>"[FILTERED]"</tt>.
|
38
37
|
def initialize(filters = [], mask: FILTERED)
|
39
38
|
@filters = filters
|
40
39
|
@mask = mask
|
@@ -59,24 +58,30 @@ module ActiveSupport
|
|
59
58
|
def self.compile(filters, mask:)
|
60
59
|
return lambda { |params| params.dup } if filters.empty?
|
61
60
|
|
62
|
-
strings, regexps, blocks = [], [], []
|
61
|
+
strings, regexps, blocks, deep_regexps, deep_strings = [], [], [], nil, nil
|
63
62
|
|
64
63
|
filters.each do |item|
|
65
64
|
case item
|
66
65
|
when Proc
|
67
66
|
blocks << item
|
68
67
|
when Regexp
|
69
|
-
|
68
|
+
if item.to_s.include?("\\.")
|
69
|
+
(deep_regexps ||= []) << item
|
70
|
+
else
|
71
|
+
regexps << item
|
72
|
+
end
|
70
73
|
else
|
71
|
-
|
74
|
+
s = Regexp.escape(item.to_s)
|
75
|
+
if s.include?("\\.")
|
76
|
+
(deep_strings ||= []) << s
|
77
|
+
else
|
78
|
+
strings << s
|
79
|
+
end
|
72
80
|
end
|
73
81
|
end
|
74
82
|
|
75
|
-
deep_regexps = regexps.extract! { |r| r.to_s.include?("\\.") }
|
76
|
-
deep_strings = strings.extract! { |s| s.include?("\\.") }
|
77
|
-
|
78
83
|
regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
|
79
|
-
deep_regexps << Regexp.new(deep_strings.join("|"), true)
|
84
|
+
(deep_regexps ||= []) << Regexp.new(deep_strings.join("|"), true) if deep_strings&.any?
|
80
85
|
|
81
86
|
new regexps, deep_regexps, blocks, mask: mask
|
82
87
|
end
|
@@ -85,7 +90,7 @@ module ActiveSupport
|
|
85
90
|
|
86
91
|
def initialize(regexps, deep_regexps, blocks, mask:)
|
87
92
|
@regexps = regexps
|
88
|
-
@deep_regexps = deep_regexps
|
93
|
+
@deep_regexps = deep_regexps&.any? ? deep_regexps : nil
|
89
94
|
@blocks = blocks
|
90
95
|
@mask = mask
|
91
96
|
end
|
@@ -40,7 +40,7 @@ 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
|
-
object.instance_variable_set
|
43
|
+
object.instance_variable_set :@per_thread_registry_key, object.name.freeze
|
44
44
|
end
|
45
45
|
|
46
46
|
def instance
|
@@ -56,5 +56,6 @@ module ActiveSupport
|
|
56
56
|
|
57
57
|
send(name, *args, &block)
|
58
58
|
end
|
59
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
59
60
|
end
|
60
61
|
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
|
|
@@ -22,12 +22,25 @@ module ActiveSupport
|
|
22
22
|
app.reloader.before_class_unload { ActiveSupport::CurrentAttributes.clear_all }
|
23
23
|
app.executor.to_run { ActiveSupport::CurrentAttributes.reset_all }
|
24
24
|
app.executor.to_complete { ActiveSupport::CurrentAttributes.reset_all }
|
25
|
+
|
26
|
+
ActiveSupport.on_load(:active_support_test_case) do
|
27
|
+
require "active_support/current_attributes/test_helper"
|
28
|
+
include ActiveSupport::CurrentAttributes::TestHelper
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
32
|
initializer "active_support.deprecation_behavior" do |app|
|
28
33
|
if deprecation = app.config.active_support.deprecation
|
29
34
|
ActiveSupport::Deprecation.behavior = deprecation
|
30
35
|
end
|
36
|
+
|
37
|
+
if disallowed_deprecation = app.config.active_support.disallowed_deprecation
|
38
|
+
ActiveSupport::Deprecation.disallowed_behavior = disallowed_deprecation
|
39
|
+
end
|
40
|
+
|
41
|
+
if disallowed_warnings = app.config.active_support.disallowed_deprecation_warnings
|
42
|
+
ActiveSupport::Deprecation.disallowed_warnings = disallowed_warnings
|
43
|
+
end
|
31
44
|
end
|
32
45
|
|
33
46
|
# Sets the default value for Time.zone
|
@@ -65,15 +78,24 @@ module ActiveSupport
|
|
65
78
|
initializer "active_support.set_configs" do |app|
|
66
79
|
app.config.active_support.each do |k, v|
|
67
80
|
k = "#{k}="
|
68
|
-
ActiveSupport.
|
81
|
+
ActiveSupport.public_send(k, v) if ActiveSupport.respond_to? k
|
69
82
|
end
|
70
83
|
end
|
71
84
|
|
72
85
|
initializer "active_support.set_hash_digest_class" do |app|
|
73
86
|
config.after_initialize do
|
74
87
|
if app.config.active_support.use_sha1_digests
|
88
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
89
|
+
config.active_support.use_sha1_digests is deprecated and will
|
90
|
+
be removed from Rails 7.0. Use
|
91
|
+
config.active_support.hash_digest_class = ::Digest::SHA1 instead.
|
92
|
+
MSG
|
75
93
|
ActiveSupport::Digest.hash_digest_class = ::Digest::SHA1
|
76
94
|
end
|
95
|
+
|
96
|
+
if klass = app.config.active_support.hash_digest_class
|
97
|
+
ActiveSupport::Digest.hash_digest_class = klass
|
98
|
+
end
|
77
99
|
end
|
78
100
|
end
|
79
101
|
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.
|
@@ -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
|
@@ -1,30 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "digest/sha2"
|
4
|
-
|
5
3
|
module ActiveSupport
|
6
4
|
module SecurityUtils
|
7
5
|
# Constant time string comparison, for fixed length strings.
|
8
6
|
#
|
9
7
|
# The values compared should be of fixed length, such as strings
|
10
8
|
# that have already been processed by HMAC. Raises in case of length mismatch.
|
11
|
-
def fixed_length_secure_compare(a, b)
|
12
|
-
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
13
9
|
|
14
|
-
|
10
|
+
if defined?(OpenSSL.fixed_length_secure_compare)
|
11
|
+
def fixed_length_secure_compare(a, b)
|
12
|
+
OpenSSL.fixed_length_secure_compare(a, b)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
def fixed_length_secure_compare(a, b)
|
16
|
+
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
17
|
+
|
18
|
+
l = a.unpack "C#{a.bytesize}"
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
res = 0
|
21
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
22
|
+
res == 0
|
23
|
+
end
|
19
24
|
end
|
20
25
|
module_function :fixed_length_secure_compare
|
21
26
|
|
22
|
-
#
|
27
|
+
# Secure string comparison for strings of variable length.
|
23
28
|
#
|
24
|
-
#
|
25
|
-
# via
|
29
|
+
# While a timing attack would not be able to discern the content of
|
30
|
+
# a secret compared via secure_compare, it is possible to determine
|
31
|
+
# the secret length. This should be considered when using secure_compare
|
32
|
+
# to compare weak, short secrets to user input.
|
26
33
|
def secure_compare(a, b)
|
27
|
-
|
34
|
+
a.bytesize == b.bytesize && fixed_length_secure_compare(a, b)
|
28
35
|
end
|
29
36
|
module_function :secure_compare
|
30
37
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
# Wrapping a string in this class gives you a prettier way to test
|
5
7
|
# for equality. The value returned by <tt>Rails.env</tt> is wrapped
|
@@ -19,11 +21,11 @@ module ActiveSupport
|
|
19
21
|
class StringInquirer < String
|
20
22
|
private
|
21
23
|
def respond_to_missing?(method_name, include_private = false)
|
22
|
-
(
|
24
|
+
method_name.end_with?("?") || super
|
23
25
|
end
|
24
26
|
|
25
27
|
def method_missing(method_name, *arguments)
|
26
|
-
if method_name
|
28
|
+
if method_name.end_with?("?")
|
27
29
|
self == method_name[0..-2]
|
28
30
|
else
|
29
31
|
super
|
@@ -31,15 +31,16 @@ module ActiveSupport
|
|
31
31
|
class Subscriber
|
32
32
|
class << self
|
33
33
|
# Attach the subscriber to a namespace.
|
34
|
-
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications)
|
34
|
+
def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
|
35
35
|
@namespace = namespace
|
36
36
|
@subscriber = subscriber
|
37
37
|
@notifier = notifier
|
38
|
+
@inherit_all = inherit_all
|
38
39
|
|
39
40
|
subscribers << subscriber
|
40
41
|
|
41
42
|
# Add event subscribers for all existing methods on the class.
|
42
|
-
subscriber
|
43
|
+
fetch_public_methods(subscriber, inherit_all).each do |event|
|
43
44
|
add_event_subscriber(event)
|
44
45
|
end
|
45
46
|
end
|
@@ -55,7 +56,7 @@ module ActiveSupport
|
|
55
56
|
subscribers.delete(subscriber)
|
56
57
|
|
57
58
|
# Remove event subscribers of all existing methods on the class.
|
58
|
-
subscriber
|
59
|
+
fetch_public_methods(subscriber, true).each do |event|
|
59
60
|
remove_event_subscriber(event)
|
60
61
|
end
|
61
62
|
|
@@ -81,18 +82,18 @@ module ActiveSupport
|
|
81
82
|
attr_reader :subscriber, :notifier, :namespace
|
82
83
|
|
83
84
|
def add_event_subscriber(event) # :doc:
|
84
|
-
return if invalid_event?(event
|
85
|
+
return if invalid_event?(event)
|
85
86
|
|
86
87
|
pattern = prepare_pattern(event)
|
87
88
|
|
88
|
-
# Don't add multiple subscribers (
|
89
|
+
# Don't add multiple subscribers (e.g. if methods are redefined).
|
89
90
|
return if pattern_subscribed?(pattern)
|
90
91
|
|
91
92
|
subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
|
92
93
|
end
|
93
94
|
|
94
95
|
def remove_event_subscriber(event) # :doc:
|
95
|
-
return if invalid_event?(event
|
96
|
+
return if invalid_event?(event)
|
96
97
|
|
97
98
|
pattern = prepare_pattern(event)
|
98
99
|
|
@@ -107,7 +108,7 @@ module ActiveSupport
|
|
107
108
|
end
|
108
109
|
|
109
110
|
def invalid_event?(event)
|
110
|
-
%
|
111
|
+
%i{ start finish }.include?(event.to_sym)
|
111
112
|
end
|
112
113
|
|
113
114
|
def prepare_pattern(event)
|
@@ -117,6 +118,10 @@ module ActiveSupport
|
|
117
118
|
def pattern_subscribed?(pattern)
|
118
119
|
subscriber.patterns.key?(pattern)
|
119
120
|
end
|
121
|
+
|
122
|
+
def fetch_public_methods(subscriber, inherit_all)
|
123
|
+
subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
|
124
|
+
end
|
120
125
|
end
|
121
126
|
|
122
127
|
attr_reader :patterns # :nodoc:
|