activesupport 6.1.4.2 → 7.0.2.3

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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +226 -462
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +0 -2
  6. data/lib/active_support/benchmarkable.rb +2 -2
  7. data/lib/active_support/cache/file_store.rb +15 -9
  8. data/lib/active_support/cache/mem_cache_store.rb +127 -32
  9. data/lib/active_support/cache/memory_store.rb +23 -15
  10. data/lib/active_support/cache/null_store.rb +10 -2
  11. data/lib/active_support/cache/redis_cache_store.rb +42 -67
  12. data/lib/active_support/cache/strategy/local_cache.rb +35 -61
  13. data/lib/active_support/cache.rb +189 -45
  14. data/lib/active_support/callbacks.rb +180 -81
  15. data/lib/active_support/code_generator.rb +65 -0
  16. data/lib/active_support/concern.rb +5 -5
  17. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  18. data/lib/active_support/concurrency/share_lock.rb +2 -2
  19. data/lib/active_support/configurable.rb +6 -3
  20. data/lib/active_support/configuration_file.rb +1 -1
  21. data/lib/active_support/core_ext/array/access.rb +1 -5
  22. data/lib/active_support/core_ext/array/conversions.rb +13 -11
  23. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  24. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  25. data/lib/active_support/core_ext/array.rb +1 -0
  26. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  27. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  28. data/lib/active_support/core_ext/date/blank.rb +1 -1
  29. data/lib/active_support/core_ext/date/calculations.rb +4 -4
  30. data/lib/active_support/core_ext/date/conversions.rb +11 -11
  31. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  32. data/lib/active_support/core_ext/date.rb +1 -0
  33. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  34. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  35. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  36. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  37. data/lib/active_support/core_ext/date_time.rb +1 -0
  38. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  39. data/lib/active_support/core_ext/enumerable.rb +78 -26
  40. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  41. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  42. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  43. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  44. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  45. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  46. data/lib/active_support/core_ext/name_error.rb +2 -8
  47. data/lib/active_support/core_ext/numeric/conversions.rb +79 -76
  48. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  49. data/lib/active_support/core_ext/numeric.rb +1 -0
  50. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  51. data/lib/active_support/core_ext/object/blank.rb +2 -2
  52. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  53. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  54. data/lib/active_support/core_ext/object/json.rb +29 -24
  55. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  56. data/lib/active_support/core_ext/object/try.rb +20 -20
  57. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  58. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  59. data/lib/active_support/core_ext/pathname.rb +3 -0
  60. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  61. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  62. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  63. data/lib/active_support/core_ext/range/each.rb +1 -1
  64. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
  65. data/lib/active_support/core_ext/range.rb +1 -1
  66. data/lib/active_support/core_ext/string/filters.rb +1 -1
  67. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  68. data/lib/active_support/core_ext/string/output_safety.rb +60 -36
  69. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  70. data/lib/active_support/core_ext/time/calculations.rb +7 -6
  71. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  72. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  73. data/lib/active_support/core_ext/time/zones.rb +4 -19
  74. data/lib/active_support/core_ext/time.rb +1 -0
  75. data/lib/active_support/core_ext/uri.rb +3 -27
  76. data/lib/active_support/core_ext.rb +1 -0
  77. data/lib/active_support/current_attributes.rb +31 -14
  78. data/lib/active_support/dependencies/interlock.rb +10 -18
  79. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  80. data/lib/active_support/dependencies.rb +58 -788
  81. data/lib/active_support/deprecation/behaviors.rb +4 -1
  82. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  83. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  84. data/lib/active_support/deprecation.rb +1 -1
  85. data/lib/active_support/descendants_tracker.rb +174 -68
  86. data/lib/active_support/digest.rb +5 -3
  87. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  88. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  89. data/lib/active_support/duration.rb +81 -51
  90. data/lib/active_support/encrypted_configuration.rb +13 -2
  91. data/lib/active_support/encrypted_file.rb +1 -1
  92. data/lib/active_support/environment_inquirer.rb +1 -1
  93. data/lib/active_support/error_reporter.rb +117 -0
  94. data/lib/active_support/evented_file_update_checker.rb +1 -1
  95. data/lib/active_support/execution_context/test_helper.rb +13 -0
  96. data/lib/active_support/execution_context.rb +53 -0
  97. data/lib/active_support/execution_wrapper.rb +43 -21
  98. data/lib/active_support/executor/test_helper.rb +7 -0
  99. data/lib/active_support/fork_tracker.rb +19 -12
  100. data/lib/active_support/gem_version.rb +4 -4
  101. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  102. data/lib/active_support/html_safe_translation.rb +43 -0
  103. data/lib/active_support/i18n.rb +1 -0
  104. data/lib/active_support/i18n_railtie.rb +1 -1
  105. data/lib/active_support/inflector/inflections.rb +23 -7
  106. data/lib/active_support/inflector/methods.rb +24 -48
  107. data/lib/active_support/isolated_execution_state.rb +64 -0
  108. data/lib/active_support/json/encoding.rb +3 -3
  109. data/lib/active_support/key_generator.rb +18 -1
  110. data/lib/active_support/locale/en.yml +1 -1
  111. data/lib/active_support/log_subscriber.rb +13 -3
  112. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  113. data/lib/active_support/message_encryptor.rb +8 -3
  114. data/lib/active_support/message_verifier.rb +46 -14
  115. data/lib/active_support/messages/metadata.rb +2 -2
  116. data/lib/active_support/multibyte/chars.rb +10 -11
  117. data/lib/active_support/multibyte/unicode.rb +0 -12
  118. data/lib/active_support/multibyte.rb +1 -1
  119. data/lib/active_support/notifications/fanout.rb +91 -65
  120. data/lib/active_support/notifications/instrumenter.rb +32 -15
  121. data/lib/active_support/notifications.rb +15 -21
  122. data/lib/active_support/number_helper/number_converter.rb +1 -3
  123. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  124. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  125. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  126. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  127. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  128. data/lib/active_support/number_helper.rb +0 -2
  129. data/lib/active_support/option_merger.rb +8 -16
  130. data/lib/active_support/ordered_hash.rb +1 -1
  131. data/lib/active_support/parameter_filter.rb +5 -0
  132. data/lib/active_support/per_thread_registry.rb +5 -0
  133. data/lib/active_support/railtie.rb +69 -19
  134. data/lib/active_support/reloader.rb +1 -1
  135. data/lib/active_support/rescuable.rb +2 -2
  136. data/lib/active_support/ruby_features.rb +7 -0
  137. data/lib/active_support/secure_compare_rotator.rb +1 -1
  138. data/lib/active_support/string_inquirer.rb +0 -2
  139. data/lib/active_support/subscriber.rb +7 -18
  140. data/lib/active_support/tagged_logging.rb +2 -2
  141. data/lib/active_support/test_case.rb +9 -21
  142. data/lib/active_support/testing/assertions.rb +35 -5
  143. data/lib/active_support/testing/deprecation.rb +52 -1
  144. data/lib/active_support/testing/isolation.rb +2 -2
  145. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  146. data/lib/active_support/testing/parallelization/server.rb +4 -0
  147. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  148. data/lib/active_support/testing/parallelization.rb +4 -0
  149. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  150. data/lib/active_support/testing/stream.rb +3 -5
  151. data/lib/active_support/testing/tagged_logging.rb +1 -1
  152. data/lib/active_support/testing/time_helpers.rb +13 -2
  153. data/lib/active_support/time_with_zone.rb +54 -13
  154. data/lib/active_support/values/time_zone.rb +30 -9
  155. data/lib/active_support/xml_mini/jdom.rb +1 -1
  156. data/lib/active_support/xml_mini/libxml.rb +5 -5
  157. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  158. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  159. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  160. data/lib/active_support/xml_mini/rexml.rb +1 -1
  161. data/lib/active_support/xml_mini.rb +5 -4
  162. data/lib/active_support.rb +17 -1
  163. metadata +26 -23
  164. data/lib/active_support/core_ext/marshal.rb +0 -26
  165. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -8,16 +8,21 @@ module ActiveSupport
