activesupport 6.0.6 → 7.0.1

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 (204) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +224 -608
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +2 -2
  6. data/lib/active_support/backtrace_cleaner.rb +3 -3
  7. data/lib/active_support/benchmarkable.rb +3 -3
  8. data/lib/active_support/cache/file_store.rb +16 -10
  9. data/lib/active_support/cache/mem_cache_store.rb +143 -38
  10. data/lib/active_support/cache/memory_store.rb +56 -28
  11. data/lib/active_support/cache/null_store.rb +10 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +62 -87
  13. data/lib/active_support/cache/strategy/local_cache.rb +46 -57
  14. data/lib/active_support/cache.rb +268 -77
  15. data/lib/active_support/callbacks.rb +226 -118
  16. data/lib/active_support/code_generator.rb +65 -0
  17. data/lib/active_support/concern.rb +49 -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 +9 -6
  21. data/lib/active_support/configuration_file.rb +51 -0
  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/benchmark.rb +2 -2
  28. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  29. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  30. data/lib/active_support/core_ext/class/subclasses.rb +11 -24
  31. data/lib/active_support/core_ext/date/blank.rb +1 -1
  32. data/lib/active_support/core_ext/date/calculations.rb +4 -4
  33. data/lib/active_support/core_ext/date/conversions.rb +5 -4
  34. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  35. data/lib/active_support/core_ext/date.rb +1 -0
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  38. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  39. data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
  40. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  41. data/lib/active_support/core_ext/date_time.rb +1 -0
  42. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  43. data/lib/active_support/core_ext/enumerable.rb +139 -15
  44. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  45. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  46. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  47. data/lib/active_support/core_ext/hash/keys.rb +2 -2
  48. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  49. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  50. data/lib/active_support/core_ext/load_error.rb +1 -1
  51. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  52. data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
  53. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
  54. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  55. data/lib/active_support/core_ext/module/delegation.rb +40 -36
  56. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  57. data/lib/active_support/core_ext/name_error.rb +23 -2
  58. data/lib/active_support/core_ext/numeric/conversions.rb +79 -72
  59. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  60. data/lib/active_support/core_ext/numeric.rb +1 -0
  61. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  62. data/lib/active_support/core_ext/object/blank.rb +2 -2
  63. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  64. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  65. data/lib/active_support/core_ext/object/json.rb +41 -25
  66. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  67. data/lib/active_support/core_ext/object/try.rb +20 -20
  68. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  69. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  70. data/lib/active_support/core_ext/pathname.rb +3 -0
  71. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  72. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  73. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  74. data/lib/active_support/core_ext/range/each.rb +1 -1
  75. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
  76. data/lib/active_support/core_ext/range.rb +1 -1
  77. data/lib/active_support/core_ext/regexp.rb +8 -1
  78. data/lib/active_support/core_ext/string/access.rb +5 -24
  79. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  80. data/lib/active_support/core_ext/string/filters.rb +1 -1
  81. data/lib/active_support/core_ext/string/inflections.rb +39 -5
  82. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  83. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  84. data/lib/active_support/core_ext/string/output_safety.rb +62 -67
  85. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  86. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  87. data/lib/active_support/core_ext/symbol.rb +3 -0
  88. data/lib/active_support/core_ext/time/calculations.rb +23 -5
  89. data/lib/active_support/core_ext/time/conversions.rb +6 -3
  90. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  91. data/lib/active_support/core_ext/time/zones.rb +4 -19
  92. data/lib/active_support/core_ext/time.rb +1 -0
  93. data/lib/active_support/core_ext/uri.rb +3 -23
  94. data/lib/active_support/core_ext.rb +2 -1
  95. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  96. data/lib/active_support/current_attributes.rb +39 -16
  97. data/lib/active_support/dependencies/interlock.rb +10 -18
  98. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  99. data/lib/active_support/dependencies.rb +58 -769
  100. data/lib/active_support/deprecation/behaviors.rb +19 -3
  101. data/lib/active_support/deprecation/disallowed.rb +56 -0
  102. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  103. data/lib/active_support/deprecation/method_wrappers.rb +6 -5
  104. data/lib/active_support/deprecation/proxy_wrappers.rb +3 -3
  105. data/lib/active_support/deprecation/reporting.rb +50 -7
  106. data/lib/active_support/deprecation.rb +6 -1
  107. data/lib/active_support/descendants_tracker.rb +174 -64
  108. data/lib/active_support/digest.rb +5 -3
  109. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  110. data/lib/active_support/duration/iso8601_serializer.rb +24 -10
  111. data/lib/active_support/duration.rb +134 -55
  112. data/lib/active_support/encrypted_configuration.rb +11 -1
  113. data/lib/active_support/encrypted_file.rb +20 -3
  114. data/lib/active_support/environment_inquirer.rb +20 -0
  115. data/lib/active_support/error_reporter.rb +117 -0
  116. data/lib/active_support/evented_file_update_checker.rb +70 -134
  117. data/lib/active_support/execution_context/test_helper.rb +13 -0
  118. data/lib/active_support/execution_context.rb +53 -0
  119. data/lib/active_support/execution_wrapper.rb +41 -18
  120. data/lib/active_support/executor/test_helper.rb +7 -0
  121. data/lib/active_support/fork_tracker.rb +71 -0
  122. data/lib/active_support/gem_version.rb +2 -2
  123. data/lib/active_support/hash_with_indifferent_access.rb +51 -25
  124. data/lib/active_support/html_safe_translation.rb +43 -0
  125. data/lib/active_support/i18n.rb +1 -0
  126. data/lib/active_support/i18n_railtie.rb +14 -19
  127. data/lib/active_support/inflector/inflections.rb +24 -9
  128. data/lib/active_support/inflector/methods.rb +29 -49
  129. data/lib/active_support/inflector/transliterate.rb +4 -4
  130. data/lib/active_support/isolated_execution_state.rb +56 -0
  131. data/lib/active_support/json/decoding.rb +4 -4
  132. data/lib/active_support/json/encoding.rb +8 -4
  133. data/lib/active_support/key_generator.rb +19 -2
  134. data/lib/active_support/locale/en.yml +8 -4
  135. data/lib/active_support/log_subscriber.rb +21 -3
  136. data/lib/active_support/logger.rb +1 -1
  137. data/lib/active_support/logger_silence.rb +2 -26
  138. data/lib/active_support/logger_thread_safe_level.rb +34 -21
  139. data/lib/active_support/message_encryptor.rb +12 -10
  140. data/lib/active_support/message_verifier.rb +50 -18
  141. data/lib/active_support/messages/metadata.rb +2 -2
  142. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  143. data/lib/active_support/messages/rotator.rb +6 -5
  144. data/lib/active_support/multibyte/chars.rb +13 -52
  145. data/lib/active_support/multibyte/unicode.rb +1 -87
  146. data/lib/active_support/multibyte.rb +1 -1
  147. data/lib/active_support/notifications/fanout.rb +110 -69
  148. data/lib/active_support/notifications/instrumenter.rb +37 -29
  149. data/lib/active_support/notifications.rb +47 -26
  150. data/lib/active_support/number_helper/number_converter.rb +2 -4
  151. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  152. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  153. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  154. data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
  155. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  156. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  157. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  158. data/lib/active_support/number_helper.rb +29 -16
  159. data/lib/active_support/option_merger.rb +9 -16
  160. data/lib/active_support/ordered_hash.rb +1 -1
  161. data/lib/active_support/ordered_options.rb +8 -2
  162. data/lib/active_support/parameter_filter.rb +21 -11
  163. data/lib/active_support/per_thread_registry.rb +6 -1
  164. data/lib/active_support/rails.rb +1 -4
  165. data/lib/active_support/railtie.rb +77 -5
  166. data/lib/active_support/reloader.rb +1 -1
  167. data/lib/active_support/rescuable.rb +6 -6
  168. data/lib/active_support/ruby_features.rb +7 -0
  169. data/lib/active_support/secure_compare_rotator.rb +51 -0
  170. data/lib/active_support/security_utils.rb +19 -12
  171. data/lib/active_support/string_inquirer.rb +2 -2
  172. data/lib/active_support/subscriber.rb +19 -25
  173. data/lib/active_support/tagged_logging.rb +31 -6
  174. data/lib/active_support/test_case.rb +9 -21
  175. data/lib/active_support/testing/assertions.rb +49 -12
  176. data/lib/active_support/testing/deprecation.rb +52 -1
  177. data/lib/active_support/testing/isolation.rb +2 -2
  178. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  179. data/lib/active_support/testing/parallelization/server.rb +82 -0
  180. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  181. data/lib/active_support/testing/parallelization.rb +16 -95
  182. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  183. data/lib/active_support/testing/stream.rb +3 -5
  184. data/lib/active_support/testing/tagged_logging.rb +1 -1
  185. data/lib/active_support/testing/time_helpers.rb +53 -5
  186. data/lib/active_support/time_with_zone.rb +120 -55
  187. data/lib/active_support/values/time_zone.rb +49 -18
  188. data/lib/active_support/xml_mini/jdom.rb +1 -1
  189. data/lib/active_support/xml_mini/libxml.rb +5 -5
  190. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  191. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  192. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  193. data/lib/active_support/xml_mini/rexml.rb +9 -2
  194. data/lib/active_support/xml_mini.rb +5 -4
  195. data/lib/active_support.rb +29 -1
  196. metadata +45 -45
  197. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  198. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  199. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  200. data/lib/active_support/core_ext/marshal.rb +0 -24
  201. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  202. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  203. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  204. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -51,10 +51,10 @@ module ActiveSupport
