activesupport 6.1.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +214 -382
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/benchmarkable.rb +2 -2
  8. data/lib/active_support/cache/file_store.rb +16 -10
  9. data/lib/active_support/cache/mem_cache_store.rb +133 -34
  10. data/lib/active_support/cache/memory_store.rb +23 -15
  11. data/lib/active_support/cache/null_store.rb +10 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +42 -67
  13. data/lib/active_support/cache/strategy/local_cache.rb +35 -61
  14. data/lib/active_support/cache.rb +196 -46
  15. data/lib/active_support/callbacks.rb +180 -81
  16. data/lib/active_support/code_generator.rb +65 -0
  17. data/lib/active_support/concern.rb +5 -5
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  19. data/lib/active_support/concurrency/share_lock.rb +2 -2
  20. data/lib/active_support/configurable.rb +6 -3
  21. data/lib/active_support/configuration_file.rb +7 -2
  22. data/lib/active_support/core_ext/array/access.rb +1 -5
  23. data/lib/active_support/core_ext/array/conversions.rb +9 -7
  24. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  25. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  26. data/lib/active_support/core_ext/array.rb +1 -0
  27. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +4 -2
  29. data/lib/active_support/core_ext/date/blank.rb +1 -1
  30. data/lib/active_support/core_ext/date/calculations.rb +4 -4
  31. data/lib/active_support/core_ext/date/conversions.rb +3 -3
  32. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  33. data/lib/active_support/core_ext/date.rb +1 -0
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  35. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
  37. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  38. data/lib/active_support/core_ext/date_time.rb +1 -0
  39. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  40. data/lib/active_support/core_ext/enumerable.rb +64 -12
  41. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  42. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  43. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  44. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  45. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  46. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  47. data/lib/active_support/core_ext/name_error.rb +2 -8
  48. data/lib/active_support/core_ext/numeric/conversions.rb +79 -76
  49. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  50. data/lib/active_support/core_ext/numeric.rb +1 -0
  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 +36 -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 +61 -37
  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 -5
  71. data/lib/active_support/core_ext/time/conversions.rb +5 -3
  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 +2 -1
  77. data/lib/active_support/current_attributes.rb +32 -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 +177 -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 +11 -1
  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 +30 -4
  98. data/lib/active_support/executor/test_helper.rb +7 -0
  99. data/lib/active_support/fork_tracker.rb +19 -10
  100. data/lib/active_support/gem_version.rb +2 -2
  101. data/lib/active_support/hash_with_indifferent_access.rb +9 -2
  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 +56 -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 +2 -2
  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 +16 -22
  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/number_to_rounded_converter.rb +10 -6
  128. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  129. data/lib/active_support/number_helper.rb +0 -2
  130. data/lib/active_support/option_merger.rb +8 -16
  131. data/lib/active_support/ordered_hash.rb +1 -1
  132. data/lib/active_support/parameter_filter.rb +6 -1
  133. data/lib/active_support/per_thread_registry.rb +5 -0
  134. data/lib/active_support/railtie.rb +69 -19
  135. data/lib/active_support/rescuable.rb +6 -6
  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/security_utils.rb +1 -1
  139. data/lib/active_support/string_inquirer.rb +0 -2
  140. data/lib/active_support/subscriber.rb +7 -18
  141. data/lib/active_support/tagged_logging.rb +2 -2
  142. data/lib/active_support/test_case.rb +9 -21
  143. data/lib/active_support/testing/assertions.rb +35 -5
  144. data/lib/active_support/testing/deprecation.rb +52 -1
  145. data/lib/active_support/testing/isolation.rb +2 -2
  146. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  147. data/lib/active_support/testing/parallelization/server.rb +4 -0
  148. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  149. data/lib/active_support/testing/parallelization.rb +4 -0
  150. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  151. data/lib/active_support/testing/stream.rb +3 -5
  152. data/lib/active_support/testing/tagged_logging.rb +1 -1
  153. data/lib/active_support/testing/time_helpers.rb +13 -2
  154. data/lib/active_support/time_with_zone.rb +54 -13
  155. data/lib/active_support/values/time_zone.rb +31 -10
  156. data/lib/active_support/xml_mini/jdom.rb +1 -1
  157. data/lib/active_support/xml_mini/libxml.rb +5 -5
  158. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  159. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  160. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  161. data/lib/active_support/xml_mini/rexml.rb +1 -1
  162. data/lib/active_support/xml_mini.rb +5 -4
  163. data/lib/active_support.rb +17 -1
  164. metadata +26 -23
  165. data/lib/active_support/core_ext/marshal.rb +0 -26
  166. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -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"} }