8
8
  self.namespace = :currency
9
9
 
10
10
  def convert
11
- number = self.number.to_s.strip
12
11
  format = options[:format]
13
12
 
14
- if number.sub!(/^-/, "") &&
15
- (options[:precision] != 0 || number.to_f > 0.5)
16
- format = options[:negative_format]
13
+ number_f = valid_float?
14
+ if number_f
15
+ if number_f.negative?
16
+ number_f = number_f.abs
17
+ format = options[:negative_format] if (number_f * 10**options[:precision]) >= 0.5
18
+ end
19
+ number_s = NumberToRoundedConverter.convert(number_f, options)
20
+ else
21
+ number_s = number.to_s.strip
22
+ format = options[:negative_format] if number_s.sub!(/^-/, "")
17
23
  end
18
24
 
19
- rounded_number = NumberToRoundedConverter.convert(number, options)
20
- format.gsub("%n", rounded_number).gsub("%u", options[:unit])
25
+ format.gsub("%n", number_s).gsub("%u", options[:unit])
21
26
  end
22
27
 
23
28
  private
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
7
- class NumberToDelimitedConverter < NumberConverter #:nodoc:
7
+ class NumberToDelimitedConverter < NumberConverter # :nodoc:
8
8
  self.validate_float = true
9
9
 
10
10
  DEFAULT_DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
7
- class NumberToHumanSizeConverter < NumberConverter #:nodoc:
7
+ class NumberToHumanSizeConverter < NumberConverter # :nodoc:
8
8
  STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb, :pb, :eb]
9
9
 
10
10
  self.namespace = :human
@@ -4,7 +4,7 @@ require "active_support/number_helper/number_converter"
4
4
 
5
5
  module ActiveSupport
6
6
  module NumberHelper
7
- class NumberToPhoneConverter < NumberConverter #:nodoc:
7
+ class NumberToPhoneConverter < NumberConverter # :nodoc:
8
8
  def convert
9
9
  str = country_code(opts[:country_code]).dup
10
10
  str << convert_to_phone_number(number.to_s.strip)
@@ -35,16 +35,12 @@ module ActiveSupport
35
35
  end
36
36
 
37
37
  def absolute_precision(number)
38
- if significant && options[:precision] > 0
38
+ if options[:significant] && options[:precision] > 0
39
39
  options[:precision] - digit_count(convert_to_decimal(number))
40
40
  else
41
41
  options[:precision]
42
42
  end
43
43
  end
44
-
45
- def significant
46
- options[:significant]
47
- end
48
44
  end
49
45
  end
50
46
  end
@@ -99,8 +99,6 @@ module ActiveSupport
99
99
  # number_to_currency(1234567890.506, locale: :fr) # => "1 234 567 890,51 €"
100
100
  # number_to_currency('123a456') # => "$123a456"
101
101
  #
102
- # number_to_currency("123a456", raise: true) # => InvalidNumberError
103
- #
104
102
  # number_to_currency(-0.456789, precision: 0)
105
103
  # # => "$0"
106
104
  # number_to_currency(-1234567890.50, negative_format: '(%u%n)')
@@ -1,10 +1,9 @@
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"
5
4
 
6
5
  module ActiveSupport
7
- class OptionMerger #:nodoc:
6
+ class OptionMerger # :nodoc:
8
7
  instance_methods.each do |method|
9
8
  undef_method(method) unless method.start_with?("__", "instance_eval", "class", "object_id")
10
9
  end
@@ -25,22 +24,15 @@ module ActiveSupport
25
24
  options = @options
26
25
  end
27
26
 
28
- invoke_method(method, arguments, options, &block)
29
- end
30
-
31
- if RUBY_VERSION >= "2.7"
32
- def invoke_method(method, arguments, options, &block)
33
- if options
34
- @context.__send__(method, *arguments, **options, &block)
35
- else
36
- @context.__send__(method, *arguments, &block)
37
- end
38
- end
39
- else
40
- def invoke_method(method, arguments, options, &block)
41
- arguments << options.dup if options
27
+ if options
28
+ @context.__send__(method, *arguments, **options, &block)
29
+ else
42
30
  @context.__send__(method, *arguments, &block)
43
31
  end
44
32
  end
33
+
34
+ def respond_to_missing?(*arguments)
35
+ @context.respond_to?(*arguments)
36
+ end
45
37
  end
46
38
  end
@@ -21,7 +21,7 @@ module ActiveSupport
21
21
  #
22
22
  # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
23
23
  # with other implementations.
24
- class OrderedHash < ::Hash
24
+ class OrderedHash < ::Hash # :nodoc:
25
25
  def to_yaml_type
26
26
  "!tag:yaml.org,2002:omap"
27
27
  end
@@ -16,6 +16,11 @@ module ActiveSupport
16
16
  # ActiveSupport::ParameterFilter.new([:foo, "bar"])
17
17
  # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
18
18
  #
19
+ # ActiveSupport::ParameterFilter.new([/\Apin\z/i, /\Apin_/i])
20
+ # => replaces the value for the exact (case-insensitive) key 'pin' and all
21
+ # (case-insensitive) keys beginning with 'pin_', with "[FILTERED]".
22
+ # Does not match keys with 'pin' as a substring, such as 'shipping_id'.
23
+ #
19
24
  # ActiveSupport::ParameterFilter.new(["credit_card.code"])
20
25
  # => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
21
26
  # change { file: { code: "xxxx"} }
@@ -40,6 +40,10 @@ 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
+ ActiveSupport::Deprecation.warn(<<~MSG)
44
+ ActiveSupport::PerThreadRegistry is deprecated and will be removed in Rails 7.1.
45
+ Use `Module#thread_mattr_accessor` instead.
46
+ MSG
43
47
  object.instance_variable_set :@per_thread_registry_key, object.name.freeze
44
48
  end
45
49
 
@@ -56,5 +60,6 @@ module ActiveSupport
56
60
 
57
61
  send(name, *args, &block)
58
62
  end
63
+ ruby2_keywords(:method_missing)
59
64
  end
60
65
  end
@@ -6,9 +6,25 @@ require "active_support/i18n_railtie"
6
6
  module ActiveSupport
7
7
  class Railtie < Rails::Railtie # :nodoc:
8
8
  config.active_support = ActiveSupport::OrderedOptions.new
9
+ config.active_support.disable_to_s_conversion = false
9
10
 
10
11
  config.eager_load_namespaces << ActiveSupport
11
12
 
13
+ initializer "active_support.isolation_level" do |app|
14
+ if level = app.config.active_support.delete(:isolation_level)
15
+ ActiveSupport::IsolatedExecutionState.isolation_level = level
16
+ end
17
+ end
18
+
19
+ initializer "active_support.remove_deprecated_time_with_zone_name" do |app|
20
+ config.after_initialize do
21
+ if app.config.active_support.remove_deprecated_time_with_zone_name
22
+ require "active_support/time_with_zone"
23
+ TimeWithZone.singleton_class.remove_method(:name)
24
+ end
25
+ end
26
+ end
27
+
12
28
  initializer "active_support.set_authenticated_message_encryption" do |app|
13
29
  config.after_initialize do
14
30
  unless app.config.active_support.use_authenticated_message_encryption.nil?
@@ -18,28 +34,50 @@ module ActiveSupport
18
34
  end
19
35
  end
20
36
 
37
+ initializer "active_support.reset_execution_context" do |app|
38
+ app.reloader.before_class_unload { ActiveSupport::ExecutionContext.clear }
39
+ app.executor.to_run { ActiveSupport::ExecutionContext.clear }
40
+ app.executor.to_complete { ActiveSupport::ExecutionContext.clear }
41
+ end
42
+
21
43
  initializer "active_support.reset_all_current_attributes_instances" do |app|
44
+ executor_around_test_case = app.config.active_support.executor_around_test_case
45
+
22
46
  app.reloader.before_class_unload { ActiveSupport::CurrentAttributes.clear_all }
23
47
  app.executor.to_run { ActiveSupport::CurrentAttributes.reset_all }
24
48
  app.executor.to_complete { ActiveSupport::CurrentAttributes.reset_all }
25
49
 
26
50
  ActiveSupport.on_load(:active_support_test_case) do
27
- require "active_support/current_attributes/test_helper"
28
- include ActiveSupport::CurrentAttributes::TestHelper
51
+ if executor_around_test_case
52
+ require "active_support/executor/test_helper"
53
+ include ActiveSupport::Executor::TestHelper
54
+ else
55
+ require "active_support/current_attributes/test_helper"
56
+ include ActiveSupport::CurrentAttributes::TestHelper
57
+
58
+ require "active_support/execution_context/test_helper"
59
+ include ActiveSupport::ExecutionContext::TestHelper
60
+ end
29
61
  end