51
51
  # constant. Available behaviors are:
52
52
  #
53
53
  # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
54
- # [+stderr+] Log all deprecation warnings to +$stderr+.
54
+ # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
55
55
  # [+log+] Log all deprecation warnings to +Rails.logger+.
56
56
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
57
- # [+silence+] Do nothing.
57
+ # [+silence+] Do nothing. On Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
58
58
  #
59
59
  # Setting behaviors only affects deprecations that happen after boot time.
60
60
  # For more information you can read the documentation of the +behavior=+ method.
@@ -67,13 +67,18 @@ module ActiveSupport
67
67
  @behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
68
68
  end
69
69
 
70
+ # Returns the current behavior for disallowed deprecations or if one isn't set, defaults to +:raise+.
71
+ def disallowed_behavior
72
+ @disallowed_behavior ||= [DEFAULT_BEHAVIORS[:raise]]
73
+ end
74
+
70
75
  # Sets the behavior to the specified value. Can be a single value, array,
71
76
  # or an object that responds to +call+.
72
77
  #
73
78
  # Available behaviors:
74
79
  #
75
80
  # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
76
- # [+stderr+] Log all deprecation warnings to +$stderr+.
81
+ # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
77
82
  # [+log+] Log all deprecation warnings to +Rails.logger+.
