activesupport 6.0.0.rc1 → 6.0.3.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.

Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +165 -2
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +0 -1
  5. data/lib/active_support/cache.rb +29 -28
  6. data/lib/active_support/cache/file_store.rb +7 -8
  7. data/lib/active_support/cache/mem_cache_store.rb +8 -8
  8. data/lib/active_support/cache/memory_store.rb +8 -7
  9. data/lib/active_support/cache/null_store.rb +3 -3
  10. data/lib/active_support/cache/redis_cache_store.rb +8 -8
  11. data/lib/active_support/cache/strategy/local_cache.rb +23 -23
  12. data/lib/active_support/callbacks.rb +0 -3
  13. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  14. data/lib/active_support/concurrency/share_lock.rb +0 -1
  15. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  16. data/lib/active_support/core_ext/date_and_time/calculations.rb +0 -30
  17. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  18. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  19. data/lib/active_support/core_ext/digest.rb +3 -0
  20. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  21. data/lib/active_support/core_ext/hash/deep_transform_values.rb +2 -2
  22. data/lib/active_support/core_ext/module/delegation.rb +14 -1
  23. data/lib/active_support/core_ext/module/introspection.rb +1 -0
  24. data/lib/active_support/core_ext/object/duplicable.rb +7 -117
  25. data/lib/active_support/core_ext/object/try.rb +2 -0
  26. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  27. data/lib/active_support/core_ext/range/each.rb +0 -1
  28. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  29. data/lib/active_support/core_ext/string/filters.rb +1 -1
  30. data/lib/active_support/core_ext/string/output_safety.rb +2 -1
  31. data/lib/active_support/core_ext/time/calculations.rb +30 -0
  32. data/lib/active_support/dependencies.rb +35 -6
  33. data/lib/active_support/dependencies/zeitwerk_integration.rb +22 -4
  34. data/lib/active_support/deprecation/method_wrappers.rb +12 -6
  35. data/lib/active_support/deprecation/proxy_wrappers.rb +28 -3
  36. data/lib/active_support/descendants_tracker.rb +0 -1
  37. data/lib/active_support/duration.rb +15 -13
  38. data/lib/active_support/duration/iso8601_parser.rb +0 -1
  39. data/lib/active_support/duration/iso8601_serializer.rb +0 -1
  40. data/lib/active_support/encrypted_file.rb +1 -1
  41. data/lib/active_support/evented_file_update_checker.rb +11 -2
  42. data/lib/active_support/file_update_checker.rb +0 -1
  43. data/lib/active_support/gem_version.rb +1 -1
  44. data/lib/active_support/i18n_railtie.rb +4 -0
  45. data/lib/active_support/inflector/inflections.rb +0 -1
  46. data/lib/active_support/inflector/methods.rb +1 -2
  47. data/lib/active_support/inflector/transliterate.rb +27 -1
  48. data/lib/active_support/json/decoding.rb +0 -1
  49. data/lib/active_support/lazy_load_hooks.rb +0 -1
  50. data/lib/active_support/locale/en.rb +4 -2
  51. data/lib/active_support/log_subscriber.rb +0 -1
  52. data/lib/active_support/logger.rb +1 -1
  53. data/lib/active_support/logger_thread_safe_level.rb +2 -1
  54. data/lib/active_support/message_encryptor.rb +1 -1
  55. data/lib/active_support/message_verifier.rb +2 -2
  56. data/lib/active_support/messages/metadata.rb +3 -2
  57. data/lib/active_support/messages/rotator.rb +4 -4
  58. data/lib/active_support/multibyte/chars.rb +1 -2
  59. data/lib/active_support/multibyte/unicode.rb +0 -1
  60. data/lib/active_support/notifications/fanout.rb +2 -2
  61. data/lib/active_support/notifications/instrumenter.rb +4 -4
  62. data/lib/active_support/number_helper.rb +4 -0
  63. data/lib/active_support/number_helper/number_converter.rb +4 -5
  64. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -8
  65. data/lib/active_support/number_helper/number_to_delimited_converter.rb +0 -1
  66. data/lib/active_support/number_helper/number_to_human_converter.rb +0 -1
  67. data/lib/active_support/number_helper/number_to_human_size_converter.rb +0 -1
  68. data/lib/active_support/number_helper/number_to_phone_converter.rb +0 -1
  69. data/lib/active_support/number_helper/number_to_rounded_converter.rb +0 -1
  70. data/lib/active_support/option_merger.rb +21 -3
  71. data/lib/active_support/ordered_hash.rb +1 -1
  72. data/lib/active_support/ordered_options.rb +5 -1
  73. data/lib/active_support/parameter_filter.rb +7 -3
  74. data/lib/active_support/string_inquirer.rb +0 -1
  75. data/lib/active_support/testing/parallelization.rb +16 -2
  76. data/lib/active_support/testing/stream.rb +0 -1
  77. data/lib/active_support/testing/time_helpers.rb +0 -2
  78. data/lib/active_support/xml_mini.rb +0 -1
  79. data/lib/active_support/xml_mini/jdom.rb +0 -1
  80. metadata +13 -9
