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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +441 -455
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/array_inquirer.rb +4 -2
  5. data/lib/active_support/backtrace_cleaner.rb +3 -3
  6. data/lib/active_support/benchmarkable.rb +1 -1
  7. data/lib/active_support/cache/file_store.rb +3 -3
  8. data/lib/active_support/cache/mem_cache_store.rb +28 -18
  9. data/lib/active_support/cache/memory_store.rb +46 -26
  10. data/lib/active_support/cache/redis_cache_store.rb +25 -25
  11. data/lib/active_support/cache/strategy/local_cache.rb +20 -5
  12. data/lib/active_support/cache.rb +87 -40
  13. data/lib/active_support/callbacks.rb +65 -56
  14. data/lib/active_support/concern.rb +46 -2
  15. data/lib/active_support/configurable.rb +3 -3
  16. data/lib/active_support/configuration_file.rb +51 -0
  17. data/lib/active_support/core_ext/benchmark.rb +2 -2
  18. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  19. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  20. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  21. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  22. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  23. data/lib/active_support/core_ext/digest/uuid.rb +1 -0
  24. data/lib/active_support/core_ext/enumerable.rb +76 -4
  25. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  26. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  27. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  28. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  29. data/lib/active_support/core_ext/load_error.rb +1 -1
  30. data/lib/active_support/core_ext/marshal.rb +2 -0
  31. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  32. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  33. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  34. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  35. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  36. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  37. data/lib/active_support/core_ext/name_error.rb +29 -2
  38. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  39. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  40. data/lib/active_support/core_ext/object/json.rb +12 -1
  41. data/lib/active_support/core_ext/object/try.rb +2 -2
  42. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  43. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  44. data/lib/active_support/core_ext/regexp.rb +8 -1
  45. data/lib/active_support/core_ext/string/access.rb +5 -24
  46. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  47. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  48. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  49. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  50. data/lib/active_support/core_ext/string/output_safety.rb +7 -4
  51. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  52. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  53. data/lib/active_support/core_ext/symbol.rb +3 -0
  54. data/lib/active_support/core_ext/time/calculations.rb +19 -0
  55. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  56. data/lib/active_support/core_ext/uri.rb +5 -1
  57. data/lib/active_support/core_ext.rb +1 -1
  58. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  59. data/lib/active_support/current_attributes.rb +9 -2
  60. data/lib/active_support/dependencies/zeitwerk_integration.rb +4 -1
  61. data/lib/active_support/dependencies.rb +37 -18
  62. data/lib/active_support/deprecation/behaviors.rb +15 -2
  63. data/lib/active_support/deprecation/disallowed.rb +56 -0
  64. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  65. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  66. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  67. data/lib/active_support/deprecation/reporting.rb +50 -7
  68. data/lib/active_support/deprecation.rb +6 -1
  69. data/lib/active_support/descendants_tracker.rb +6 -2
  70. data/lib/active_support/digest.rb +2 -0
  71. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  72. data/lib/active_support/duration.rb +75 -25
  73. data/lib/active_support/encrypted_file.rb +27 -11
  74. data/lib/active_support/environment_inquirer.rb +20 -0
  75. data/lib/active_support/evented_file_update_checker.rb +69 -133
  76. data/lib/active_support/fork_tracker.rb +64 -0
  77. data/lib/active_support/gem_version.rb +3 -3
  78. data/lib/active_support/hash_with_indifferent_access.rb +48 -24
  79. data/lib/active_support/i18n_railtie.rb +14 -19
  80. data/lib/active_support/inflector/inflections.rb +1 -2
  81. data/lib/active_support/inflector/methods.rb +36 -33
  82. data/lib/active_support/inflector/transliterate.rb +4 -4
  83. data/lib/active_support/json/decoding.rb +4 -4
  84. data/lib/active_support/json/encoding.rb +5 -1
  85. data/lib/active_support/key_generator.rb +1 -1
  86. data/lib/active_support/locale/en.yml +7 -3
  87. data/lib/active_support/log_subscriber.rb +8 -0
  88. data/lib/active_support/logger.rb +1 -1
  89. data/lib/active_support/logger_silence.rb +2 -26
  90. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  91. data/lib/active_support/message_encryptor.rb +4 -7
  92. data/lib/active_support/message_verifier.rb +5 -5
  93. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  94. data/lib/active_support/messages/rotator.rb +6 -5
  95. data/lib/active_support/multibyte/chars.rb +4 -42
  96. data/lib/active_support/multibyte/unicode.rb +9 -83
  97. data/lib/active_support/notifications/fanout.rb +23 -8
  98. data/lib/active_support/notifications/instrumenter.rb +6 -15
  99. data/lib/active_support/notifications.rb +32 -5
  100. data/lib/active_support/number_helper/number_converter.rb +1 -1
  101. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  102. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  103. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  104. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  105. data/lib/active_support/number_helper.rb +29 -14
  106. data/lib/active_support/option_merger.rb +2 -1
  107. data/lib/active_support/ordered_options.rb +8 -2
  108. data/lib/active_support/parameter_filter.rb +16 -11
  109. data/lib/active_support/per_thread_registry.rb +2 -1
  110. data/lib/active_support/rails.rb +1 -4
  111. data/lib/active_support/railtie.rb +23 -1
  112. data/lib/active_support/rescuable.rb +4 -4
  113. data/lib/active_support/secure_compare_rotator.rb +51 -0
  114. data/lib/active_support/security_utils.rb +19 -12
  115. data/lib/active_support/string_inquirer.rb +4 -2
  116. data/lib/active_support/subscriber.rb +12 -7
  117. data/lib/active_support/tagged_logging.rb +30 -5
  118. data/lib/active_support/testing/assertions.rb +18 -11
  119. data/lib/active_support/testing/parallelization/server.rb +78 -0
  120. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  121. data/lib/active_support/testing/parallelization.rb +12 -95
  122. data/lib/active_support/testing/time_helpers.rb +40 -3
  123. data/lib/active_support/time_with_zone.rb +67 -43
  124. data/lib/active_support/values/time_zone.rb +22 -10
  125. data/lib/active_support/xml_mini/rexml.rb +8 -1
  126. data/lib/active_support.rb +13 -1
  127. metadata +34 -36
  128. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  129. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  130. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  131. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  132. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  133. 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