30
62
  end
31
63
 
32
64
  initializer "active_support.deprecation_behavior" do |app|
33
- if deprecation = app.config.active_support.deprecation
34
- ActiveSupport::Deprecation.behavior = deprecation
35
- end
65
+ if app.config.active_support.report_deprecations == false
66
+ ActiveSupport::Deprecation.silenced = true
67
+ ActiveSupport::Deprecation.behavior = :silence
68
+ ActiveSupport::Deprecation.disallowed_behavior = :silence
69
+ else
70
+ if deprecation = app.config.active_support.deprecation
71
+ ActiveSupport::Deprecation.behavior = deprecation
72
+ end
36
73
 
37
- if disallowed_deprecation = app.config.active_support.disallowed_deprecation
38
- ActiveSupport::Deprecation.disallowed_behavior = disallowed_deprecation
39
- end
74
+ if disallowed_deprecation = app.config.active_support.disallowed_deprecation
75
+ ActiveSupport::Deprecation.disallowed_behavior = disallowed_deprecation
76
+ end
40
77
 
41
- if disallowed_warnings = app.config.active_support.disallowed_deprecation_warnings
42
- ActiveSupport::Deprecation.disallowed_warnings = disallowed_warnings
78
+ if disallowed_warnings = app.config.active_support.disallowed_deprecation_warnings
79
+ ActiveSupport::Deprecation.disallowed_warnings = disallowed_warnings
80
+ end
43
81
  end
44
82
  end
45
83
 
@@ -75,6 +113,10 @@ module ActiveSupport
75
113
  end
76
114
  end
77
115
 
116
+ initializer "active_support.set_error_reporter" do |app|
117
+ ActiveSupport.error_reporter = app.executor.error_reporter
118
+ end
119
+
78
120
  initializer "active_support.set_configs" do |app|
79
121
  app.config.active_support.each do |k, v|
80
122
  k = "#{k}="
@@ -84,19 +126,27 @@ module ActiveSupport
84
126
 
85
127
  initializer "active_support.set_hash_digest_class" do |app|
86
128
  config.after_initialize do
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
93
- ActiveSupport::Digest.hash_digest_class = ::Digest::SHA1
94
- end
95
-
96
129
  if klass = app.config.active_support.hash_digest_class
97
130
  ActiveSupport::Digest.hash_digest_class = klass
98
131
  end
99
132
  end
100
133
  end
134
+
135
+ initializer "active_support.set_key_generator_hash_digest_class" do |app|
136
+ config.after_initialize do
137
+ if klass = app.config.active_support.key_generator_hash_digest_class
138
+ ActiveSupport::KeyGenerator.hash_digest_class = klass
139
+ end
140
+ end
141
+ end
142
+
143
+ initializer "active_support.set_rfc4122_namespaced_uuids" do |app|
144
+ config.after_initialize do
145
+ if app.config.active_support.use_rfc4122_namespaced_uuids
146
+ require "active_support/core_ext/digest"
147
+ ::Digest::UUID.use_rfc4122_namespaced_uuids = app.config.active_support.use_rfc4122_namespaced_uuids
148
+ end
149
+ end
150
+ end
101
151
  end
102
152
  end
@@ -58,7 +58,7 @@ module ActiveSupport
58
58
  prepare!
59
59
  end
60
60
 
61
- def self.run! # :nodoc:
61
+ def self.run!(reset: false) # :nodoc:
62
62
  if check!
63
63
  super
64
64
  else
@@ -100,7 +100,7 @@ module ActiveSupport
100
100
  end
101
101
  end
102
102
 
103
- def handler_for_rescue(exception, object: self) #:nodoc:
103
+ def handler_for_rescue(exception, object: self) # :nodoc:
104
104
  case rescuer = find_rescue_handler(exception)
105
105
  when Symbol
106
106
  method = object.method(rescuer)
@@ -167,7 +167,7 @@ module ActiveSupport
167
167
 
168
168
  # Internal handler lookup. Delegates to class method. Some libraries call
169
169
  # this directly, so keeping it around for compatibility.
170
- def handler_for_rescue(exception) #:nodoc:
170
+ def handler_for_rescue(exception) # :nodoc:
171
171
  self.class.handler_for_rescue exception, object: self
172
172
  end
173
173
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module RubyFeatures # :nodoc:
5
+ CLASS_SUBCLASSES = Class.method_defined?(:subclasses) # RUBY_VERSION >= "3.1"
6
+ end
7
+ end
@@ -17,7 +17,7 @@ module ActiveSupport
17
17
  #
18
18
  # class MyController < ApplicationController
19
19
  # def authenticate_request
20
- # rotator = ActiveSupport::SecureComparerotator.new('new_password')
20
+ # rotator = ActiveSupport::SecureCompareRotator.new('new_password')
21
21
  # rotator.rotate('old_password')
22
22
  #
23
23
  # authenticate_or_request_with_http_basic do |username, password|
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/symbol/starts_ends_with"
4
-
5
3
  module ActiveSupport
6
4
  # Wrapping a string in this class gives you a prettier way to test
7
5
  # for equality. The value returned by <tt>Rails.env</tt> is wrapped
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/per_thread_registry"
4
3
  require "active_support/notifications"
5
4
 
6
5
  module ActiveSupport
@@ -150,25 +149,15 @@ module ActiveSupport
150
149
  send(method, event)
151
150
  end
152
151
 
152
+ def publish_event(event) # :nodoc:
153
+ method = event.name.split(".").first
154
+ send(method, event)
155
+ end
156
+
153
157
  private
154
158
  def event_stack
155
- SubscriberQueueRegistry.instance.get_queue(@queue_key)
159
+ registry = ActiveSupport::IsolatedExecutionState[:active_support_subscriber_queue_registry] ||= {}
160
+ registry[@queue_key] ||= []
156
161
  end
157
162
  end
158
-
159
- # This is a registry for all the event stacks kept for subscribers.
160
- #
161
- # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
162
- # for further details.
163
- class SubscriberQueueRegistry # :nodoc:
164
- extend PerThreadRegistry
165
-
166
- def initialize
167
- @registry = {}
168
- end
169
-
170
- def get_queue(queue_key)
171
- @registry[queue_key] ||= []
172
- end
173
- end
174
163
  end
@@ -57,7 +57,7 @@ module ActiveSupport
57
57
  def current_tags
58
58
  # We use our object ID here to avoid conflicting with other instances
59
59
  thread_key = @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
60
- Thread.current[thread_key] ||= []
60
+ IsolatedExecutionState[thread_key] ||= []
61
61
  end
62
62
 
63
63
  def tags_text
@@ -79,7 +79,7 @@ module ActiveSupport
79
79
  end
80
80
 
81
81
  def self.new(logger)
82
- logger = logger.dup
82
+ logger = logger.clone
83
83
 
84
84
  if logger.formatter
85
85
  logger.formatter = logger.formatter.dup
@@ -12,6 +12,7 @@ require "active_support/testing/constant_lookup"
12
12
  require "active_support/testing/time_helpers"
13
13
  require "active_support/testing/file_fixtures"
14
14
  require "active_support/testing/parallelization"
15
+ require "active_support/testing/parallelize_executor"
15
16
  require "concurrent/utility/processor_counter"
16
17
 
17
18
  module ActiveSupport
@@ -71,26 +72,17 @@ module ActiveSupport
71
72
  #
72
73
  # The threaded parallelization uses minitest's parallel executor directly.
73
74
  # The processes parallelization uses a Ruby DRb server.
74
- def parallelize(workers: :number_of_processors, with: :processes)
75
+ #
76
+ # Because parallelization presents an overhead, it is only enabled when the
77
+ # number of tests to run is above the +threshold+ param. The default value is
78
+ # 50, and it's configurable via +config.active_support.test_parallelization_threshold+.
79
+ def parallelize(workers: :number_of_processors, with: :processes, threshold: ActiveSupport.test_parallelization_threshold)
75
80
  workers = Concurrent.physical_processor_count if workers == :number_of_processors
76
81
  workers = ENV["PARALLEL_WORKERS"].to_i if ENV["PARALLEL_WORKERS"]
77
82
 
78
83
  return if workers <= 1
79
84
 