@@ -172,7 +172,7 @@ module ActiveSupport
172
172
  iv = cipher.random_iv
173
173
  cipher.auth_data = "" if aead_mode?
174
174
 
175
- encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), metadata_options))
175
+ encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), **metadata_options))
176
176
  encrypted_data << cipher.final
177
177
 
178
178
  blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
@@ -172,8 +172,8 @@ module ActiveSupport
172
172
  #
173
173
  # other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
174
174
  # other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
175
- def verify(*args)
176
- verified(*args) || raise(InvalidSignature)
175
+ def verify(*args, **options)
176
+ verified(*args, **options) || raise(InvalidSignature)
177
177
  end
178
178
 
179
179
  # Generates a signed message for the provided value.
@@ -6,7 +6,8 @@ module ActiveSupport
6
6
  module Messages #:nodoc:
7
7
  class Metadata #:nodoc:
8
8
  def initialize(message, expires_at = nil, purpose = nil)
9
- @message, @expires_at, @purpose = message, expires_at, purpose
9
+ @message, @purpose = message, purpose
10
+ @expires_at = expires_at.is_a?(String) ? Time.iso8601(expires_at) : expires_at
10
11
  end
11
12
 
12
13
  def as_json(options = {})
@@ -64,7 +65,7 @@ module ActiveSupport
64
65
  end
65
66
 
66
67
  def fresh?
67
- @expires_at.nil? || Time.now.utc < Time.iso8601(@expires_at)
68
+ @expires_at.nil? || Time.now.utc < @expires_at
68
69
  end
69
70
  end
70
71
  end
@@ -20,12 +20,12 @@ module ActiveSupport
20
20
  def decrypt_and_verify(*args, on_rotation: nil, **options)
21
21
  super
22
22
  rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
23
- run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, options) } || raise
23
+ run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
24
24
  end
25
25
 
26
26
  private
27
27
  def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
28
- self.class.new(secret, sign_secret, options)
28
+ self.class.new(secret, sign_secret, **options)
29
29
  end
30
30
  end
31
31
 
@@ -33,12 +33,12 @@ module ActiveSupport
33
33
  include Rotator
34
34
 
35
35
  def verified(*args, on_rotation: nil, **options)
36
- super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, options) }
36
+ super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
37
37
  end
38
38
 
39
39
  private
40
40
  def build_rotation(secret = @secret, options)
41
- self.class.new(secret, options)
41
+ self.class.new(secret, **options)
42
42
  end
43
43
  end
44
44
 
@@ -122,7 +122,7 @@ module ActiveSupport #:nodoc:
122
122
  #
123
123
  # 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
124
124
  def limit(limit)
125
- truncate_bytes(limit, omission: nil)
125
+ chars(@wrapped_string.truncate_bytes(limit, omission: nil))
126
126
  end
127
127
 
128
128
  # Capitalizes the first letter of every word, when possible.
@@ -207,7 +207,6 @@ module ActiveSupport #:nodoc:
207
207
  end
208
208
 
209
209
  private
210
-
211
210
  def chars(string)
212
211
  self.class.new(string)
213
212
  end
@@ -148,7 +148,6 @@ module ActiveSupport
148
148
  end
149
149
 
150
150
  private
151
-
152
151
  def recode_windows1252_chars(string)
153
152
  string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
154
153
  end
@@ -180,13 +180,13 @@ module ActiveSupport
180
180
 
181
181
  def start(name, id, payload)
182
182
  timestack = Thread.current[:_timestack] ||= []
183
- timestack.push Concurrent.monotonic_time
183
+ timestack.push Time.now
184
184
  end
185
185
 
186
186
  def finish(name, id, payload)
187
187
  timestack = Thread.current[:_timestack]
188
188
  started = timestack.pop
189
- @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
189
+ @delegate.call(name, started, Time.now, id, payload)
190
190
  end
191
191
  end
192
192
 
@@ -46,7 +46,6 @@ module ActiveSupport
46
46
  end
47
47
 
48
48
  private
49
-
50
49
  def unique_id
51
50
  SecureRandom.hex(10)
52
51
  end
@@ -56,8 +55,9 @@ module ActiveSupport
56
55
  attr_reader :name, :time, :end, :transaction_id, :payload, :children
57
56
 
58
57
  def self.clock_gettime_supported? # :nodoc:
59
- defined?(Process::CLOCK_PROCESS_CPUTIME_ID) &&
60
- !Gem.win_platform?
58
+ defined?(Process::CLOCK_THREAD_CPUTIME_ID) &&
59
+ !Gem.win_platform? &&
60
+ !RUBY_PLATFORM.match?(/solaris/i)
61
61
  end
62
62
  private_class_method :clock_gettime_supported?
63
63
 
@@ -142,7 +142,7 @@ module ActiveSupport
142
142
 
143
143
  if clock_gettime_supported?
144
144
  def now_cpu
145
- Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID)
145
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
146
146
  end
147
147
  else
148
148
  def now_cpu
@@ -99,6 +99,10 @@ module ActiveSupport
99
99
  # number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
100
100
  # number_to_currency('123a456') # => "$123a456"
101
101
  #
102
+ # number_to_currency("123a456", raise: true) # => InvalidNumberError
103
+ #
104
+ # number_to_currency(-0.456789, precision: 0)
105
+ # # => "$0"
102
106
  # number_to_currency(-1234567890.50, negative_format: '(%u%n)')
103
107
  # # => "($1,234,567,890.50)"
104
108
  # number_to_currency(1234567890.50, unit: '&pound;', separator: ',', delimiter: '')
@@ -136,7 +136,6 @@ module ActiveSupport
136
136
  end
137
137
 
138
138
  private
139
-
140
139
  def options
141
140
  @options ||= format_options.merge(opts)
142
141
  end
@@ -162,12 +161,12 @@ module ActiveSupport
162
161
  options
163
162
  end
164
163
 
165
- def translate_number_value_with_default(key, i18n_options = {})
166
- I18n.translate(key, { default: default_value(key), scope: :number }.merge!(i18n_options))
164
+ def translate_number_value_with_default(key, **i18n_options)
165
+ I18n.translate(key, **{ default: default_value(key), scope: :number }.merge!(i18n_options))
167
166
  end
168
167
 
169
- def translate_in_locale(key, i18n_options = {})
170
- translate_number_value_with_default(key, { locale: options[:locale] }.merge(i18n_options))
168
+ def translate_in_locale(key, **i18n_options)
169
+ translate_number_value_with_default(key, **{ locale: options[:locale] }.merge(i18n_options))
171
170
  end
172
171
 
173
172
  def default_value(key)
@@ -9,11 +9,15 @@ module ActiveSupport
9
9
 
10
10
  def convert
11
11
  number = self.number.to_s.strip
12
+ number_f = number.to_f
12
13
  format = options[:format]
13
14
 
14
- if number.to_f.negative?
15
- format = options[:negative_format]
16
- number = absolute_value(number)
15
+ if number_f.negative?
16
+ number = number_f.abs
17
+
18
+ unless options[:precision] == 0 && number < 0.5
19
+ format = options[:negative_format]
20
+ end
17
21
  end
18
22
 
19
23
  rounded_number = NumberToRoundedConverter.convert(number, options)
@@ -21,11 +25,6 @@ module ActiveSupport
21
25
  end
22
26
 
23
27
  private
24
-
25
- def absolute_value(number)
26
- number.respond_to?(:abs) ? number.abs : number.sub(/\A-/, "")
27
- end
28
-
29
28
  def options