- number = convert_to_decimal(number)
15
- if significant && precision > 0
16
- round_significant(number)
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(absolute_number(number)) + 1).floor
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 precision
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 &pound;"
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) # => "100.000%"
143
- # number_to_percentage('98') # => "98.000%"
144
- # number_to_percentage(100, precision: 0) # => "100%"
145
- # number_to_percentage(1000, delimiter: '.', separator: ',') # => "1.000,000%"
146
- # number_to_percentage(302.24398923423, precision: 5) # => "302.24399%"
147
- # number_to_percentage(1000, locale: :fr) # => "1000,000%"
148
- # number_to_percentage(1000, precision: nil) # => "1000%"
149
- # number_to_percentage('98a') # => "98a%"
150
- # number_to_percentage(100, format: '%n %') # => "100.000 %"
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.5 KB). This
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 (eg.: 1200000000 becomes "1.2
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 (eg.: 1500 becomes "1.5
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) if !/^(__|instance_eval|class|object_id)/.match?(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
- # Usually key value pairs are handled something like this:
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 could be reduced to:
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 k =~ /secret/i
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 +"[FILTERED]"+
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
- regexps << item
68
+ if item.to_s.include?("\\.")
69
+ (deep_regexps ||= []) << item
70
+ else
71
+ regexps << item
72
+ end
70
73
  else
71
- strings << Regexp.escape(item.to_s)
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) unless deep_strings.empty?
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.any? ? deep_regexps : nil
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 "@per_thread_registry_key", object.name.freeze
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
@@ -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.send(k, v) if ActiveSupport.respond_to? k
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
- # Rescue exceptions raised in controller actions.
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> option with the name of a method
21
- # or a Proc object to be called to handle them. Alternatively a block can
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
- l = a.unpack "C#{a.bytesize}"
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
- res = 0
17
- b.each_byte { |byte| res |= byte ^ l.shift }
18
- res == 0
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
- # Constant time string comparison, for variable length strings.
27
+ # Secure string comparison for strings of variable length.
23
28
  #
24
- # The values are first processed by SHA256, so that we don't leak length info
25
- # via timing attacks.
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
- fixed_length_secure_compare(::Digest::SHA256.digest(a), ::Digest::SHA256.digest(b)) && a == b
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
- (method_name[-1] == "?") || super
24
+ method_name.end_with?("?") || super
23
25
  end
24
26
 
25
27
  def method_missing(method_name, *arguments)
26
- if method_name[-1] == "?"
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.public_methods(false).each do |event|
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.public_methods(false).each do |event|
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.to_s)
85
+ return if invalid_event?(event)
85
86
 
86
87
  pattern = prepare_pattern(event)
87
88
 
88
- # Don't add multiple subscribers (eg. if methods are redefined).
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.to_s)
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
- %w{ start finish }.include?(event.to_s)
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: