activesupport 6.0.6.1 → 6.1.0.rc1
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 +337 -573
- data/MIT-LICENSE +1 -1
- data/README.rdoc +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 +2 -2
- data/lib/active_support/cache/mem_cache_store.rb +20 -14
- data/lib/active_support/cache/memory_store.rb +38 -26
- data/lib/active_support/cache/redis_cache_store.rb +25 -25
- data/lib/active_support/cache/strategy/local_cache.rb +13 -4
- data/lib/active_support/cache.rb +75 -34
- 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 +46 -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/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 +5 -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/string/access.rb +5 -24
- 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 +8 -38
- 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 +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +5 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +7 -2
- data/lib/active_support/dependencies.rb +38 -24
- 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/duration/iso8601_serializer.rb +15 -9
- data/lib/active_support/duration.rb +71 -22
- data/lib/active_support/encrypted_file.rb +19 -2
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +69 -133
- data/lib/active_support/execution_wrapper.rb +13 -16
- data/lib/active_support/fork_tracker.rb +58 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +35 -22
- 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 +35 -31
- 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 +31 -4
- 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 +3 -3
- 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 +15 -10
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +23 -1
- data/lib/active_support/reloader.rb +1 -1
- 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 +29 -4
- 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 +66 -42
- data/lib/active_support/values/time_zone.rb +20 -10
- data/lib/active_support/xml_mini/rexml.rb +8 -1
- data/lib/active_support.rb +13 -1
- metadata +39 -42
- 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
@@ -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
|
@@ -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
|
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 6.2. 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
|
@@ -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.length == b.length && 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:
|
@@ -8,11 +8,20 @@ require "active_support/logger"
|
|
8
8
|
module ActiveSupport
|
9
9
|
# Wraps any standard Logger object to provide tagging capabilities.
|
10
10
|
#
|
11
|
+
# May be called with a block:
|
12
|
+
#
|
11
13
|
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
12
14
|
# logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
|
13
15
|
# logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
|
14
16
|
# logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
|
15
17
|
#
|
18
|
+
# If called without a block, a new logger will be returned with applied tags:
|
19
|
+
#
|
20
|
+
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
|
21
|
+
# logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff"
|
22
|
+
# logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
23
|
+
# logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
|
24
|
+
#
|
16
25
|
# This is used by the default Rails.logger as configured by Railties to make
|
17
26
|
# it easy to stamp log lines with subdomains, request ids, and anything else
|
18
27
|
# to aid debugging of multi-user production applications.
|
@@ -31,9 +40,10 @@ module ActiveSupport
|
|
31
40
|
end
|
32
41
|
|
33
42
|
def push_tags(*tags)
|
34
|
-
tags.flatten
|
35
|
-
|
36
|
-
|
43
|
+
tags.flatten!
|
44
|
+
tags.reject!(&:blank?)
|
45
|
+
current_tags.concat tags
|
46
|
+
tags
|
37
47
|
end
|
38
48
|
|
39
49
|
def pop_tags(size = 1)
|
@@ -60,6 +70,14 @@ module ActiveSupport
|
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
73
|
+
module LocalTagStorage # :nodoc:
|
74
|
+
attr_accessor :current_tags
|
75
|
+
|
76
|
+
def self.extended(base)
|
77
|
+
base.current_tags = []
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
63
81
|
def self.new(logger)
|
64
82
|
logger = logger.dup
|
65
83
|
|
@@ -77,7 +95,14 @@ module ActiveSupport
|
|
77
95
|
delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
|
78
96
|
|
79
97
|
def tagged(*tags)
|
80
|
-
|
98
|
+
if block_given?
|
99
|
+
formatter.tagged(*tags) { yield self }
|
100
|
+
else
|
101
|
+
logger = ActiveSupport::TaggedLogging.new(self)
|
102
|
+
logger.formatter.extend LocalTagStorage
|
103
|
+
logger.push_tags(*formatter.current_tags, *tags)
|
104
|
+
logger
|
105
|
+
end
|
81
106
|
end
|
82
107
|
|
83
108
|
def flush
|