80
- executor = case with
81
- when :processes
82
- Testing::Parallelization.new(workers)
83
- when :threads
84
- Minitest::Parallel::Executor.new(workers)
85
- else
86
- raise ArgumentError, "#{with} is not a supported parallelization executor."
87
- end
88
-
89
- self.lock_threads = false if defined?(self.lock_threads) && with == :threads
90
-
91
- Minitest.parallel_executor = executor
92
-
93
- parallelize_me!
85
+ Minitest.parallel_executor = ActiveSupport::Testing::ParallelizeExecutor.new(size: workers, with: with, threshold: threshold)
94
86
  end
95
87
 
96
88
  # Set up hook for parallel testing. This can be used if you have multiple
@@ -107,9 +99,7 @@ module ActiveSupport
107
99
  # end
108
100
  # end
109
101
  def parallelize_setup(&block)
110
- ActiveSupport::Testing::Parallelization.after_fork_hook do |worker|
111
- yield worker
112
- end
102
+ ActiveSupport::Testing::Parallelization.after_fork_hook(&block)
113
103
  end
114
104
 
115
105
  # Clean up hook for parallel testing. This can be used to drop databases
@@ -126,9 +116,7 @@ module ActiveSupport
126
116
  # end
127
117
  # end
128
118
  def parallelize_teardown(&block)
129
- ActiveSupport::Testing::Parallelization.run_cleanup_hook do |worker|
130
- yield worker
131
- end
119
+ ActiveSupport::Testing::Parallelization.run_cleanup_hook(&block)
132
120
  end
133
121
  end
134
122
 
@@ -99,7 +99,7 @@ module ActiveSupport
99
99
  }
100
100
  before = exps.map(&:call)
101
101
 
102
- retval = assert_nothing_raised(&block)
102
+ retval = _assert_nothing_raised_or_warn("assert_difference", &block)
103
103
 
104
104
  expressions.zip(exps, before) do |(code, diff), exp, before_value|
105
105
  error = "#{code.inspect} didn't change by #{diff}"
@@ -176,7 +176,7 @@ module ActiveSupport
176
176
  exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
177
177
 
178
178
  before = exp.call
179
- retval = assert_nothing_raised(&block)
179
+ retval = _assert_nothing_raised_or_warn("assert_changes", &block)
180
180
 
181
181
  unless from == UNTRACKED
182
182
  error = "Expected change from #{from.inspect}"
@@ -189,7 +189,7 @@ module ActiveSupport
189
189
  error = "#{expression.inspect} didn't change"
190
190
  error = "#{error}. It was already #{to}" if before == to
191
191
  error = "#{message}.\n#{error}" if message
192
- assert_not_equal before, after, error
192
+ refute_equal before, after, error
193
193
 
194
194
  unless to == UNTRACKED
195
195
  error = "Expected change to #{to}\n"
@@ -207,16 +207,30 @@ module ActiveSupport
207
207
  # post :create, params: { status: { ok: true } }
208
208
  # end
209
209
  #
210
+ # Provide the optional keyword argument :from to specify the expected
211
+ # initial value.
212
+ #
213
+ # assert_no_changes -> { Status.all_good? }, from: true do
214
+ # post :create, params: { status: { ok: true } }
215
+ # end
216
+ #
210
217
  # An error message can be specified.
211
218
  #
212
219
  # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
213
220
  # post :create, params: { status: { ok: false } }
214
221
  # end
215
- def assert_no_changes(expression, message = nil, &block)
222
+ def assert_no_changes(expression, message = nil, from: UNTRACKED, &block)
216
223
  exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
217
224
 
218
225
  before = exp.call
219
- retval = assert_nothing_raised(&block)
226
+ retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)
227
+
228
+ unless from == UNTRACKED
229
+ error = "Expected initial value of #{from.inspect}"
230
+ error = "#{message}.\n#{error}" if message
231
+ assert from === before, error
232
+ end
233
+
220
234
  after = exp.call
221
235
 
222
236
  error = "#{expression.inspect} changed"
@@ -230,6 +244,22 @@ module ActiveSupport
230
244
 
231
245
  retval
232
246
  end