78
83
  # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
79
84
  # [+silence+] Do nothing.
@@ -88,10 +93,21 @@ module ActiveSupport
88
93
  # ActiveSupport::Deprecation.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
89
94
  # # custom stuff
90
95
  # }
96
+ #
97
+ # If you are using Rails, you can set <tt>config.active_support.report_deprecations = false</tt> to disable
98
+ # all deprecation behaviors. This is similar to the +silence+ option but more performant.
91
99
  def behavior=(behavior)
92
100
  @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
93
101
  end
94
102
 
103
+ # Sets the behavior for disallowed deprecations (those configured by
104
+ # ActiveSupport::Deprecation.disallowed_warnings=) to the specified
105
+ # value. As with +behavior=+, this can be a single value, array, or an
106
+ # object that responds to +call+.
107
+ def disallowed_behavior=(behavior)
108
+ @disallowed_behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
109
+ end
110
+
95
111
  private
96
112
  def arity_coerce(behavior)
97
113
  unless behavior.respond_to?(:call)
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ class Deprecation
5
+ module Disallowed
6
+ # Sets the criteria used to identify deprecation messages which should be
7
+ # disallowed. Can be an array containing strings, symbols, or regular
8
+ # expressions. (Symbols are treated as strings). These are compared against
9
+ # the text of the generated deprecation warning.
10
+ #
11
+ # Additionally the scalar symbol +:all+ may be used to treat all
12
+ # deprecations as disallowed.
13
+ #
14
+ # Deprecations matching a substring or regular expression will be handled
15
+ # using the configured +ActiveSupport::Deprecation.disallowed_behavior+
16
+ # rather than +ActiveSupport::Deprecation.behavior+
17
+ attr_writer :disallowed_warnings
18
+
19
+ # Returns the configured criteria used to identify deprecation messages
20
+ # which should be treated as disallowed.
21
+ def disallowed_warnings
22
+ @disallowed_warnings ||= []
23
+ end
24
+
25
+ private
26
+ def deprecation_disallowed?(message)
27
+ disallowed = ActiveSupport::Deprecation.disallowed_warnings
28
+ return false if explicitly_allowed?(message)
29
+ return true if disallowed == :all
30
+ disallowed.any? do |rule|
31
+ case rule
32
+ when String, Symbol
33
+ message.include?(rule.to_s)
34
+ when Regexp
35
+ rule.match?(message)
36
+ end
37
+ end
38
+ end
39
+
40
+ def explicitly_allowed?(message)
41
+ allowances = @explicitly_allowed_warnings.value
42
+ return false unless allowances
43
+ return true if allowances == :all
44
+ allowances = [allowances] unless allowances.kind_of?(Array)
45
+ allowances.any? do |rule|
46
+ case rule
47
+ when String, Symbol
48
+ message.include?(rule.to_s)
49
+ when Regexp
50
+ rule.match?(message)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/kernel/singleton_class"
4
3
  require "active_support/core_ext/module/delegation"
5
4
 
6
5
  module ActiveSupport
@@ -56,23 +56,24 @@ module ActiveSupport
56
56
  mod = nil
57
57
 
58
58
  method_names.each do |method_name|
59
+ message = options[method_name]
59
60
  if target_module.method_defined?(method_name) || target_module.private_method_defined?(method_name)
60
61
  method = target_module.instance_method(method_name)
61
62
  target_module.module_eval do
62
63
  redefine_method(method_name) do |*args, &block|
63
- deprecator.deprecation_warning(method_name, options[method_name])
64
- method.bind(self).call(*args, &block)
64
+ deprecator.deprecation_warning(method_name, message)
65
+ method.bind_call(self, *args, &block)
65
66
  end
66
- ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
67
+ ruby2_keywords(method_name)
67
68
  end
68
69
  else
69
70
  mod ||= Module.new
70
71
  mod.module_eval do
71
72
  define_method(method_name) do |*args, &block|
72
- deprecator.deprecation_warning(method_name, options[method_name])
73
+ deprecator.deprecation_warning(method_name, message)
73
74
  super(*args, &block)
74
75
  end
75
- ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
76
+ ruby2_keywords(method_name)
76
77
  end
77
78
  end
78
79
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveSupport
4
4
  class Deprecation
5
- class DeprecationProxy #:nodoc:
5
+ class DeprecationProxy # :nodoc:
6
6
  def self.new(*args, &block)
7
7
  object = args.first
8
8
 
@@ -121,7 +121,7 @@ module ActiveSupport
121
121
  # (Backtrace information…)
122
122
  # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
123
123
  class DeprecatedConstantProxy < Module
124
- def self.new(*args, **kwargs, &block)
124
+ def self.new(*args, **options, &block)
125
125
  object = args.first
126
126
 
127
127
  return object unless object
@@ -129,7 +129,7 @@ module ActiveSupport
129
129
  end
130
130
 
131
131
  def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
132
- require "active_support/inflector/methods"
132
+ Kernel.require "active_support/inflector/methods"
133
133
 
134
134
  @old_const = old_const
135
135
  @new_const = new_const
@@ -6,7 +6,7 @@ module ActiveSupport
6
6
  class Deprecation
7
7
  module Reporting
8
8
  # Whether to print a message (silent mode)
9
- attr_accessor :silenced
9
+ attr_writer :silenced
10
10
  # Name of gem where method is deprecated
11
11
  attr_accessor :gem_name
12
12
 
@@ -20,7 +20,11 @@ module ActiveSupport
20
20
 
21
21
  callstack ||= caller_locations(2)
22
22
  deprecation_message(callstack, message).tap do |m|
23
- behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
23
+ if deprecation_disallowed?(message)
24
+ disallowed_behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
25
+ else
26
+ behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
27
+ end
24
28
  end
25
29
  end
26
30
 
@@ -33,11 +37,50 @@ module ActiveSupport
33
37
  # ActiveSupport::Deprecation.warn('something broke!')
34
38
  # end
35
39
  # # => nil
36
- def silence
37
- old_silenced, @silenced = @silenced, true
38
- yield
39
- ensure
40
- @silenced = old_silenced
40
+ def silence(&block)
41
+ @silenced_thread.bind(true, &block)
42
+ end
43
+
44
+ # Allow previously disallowed deprecation warnings within the block.
45
+ # <tt>allowed_warnings</tt> can be an array containing strings, symbols, or regular
46
+ # expressions. (Symbols are treated as strings). These are compared against
47
+ # the text of deprecation warning messages generated within the block.
48
+ # Matching warnings will be exempt from the rules set by
49
+ # +ActiveSupport::Deprecation.disallowed_warnings+
50
+ #
51
+ # The optional <tt>if:</tt> argument accepts a truthy/falsy value or an object that
52
+ # responds to <tt>.call</tt>. If truthy, then matching warnings will be allowed.
53
+ # If falsey then the method yields to the block without allowing the warning.
54
+ #
55
+ # ActiveSupport::Deprecation.disallowed_behavior = :raise
56
+ # ActiveSupport::Deprecation.disallowed_warnings = [
57
+ # "something broke"
58
+ # ]
59
+ #
60
+ # ActiveSupport::Deprecation.warn('something broke!')
61
+ # # => ActiveSupport::DeprecationException
62
+ #
63
+ # ActiveSupport::Deprecation.allow ['something broke'] do
64
+ # ActiveSupport::Deprecation.warn('something broke!')
65
+ # end
66
+ # # => nil
67
+ #
68
+ # ActiveSupport::Deprecation.allow ['something broke'], if: Rails.env.production? do
69
+ # ActiveSupport::Deprecation.warn('something broke!')
70
+ # end
71
+ # # => ActiveSupport::DeprecationException for dev/test, nil for production
72
+ def allow(allowed_warnings = :all, if: true, &block)
73
+ conditional = binding.local_variable_get(:if)
74
+ conditional = conditional.call if conditional.respond_to?(:call)
75
+ if conditional
76
+ @explicitly_allowed_warnings.bind(allowed_warnings, &block)
77
+ else
78
+ yield
79
+ end
80
+ end
81
+
82
+ def silenced
83
+ @silenced || @silenced_thread.value
41
84
  end
42
85
 
43
86
  def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
@@ -17,15 +17,18 @@ module ActiveSupport
17
17
  require "active_support/deprecation/instance_delegator"
18
18
  require "active_support/deprecation/behaviors"
19
19
  require "active_support/deprecation/reporting"
20
+ require "active_support/deprecation/disallowed"
20
21
  require "active_support/deprecation/constant_accessor"
21
22
  require "active_support/deprecation/method_wrappers"
22
23
  require "active_support/deprecation/proxy_wrappers"
23
24
  require "active_support/core_ext/module/deprecation"
25
+ require "concurrent/atomic/thread_local_var"
24
26
 
25
27
  include Singleton
26
28
  include InstanceDelegator
27
29
  include Behavior
28
30
  include Reporting
31
+ include Disallowed
29
32
  include MethodWrapper
30
33
 
31
34
  # The version number in which the deprecated behavior will be removed, by default.
@@ -35,12 +38,14 @@ module ActiveSupport
35
38
  # and the second is a library name.
36
39
  #
37
40
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
38
- def initialize(deprecation_horizon = "6.1", gem_name = "Rails")
41
+ def initialize(deprecation_horizon = "7.1", gem_name = "Rails")
39
42
  self.gem_name = gem_name
40
43
  self.deprecation_horizon = deprecation_horizon
41
44
  # By default, warnings are not silenced and debugging is off.
42
45
  self.silenced = false
43
46
  self.debug = false
47
+ @silenced_thread = Concurrent::ThreadLocalVar.new(false)
48
+ @explicitly_allowed_warnings = Concurrent::ThreadLocalVar.new(nil)
44
49
  end
45
50
  end
46
51
  end
@@ -1,106 +1,216 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "weakref"
4
+ require "active_support/ruby_features"
4
5
 
5
6
  module ActiveSupport
6
7
  # This module provides an internal implementation to track descendants
7
8
  # which is faster than iterating through ObjectSpace.
8
9
  module DescendantsTracker
9
- @@direct_descendants = {}
10
-
11
10
  class << self
12
11
  def direct_descendants(klass)
13
- descendants = @@direct_descendants[klass]
14
- descendants ? descendants.to_a : []
12
+ ActiveSupport::Deprecation.warn(<<~MSG)
13
+ ActiveSupport::DescendantsTracker.direct_descendants is deprecated and will be removed in Rails 7.1.
14
+ Use ActiveSupport::DescendantsTracker.subclasses instead.
15
+ MSG
16
+ subclasses(klass)
15
17
  end
18
+ end
19
+
20
+ @clear_disabled = false
21
+
22
+ if RubyFeatures::CLASS_SUBCLASSES
23
+ @@excluded_descendants = if RUBY_ENGINE == "ruby"
24
+ # On MRI `ObjectSpace::WeakMap` keys are weak references.
25
+ # So we can simply use WeakMap as a `Set`.
26
+ ObjectSpace::WeakMap.new
27
+ else
28
+ # On TruffleRuby `ObjectSpace::WeakMap` keys are strong references.
29
+ # So we use `object_id` as a key and the actual object as a value.
30
+ #
31
+ # JRuby for now doesn't have Class#descendant, but when it will, it will likely
32
+ # have the same WeakMap semantic than Truffle so we future proof this as much as possible.
33
+ class WeakSet # :nodoc:
34
+ def initialize
35
+ @map = ObjectSpace::WeakMap.new
36
+ end
16
37
 
17
- def descendants(klass)
18
- arr = []
19
- accumulate_descendants(klass, arr)
20
- arr
38
+ def [](object)
39
+ @map.key?(object.object_id)
40
+ end
41
+
42
+ def []=(object, _present)
43
+ @map[object.object_id] = object
44
+ end
45
+ end
46
+ WeakSet.new
21
47
  end
22
48
 
23
- def clear
24
- if defined? ActiveSupport::Dependencies
25
- @@direct_descendants.each do |klass, descendants|
26
- if Dependencies.autoloaded?(klass)
27
- @@direct_descendants.delete(klass)
28
- else
29
- descendants.reject! { |v| Dependencies.autoloaded?(v) }
49
+ class << self
50
+ def disable_clear! # :nodoc:
51
+ unless @clear_disabled
52
+ @clear_disabled = true
53
+ remove_method(:subclasses)
54
+ @@excluded_descendants = nil
55
+ end
56
+ end
57
+
58
+ def subclasses(klass)
59
+ klass.subclasses
60
+ end
61
+
62
+ def descendants(klass)
63
+ klass.descendants
64
+ end
65
+
66
+ def clear(classes) # :nodoc:
67
+ raise "DescendantsTracker.clear was disabled because config.cache_classes = true" if @clear_disabled
68
+
69
+ classes.each do |klass|
70
+ @@excluded_descendants[klass] = true
71
+ klass.descendants.each do |descendant|
72
+ @@excluded_descendants[descendant] = true
30
73
  end
31
74
  end
32
- else
33
- @@direct_descendants.clear
34
75
  end
76
+
77
+ def native? # :nodoc:
78
+ true
79
+ end
80
+ end
81
+
82
+ def subclasses
83
+ subclasses = super
84
+ subclasses.reject! { |d| @@excluded_descendants[d] }
85
+ subclasses
35
86
  end
36
87
 
37
- # This is the only method that is not thread safe, but is only ever called
38
- # during the eager loading phase.
39
- def store_inherited(klass, descendant)
40
- (@@direct_descendants[klass] ||= DescendantsArray.new) << descendant
88
+ def descendants
89
+ subclasses.concat(subclasses.flat_map(&:descendants))
41
90
  end
42
91
 
43
- private
44
- def accumulate_descendants(klass, acc)
45
- if direct_descendants = @@direct_descendants[klass]
46
- direct_descendants.each do |direct_descendant|
47
- acc << direct_descendant
48
- accumulate_descendants(direct_descendant, acc)
92
+ def direct_descendants
93
+ ActiveSupport::Deprecation.warn(<<~MSG)
94
+ ActiveSupport::DescendantsTracker#direct_descendants is deprecated and will be removed in Rails 7.1.
95
+ Use #subclasses instead.
96
+ MSG
97
+ subclasses
98
+ end
99
+ else
100
+ @@direct_descendants = {}
101
+
102
+ class << self
103
+ def disable_clear! # :nodoc:
104
+ @clear_disabled = true
105
+ end
106
+
107
+ def subclasses(klass)
108
+ descendants = @@direct_descendants[klass]
109
+ descendants ? descendants.to_a : []
110
+ end
111
+
112
+ def descendants(klass)
113
+ arr = []
114
+ accumulate_descendants(klass, arr)
115
+ arr
116
+ end
117
+
118
+ def clear(classes) # :nodoc:
119
+ raise "DescendantsTracker.clear was disabled because config.cache_classes = true" if @clear_disabled
120
+
121
+ @@direct_descendants.each do |klass, direct_descendants_of_klass|
122
+ if classes.member?(klass)
123
+ @@direct_descendants.delete(klass)
124
+ else
125
+ direct_descendants_of_klass.reject! do |direct_descendant_of_class|
126
+ classes.member?(direct_descendant_of_class)
127
+ end
49
128
  end