30
29
  @options ||= begin
31
30
  defaults = default_format_options.merge(i18n_opts)
@@ -14,7 +14,6 @@ module ActiveSupport
14
14
  end
15
15
 
16
16
  private
17
-
18
17
  def parts
19
18
  left, right = number.to_s.split(".")
20
19
  left.gsub!(delimiter_pattern) do |digit_to_delimit|
@@ -31,7 +31,6 @@ module ActiveSupport
31
31
  end
32
32
 
33
33
  private
34
-
35
34
  def format
36
35
  options[:format] || translate_in_locale("human.decimal_units.format")
37
36
  end
@@ -28,7 +28,6 @@ module ActiveSupport
28
28
  end
29
29
 
30
30
  private
31
-
32
31
  def conversion_format
33
32
  translate_number_value_with_default("human.storage_units.format", locale: options[:locale], raise: true)
34
33
  end
@@ -12,7 +12,6 @@ module ActiveSupport
12
12
  end
13
13
 
14
14
  private
15
-
16
15
  def convert_to_phone_number(number)
17
16
  if opts[:area_code]
18
17
  convert_with_area_code(number)
@@ -38,7 +38,6 @@ module ActiveSupport
38
38
  end
39
39
 
40
40
  private
41
-
42
41
  def strip_insignificant_zeros
43
42
  options[:strip_insignificant_zeros]
44
43
  end
@@ -5,7 +5,7 @@ require "active_support/core_ext/hash/deep_merge"
5
5
  module ActiveSupport
6
6
  class OptionMerger #:nodoc:
7
7
  instance_methods.each do |method|
8
- undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
8
+ undef_method(method) if !/^(__|instance_eval|class|object_id)/.match?(method)
9
9
  end
10
10
 
11
11
  def initialize(context, options)
@@ -14,14 +14,32 @@ module ActiveSupport
14
14
 
15
15
  private
16
16
  def method_missing(method, *arguments, &block)
17
+ options = nil
17
18
  if arguments.first.is_a?(Proc)
18
19
  proc = arguments.pop
19
20
  arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
21
+ elsif arguments.last.respond_to?(:to_hash)
22
+ options = @options.deep_merge(arguments.pop)
20
23
  else
21
- arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
24
+ options = @options
22
25
  end
23
26
 
24
- @context.__send__(method, *arguments, &block)
27
+ invoke_method(method, arguments, options, &block)
28
+ end
29
+
30
+ if RUBY_VERSION >= "2.7"
31
+ def invoke_method(method, arguments, options, &block)
32
+ if options
33
+ @context.__send__(method, *arguments, **options, &block)
34
+ else
35
+ @context.__send__(method, *arguments, &block)
36
+ end
37
+ end
38
+ else
39
+ def invoke_method(method, arguments, options, &block)
40
+ arguments << options if options
41
+ @context.__send__(method, *arguments, &block)
42
+ end
25
43
  end
26
44
  end
27
45
  end
@@ -16,7 +16,7 @@ module ActiveSupport
16
16
  # oh.keys # => [:a, :b], this order is guaranteed
17
17
  #
18
18
  # Also, maps the +omap+ feature for YAML files
19
- # (See http://yaml.org/type/omap.html) to support ordered items
19
+ # (See https://yaml.org/type/omap.html) to support ordered items
20
20
  # when loading from yaml.
21
21
  #
22
22
  # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
@@ -39,7 +39,7 @@ module ActiveSupport
39
39
  end
40
40
 
41
41
  def method_missing(name, *args)
42
- name_string = name.to_s
42
+ name_string = +name.to_s
43
43
  if name_string.chomp!("=")
44
44
  self[name_string] = args.first
45
45
  else
@@ -56,6 +56,10 @@ module ActiveSupport
56
56
  def respond_to_missing?(name, include_private)
57
57
  true
58
58
  end
59
+
60
+ def extractable_options?
61
+ true
62
+ end
59
63
  end
60
64
 
61
65
  # +InheritableOptions+ provides a constructor to build an +OrderedOptions+
@@ -51,7 +51,6 @@ module ActiveSupport
51
51
  end
52
52
 
53
53
  private
54
-
55
54
  def compiled_filter
56
55
  @compiled_filter ||= CompiledFilter.compile(@filters, mask: @mask)
57
56
  end
@@ -103,14 +102,19 @@ module ActiveSupport
103
102
 
104
103
  def value_for_key(key, value, parents = [], original_params = nil)
105
104
  parents.push(key) if deep_regexps
106
- if regexps.any? { |r| r.match?(key) }
105
+ if regexps.any? { |r| r.match?(key.to_s) }
107
106
  value = @mask
108
107
  elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| r.match?(joined) }
109
108
  value = @mask
110
109
  elsif value.is_a?(Hash)
111
110
  value = call(value, parents, original_params)
112
111
  elsif value.is_a?(Array)
113
- value = value.map { |v| v.is_a?(Hash) ? call(v, parents, original_params) : v }
112
+ # If we don't pop the current parent it will be duplicated as we
113
+ # process each array value.
114
+ parents.pop if deep_regexps
115
+ value = value.map { |v| value_for_key(key, v, parents, original_params) }
116
+ # Restore the parent stack after processing the array.
117
+ parents.push(key) if deep_regexps
114
118
  elsif blocks.any?
115
119
  key = key.dup if key.duplicable?
116
120
  value = value.dup if value.duplicable?
@@ -18,7 +18,6 @@ module ActiveSupport
18
18
  # vehicle.bike? # => false
19
19
  class StringInquirer < String
20
20
  private
21
-
22
21
  def respond_to_missing?(method_name, include_private = false)
23
22
  (method_name[-1] == "?") || super
24
23
  end
@@ -27,6 +27,10 @@ module ActiveSupport
27
27
  @queue << o
28
28
  end
29
29
 
30
+ def length
31
+ @queue.length
32
+ end
33
+
30
34
  def pop; @queue.pop; end
31
35
  end
32
36
 
@@ -90,8 +94,14 @@ module ActiveSupport
90
94
  begin
91
95
  queue.record(reporter, result)
92
96
  rescue DRb::DRbConnError
93
- result.failures.each do |failure|
94
- failure.exception = DRb::DRbRemoteError.new(failure.exception)
97
+ result.failures.map! do |failure|
98
+ if failure.respond_to?(:error)
99
+ # minitest >5.14.0
100
+ error = DRb::DRbRemoteError.new(failure.error)
101
+ else
102
+ error = DRb::DRbRemoteError.new(failure.exception)
103
+ end
104
+ Minitest::UnexpectedError.new(error)
95
105
  end
96
106
  queue.record(reporter, result)
97
107
  end
@@ -109,6 +119,10 @@ module ActiveSupport
109
119
  def shutdown
110
120
  @queue_size.times { @queue << nil }
111
121
  @pool.each { |pid| Process.waitpid pid }
122
+
123
+ if @queue.length > 0
124
+ raise "Queue not empty, but all workers have finished. This probably means that a worker crashed and #{@queue.length} tests were missed."
125
+ end
112
126
  end
113
127
 
114
128
  private
@@ -4,7 +4,6 @@ module ActiveSupport
4
4
  module Testing
5
5
  module Stream #:nodoc:
6
6
  private
7
-
8
7
  def silence_stream(stream)
9
8
  old_stream = stream.dup
10
9
  stream.reopen(IO::NULL)
@@ -40,7 +40,6 @@ module ActiveSupport
40
40
  end
41
41
 
42
42
  private
43
-
44
43
  def unstub_object(stub)
45
44
  singleton_class = stub.object.singleton_class
46
45
  singleton_class.silence_redefinition_of_method stub.method_name
@@ -191,7 +190,6 @@ module ActiveSupport
191
190
  end
192
191
 
193
192
  private
194
-
195
193
  def simple_stubs
196
194
  @simple_stubs ||= SimpleStubs.new
197
195
  end
@@ -155,7 +155,6 @@ module ActiveSupport
155
155
  end
156
156
 
157
157
  private
158
-
159
158
  def _dasherize(key)
160
159
  # $2 must be a non-greedy regex for this to work
161
160
  left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1, 3]
@@ -53,7 +53,6 @@ module ActiveSupport
53
53
  end
54
54
 
55
55
  private
56
-
57
56
  # Convert an XML element and merge into the hash
58
57
  #
59
58
  # hash::