247
+
248
+ private
249
+ def _assert_nothing_raised_or_warn(assertion, &block)
250
+ assert_nothing_raised(&block)
251
+ rescue Minitest::UnexpectedError => e
252
+ if tagged_logger && tagged_logger.warn?
253
+ warning = <<~MSG
254
+ #{self.class} - #{name}: #{e.error.class} raised.
255
+ If you expected this exception, use `assert_raises` as near to the code that raises as possible.
256
+ Other block based assertions (e.g. `#{assertion}`) can be used, as long as `assert_raises` is inside their block.
257
+ MSG
258
+ tagged_logger.warn warning
259
+ end
260
+
261
+ raise
262
+ end
233
263
  end
234
264
  end
235
265
  end
@@ -4,7 +4,30 @@ require "active_support/deprecation"
4
4
 
5
5
  module ActiveSupport
6
6
  module Testing
7
- module Deprecation #:nodoc:
7
+ module Deprecation
8
+ # Asserts that a matching deprecation warning was emitted by the given deprecator during the execution of the yielded block.
9
+ #
10
+ # assert_deprecated(/foo/, CustomDeprecator) do
11
+ # CustomDeprecator.warn "foo should no longer be used"
12
+ # end
13
+ #
14
+ # The +match+ object may be a +Regexp+, or +String+ appearing in the message.
15
+ #
16
+ # assert_deprecated('foo', CustomDeprecator) do
17
+ # CustomDeprecator.warn "foo should no longer be used"
18
+ # end
19
+ #
20
+ # If the +match+ is omitted (or explicitly +nil+), any deprecation warning will match.
21
+ #
22
+ # assert_deprecated(nil, CustomDeprecator) do
23
+ # CustomDeprecator.warn "foo should no longer be used"
24
+ # end
25
+ #
26
+ # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
27
+ #
28
+ # assert_deprecated do
29
+ # ActiveSupport::Deprecation.warn "foo should no longer be used"
30
+ # end
8
31
  def assert_deprecated(match = nil, deprecator = nil, &block)
9
32
  result, warnings = collect_deprecations(deprecator, &block)
10
33
  assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
@@ -15,12 +38,40 @@ module ActiveSupport
15
38
  result
16
39
  end
17
40
 
41
+ # Asserts that no deprecation warnings are emitted by the given deprecator during the execution of the yielded block.
42
+ #
43
+ # assert_not_deprecated(CustomDeprecator) do
44
+ # CustomDeprecator.warn "message" # fails assertion
45
+ # end
46
+ #
47
+ # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
48
+ #
49
+ # assert_not_deprecated do
50
+ # ActiveSupport::Deprecation.warn "message" # fails assertion
51
+ # end
52
+ #
53
+ # assert_not_deprecated do
54
+ # CustomDeprecator.warn "message" # passes assertion
55
+ # end
18
56
  def assert_not_deprecated(deprecator = nil, &block)
19
57
  result, deprecations = collect_deprecations(deprecator, &block)
20
58
  assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
21
59
  result
22
60
  end
23
61
 
62
+ # Returns an array of all the deprecation warnings emitted by the given
63
+ # +deprecator+ during the execution of the yielded block.
64
+ #
65
+ # collect_deprecations(CustomDeprecator) do
66
+ # CustomDeprecator.warn "message"
67
+ # end # => ["message"]
68
+ #
69
+ # If no +deprecator+ is given, defaults to ActiveSupport::Deprecation.
70
+ #
71
+ # collect_deprecations do
72
+ # CustomDeprecator.warn "custom message"
73
+ # ActiveSupport::Deprecation.warn "message"
74
+ # end # => ["message"]
24
75
  def collect_deprecations(deprecator = nil)
25
76
  deprecator ||= ActiveSupport::Deprecation
26
77
  old_behavior = deprecator.behavior
@@ -5,7 +5,7 @@ module ActiveSupport
5
5
  module Isolation
6
6
  require "thread"
7
7
 
8
- def self.included(klass) #:nodoc:
8
+ def self.included(klass) # :nodoc:
9
9
  klass.class_eval do
10
10
  parallelize_me!
11
11
  end
@@ -63,7 +63,7 @@ module ActiveSupport
63
63
  module Subprocess
64
64
  ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
65
65
 
66
- # Crazy H4X to get this working in windows / jruby with
66
+ # Complicated H4X to get this working in windows / jruby with
67
67
  # no forking.
68
68
  def run_in_isolation(&blk)
69
69
  require "tempfile"