50
129
  end
51
130
  end
52
- end
53
131
 
54
- def inherited(base)
55
- DescendantsTracker.store_inherited(self, base)
56
- super
57
- end
132
+ def native? # :nodoc:
133
+ false
134
+ end
58
135
 
59
- def direct_descendants
60
- DescendantsTracker.direct_descendants(self)
61
- end
136
+ # This is the only method that is not thread safe, but is only ever called
137
+ # during the eager loading phase.
138
+ def store_inherited(klass, descendant)
139
+ (@@direct_descendants[klass] ||= DescendantsArray.new) << descendant
140
+ end
62
141
 
63
- def descendants
64
- DescendantsTracker.descendants(self)
65
- end
142
+ private
143
+ def accumulate_descendants(klass, acc)
144
+ if direct_descendants = @@direct_descendants[klass]
145
+ direct_descendants.each do |direct_descendant|
146
+ acc << direct_descendant
147
+ accumulate_descendants(direct_descendant, acc)
148
+ end
149
+ end
150
+ end
151
+ end
66
152
 
67
- # DescendantsArray is an array that contains weak references to classes.
68
- class DescendantsArray # :nodoc:
69
- include Enumerable
153
+ def inherited(base)
154
+ DescendantsTracker.store_inherited(self, base)
155
+ super
156
+ end
70
157
 
71
- def initialize
72
- @refs = []
158
+ def direct_descendants
159
+ ActiveSupport::Deprecation.warn(<<~MSG)
160
+ ActiveSupport::DescendantsTracker#direct_descendants is deprecated and will be removed in Rails 7.1.
161
+ Use #subclasses instead.
162
+ MSG
163
+ DescendantsTracker.subclasses(self)
73
164
  end
74
165
 
75
- def initialize_copy(orig)
76
- @refs = @refs.dup
166
+ def subclasses
167
+ DescendantsTracker.subclasses(self)
77
168
  end
78
169
 
79
- def <<(klass)
80
- cleanup!
81
- @refs << WeakRef.new(klass)
170
+ def descendants
171
+ DescendantsTracker.descendants(self)
82
172
  end
83
173
 
84
- def each
85
- @refs.each do |ref|
86
- yield ref.__getobj__
87
- rescue WeakRef::RefError
174
+ # DescendantsArray is an array that contains weak references to classes.
175
+ class DescendantsArray # :nodoc:
176
+ include Enumerable
177
+
178
+ def initialize
179
+ @refs = []
88
180
  end
89
- end
90
181
 
91
- def refs_size
92
- @refs.size
93
- end
182
+ def initialize_copy(orig)
183
+ @refs = @refs.dup
184
+ end
94
185
 
95
- def cleanup!
96
- @refs.delete_if { |ref| !ref.weakref_alive? }
97
- end
186
+ def <<(klass)
187
+ @refs << WeakRef.new(klass)
188
+ end
98
189
 
99
- def reject!
100
- @refs.reject! do |ref|
101
- yield ref.__getobj__
102
- rescue WeakRef::RefError
103
- true
190
+ def each
191
+ @refs.reject! do |ref|
192
+ yield ref.__getobj__
193
+ false
194
+ rescue WeakRef::RefError
195
+ true
196
+ end
197
+ self
198
+ end
199
+
200
+ def refs_size
201
+ @refs.size
202
+ end
203
+
204
+ def cleanup!
205
+ @refs.delete_if { |ref| !ref.weakref_alive? }
206
+ end
207
+
208
+ def reject!
209
+ @refs.reject! do |ref|
210
+ yield ref.__getobj__
211
+ rescue WeakRef::RefError
212
+ true
213
+ end
104
214
  end