@@ -33,7 +38,7 @@ module ActiveSupport
33
38
  #
34
39
  # ==== Options
35
40
  #
36
- # * <tt>:mask</tt> - A replaced object when filtered. Defaults to +"[FILTERED]"+
41
+ # * <tt>:mask</tt> - A replaced object when filtered. Defaults to <tt>"[FILTERED]"</tt>.
37
42
  def initialize(filters = [], mask: FILTERED)
38
43
  @filters = filters
39
44
  @mask = mask
@@ -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
@@ -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.
@@ -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|
@@ -31,7 +31,7 @@ module ActiveSupport
31
31
  # the secret length. This should be considered when using secure_compare
32
32
  # to compare weak, short secrets to user input.
33
33
  def secure_compare(a, b)
34
- a.length == b.length && fixed_length_secure_compare(a, b)
34
+ a.bytesize == b.bytesize && fixed_length_secure_compare(a, b)
35
35
  end
36
36
  module_function :secure_compare
37
37
  end
@@ -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"
@@ -6,10 +6,10 @@ module ActiveSupport
6
6
  module Testing
7
7
  module MethodCallAssertions # :nodoc:
8
8
  private
9
- def assert_called(object, method_name, message = nil, times: 1, returns: nil)
9
+ def assert_called(object, method_name, message = nil, times: 1, returns: nil, &block)
10
10
  times_called = 0
11
11
 
12
- object.stub(method_name, proc { times_called += 1; returns }) { yield }
12
+ object.stub(method_name, proc { times_called += 1; returns }, &block)
13
13
 
14
14
  error = "Expected #{method_name} to be called #{times} times, " \
15
15
  "but was called #{times_called} times"
@@ -17,16 +17,16 @@ module ActiveSupport
17
17
  assert_equal times, times_called, error
18
18
  end
19
19
 
20
- def assert_called_with(object, method_name, args, returns: nil)
20
+ def assert_called_with(object, method_name, args, returns: nil, &block)
21
21
  mock = Minitest::Mock.new
22
22
 
23
- if args.all? { |arg| arg.is_a?(Array) }
23
+ if args.all?(Array)
24
24
  args.each { |arg| mock.expect(:call, returns, arg) }
25
25
  else
26
26
  mock.expect(:call, returns, args)
27
27
  end
28
28
 
29
- object.stub(method_name, mock) { yield }
29
+ object.stub(method_name, mock, &block)
30
30
 
31
31
  mock.verify
32
32
  end
@@ -49,6 +49,10 @@ module ActiveSupport
49
49
  @active_workers.size > 0
50
50
  end
51
51
 
52
+ def interrupt
53
+ @queue.clear
54
+ end
55
+
52
56
  def shutdown
53
57
  # Wait for initial queue to drain
54
58
  while @queue.length != 0
@@ -69,6 +69,9 @@ module ActiveSupport
69
69
  Minitest::UnexpectedError.new(error)
70
70
  end
71
71
  @queue.record(reporter, result)
72
+ rescue Interrupt
73
+ @queue.interrupt
74
+ raise
72
75
  end
73
76
 
74
77
  set_process_title("(idle)")