105
215
  end
106
216
  end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "openssl"
4
+
3
5
  module ActiveSupport
4
- class Digest #:nodoc:
5
- class <<self
6
+ class Digest # :nodoc:
7
+ class << self
6
8
  def hash_digest_class
7
- @hash_digest_class ||= ::Digest::MD5
9
+ @hash_digest_class ||= OpenSSL::Digest::MD5
8
10
  end
9
11
 
10
12
  def hash_digest_class=(klass)
@@ -16,11 +16,11 @@ module ActiveSupport
16
16
  PERIOD = "."
17
17
  COMMA = ","
18
18
 
19
- SIGN_MARKER = /\A\-|\+|/
19
+ SIGN_MARKER = /\A-|\+|/
20
20
  DATE_MARKER = /P/
21
21
  TIME_MARKER = /T/
22
- DATE_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(Y|M|D|W)/
23
- TIME_COMPONENT = /(\-?\d+(?:[.,]\d+)?)(H|M|S)/
22
+ DATE_COMPONENT = /(-?\d+(?:[.,]\d+)?)(Y|M|D|W)/
23
+ TIME_COMPONENT = /(-?\d+(?:[.,]\d+)?)(H|M|S)/
24
24
 
25
25
  DATE_TO_PART = { "Y" => :years, "M" => :months, "W" => :weeks, "D" => :days }
26
26
  TIME_TO_PART = { "H" => :hours, "M" => :minutes, "S" => :seconds }
@@ -6,6 +6,8 @@ module ActiveSupport
6
6
  class Duration
7
7
  # Serializes duration to string according to ISO 8601 Duration format.
8
8
  class ISO8601Serializer # :nodoc:
9
+ DATE_COMPONENTS = %i(years months days)
10
+
9
11
  def initialize(duration, precision: nil)
10
12
  @duration = duration
11
13
  @precision = precision
@@ -13,22 +15,22 @@ module ActiveSupport
13
15
 
14
16
  # Builds and returns output string.
15
17
  def serialize
16
- parts, sign = normalize
18
+ parts = normalize
17
19
  return "PT0S" if parts.empty?
18
20
 
19
21
  output = +"P"
20
22
  output << "#{parts[:years]}Y" if parts.key?(:years)
21
23
  output << "#{parts[:months]}M" if parts.key?(:months)
22
- output << "#{parts[:weeks]}W" if parts.key?(:weeks)
23
24
  output << "#{parts[:days]}D" if parts.key?(:days)
25
+ output << "#{parts[:weeks]}W" if parts.key?(:weeks)
24
26
  time = +""
25
27
  time << "#{parts[:hours]}H" if parts.key?(:hours)
26
28
  time << "#{parts[:minutes]}M" if parts.key?(:minutes)
27
29
  if parts.key?(:seconds)
28
- time << "#{sprintf(@precision ? "%0.0#{@precision}f" : '%g', parts[:seconds])}S"
30
+ time << "#{format_seconds(parts[:seconds])}S"
29
31
  end
30
32
  output << "T#{time}" unless time.empty?
31
- "#{sign}#{output}"
33
+ output
32
34
  end
33
35
 
34
36
  private
@@ -40,13 +42,25 @@ module ActiveSupport
40
42
  parts = @duration.parts.each_with_object(Hash.new(0)) do |(k, v), p|
41
43
  p[k] += v unless v.zero?
42
44
  end
43
- # If all parts are negative - let's make a negative duration
44
- sign = ""
45
- if parts.values.all? { |v| v < 0 }
46
- sign = "-"
47
- parts.transform_values!(&:-@)
45
+
46
+ # Convert weeks to days and remove weeks if mixed with date parts
47
+ if week_mixed_with_date?(parts)
48
+ parts[:days] += parts.delete(:weeks) * SECONDS_PER_WEEK / SECONDS_PER_DAY
49
+ end
50
+
51
+ parts
52
+ end
53
+
54
+ def week_mixed_with_date?(parts)
55
+ parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
56
+ end
57
+
58
+ def format_seconds(seconds)
59
+ if @precision
60
+ sprintf("%0.0#{@precision}f", seconds)
61
+ else
62
+ seconds.to_s
48
63
  end
49
- [parts, sign]
50
64
  end
51
65
  end
52
66
  end