activesupport 7.0.8.7 → 7.2.2.1

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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +143 -459
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +3 -1
  7. data/lib/active_support/backtrace_cleaner.rb +39 -7
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +251 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +49 -17
  14. data/lib/active_support/cache/mem_cache_store.rb +94 -128
  15. data/lib/active_support/cache/memory_store.rb +80 -25
  16. data/lib/active_support/cache/null_store.rb +6 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +165 -152
  18. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +29 -14
  20. data/lib/active_support/cache.rb +363 -291
  21. data/lib/active_support/callbacks.rb +118 -134
  22. data/lib/active_support/code_generator.rb +15 -10
  23. data/lib/active_support/concern.rb +4 -2
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/configurable.rb +10 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +1 -2
  28. data/lib/active_support/core_ext/array.rb +0 -1
  29. data/lib/active_support/core_ext/class/subclasses.rb +17 -34
  30. data/lib/active_support/core_ext/date/blank.rb +4 -0
  31. data/lib/active_support/core_ext/date/conversions.rb +1 -2
  32. data/lib/active_support/core_ext/date.rb +0 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  35. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  36. data/lib/active_support/core_ext/date_time/conversions.rb +2 -2
  37. data/lib/active_support/core_ext/date_time.rb +0 -1
  38. data/lib/active_support/core_ext/digest/uuid.rb +7 -10
  39. data/lib/active_support/core_ext/enumerable.rb +3 -75
  40. data/lib/active_support/core_ext/erb/util.rb +201 -0
  41. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  42. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  43. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  44. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  45. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  46. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  47. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  48. data/lib/active_support/core_ext/module/delegation.rb +20 -119
  49. data/lib/active_support/core_ext/module/deprecation.rb +12 -12
  50. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  51. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  52. data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
  53. data/lib/active_support/core_ext/numeric.rb +0 -1
  54. data/lib/active_support/core_ext/object/blank.rb +45 -1
  55. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  56. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  57. data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
  58. data/lib/active_support/core_ext/object/json.rb +17 -7
  59. data/lib/active_support/core_ext/object/with.rb +46 -0
  60. data/lib/active_support/core_ext/object/with_options.rb +4 -4
  61. data/lib/active_support/core_ext/object.rb +1 -0
  62. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  63. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  64. data/lib/active_support/core_ext/pathname.rb +1 -0
  65. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  66. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  67. data/lib/active_support/core_ext/range.rb +1 -2
  68. data/lib/active_support/core_ext/securerandom.rb +1 -5
  69. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  70. data/lib/active_support/core_ext/string/filters.rb +21 -15
  71. data/lib/active_support/core_ext/string/indent.rb +1 -1
  72. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  73. data/lib/active_support/core_ext/string/multibyte.rb +1 -1
  74. data/lib/active_support/core_ext/string/output_safety.rb +34 -177
  75. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  76. data/lib/active_support/core_ext/time/calculations.rb +36 -30
  77. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  78. data/lib/active_support/core_ext/time/conversions.rb +1 -3
  79. data/lib/active_support/core_ext/time/zones.rb +4 -4
  80. data/lib/active_support/core_ext/time.rb +0 -1
  81. data/lib/active_support/core_ext.rb +0 -1
  82. data/lib/active_support/current_attributes.rb +53 -46
  83. data/lib/active_support/deep_mergeable.rb +53 -0
  84. data/lib/active_support/delegation.rb +202 -0
  85. data/lib/active_support/dependencies/autoload.rb +9 -16
  86. data/lib/active_support/deprecation/behaviors.rb +65 -42
  87. data/lib/active_support/deprecation/constant_accessor.rb +47 -25
  88. data/lib/active_support/deprecation/deprecators.rb +104 -0
  89. data/lib/active_support/deprecation/disallowed.rb +3 -5
  90. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  91. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
  92. data/lib/active_support/deprecation/reporting.rb +49 -27
  93. data/lib/active_support/deprecation.rb +39 -9
  94. data/lib/active_support/deprecator.rb +7 -0
  95. data/lib/active_support/descendants_tracker.rb +66 -172
  96. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  97. data/lib/active_support/duration/iso8601_serializer.rb +1 -4
  98. data/lib/active_support/duration.rb +13 -7
  99. data/lib/active_support/encrypted_configuration.rb +30 -9
  100. data/lib/active_support/encrypted_file.rb +9 -4
  101. data/lib/active_support/environment_inquirer.rb +22 -2
  102. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  103. data/lib/active_support/error_reporter.rb +160 -36
  104. data/lib/active_support/evented_file_update_checker.rb +0 -1
  105. data/lib/active_support/execution_wrapper.rb +4 -5
  106. data/lib/active_support/file_update_checker.rb +5 -3
  107. data/lib/active_support/fork_tracker.rb +4 -32
  108. data/lib/active_support/gem_version.rb +4 -4
  109. data/lib/active_support/gzip.rb +2 -0
  110. data/lib/active_support/hash_with_indifferent_access.rb +41 -25
  111. data/lib/active_support/html_safe_translation.rb +19 -6
  112. data/lib/active_support/i18n.rb +1 -1
  113. data/lib/active_support/i18n_railtie.rb +20 -13
  114. data/lib/active_support/inflector/inflections.rb +2 -0
  115. data/lib/active_support/inflector/methods.rb +23 -11
  116. data/lib/active_support/inflector/transliterate.rb +3 -1
  117. data/lib/active_support/isolated_execution_state.rb +26 -22
  118. data/lib/active_support/json/decoding.rb +2 -1
  119. data/lib/active_support/json/encoding.rb +25 -43
  120. data/lib/active_support/key_generator.rb +9 -1
  121. data/lib/active_support/lazy_load_hooks.rb +6 -4
  122. data/lib/active_support/locale/en.yml +2 -0
  123. data/lib/active_support/log_subscriber.rb +74 -34
  124. data/lib/active_support/logger.rb +22 -60
  125. data/lib/active_support/logger_thread_safe_level.rb +10 -32
  126. data/lib/active_support/message_encryptor.rb +197 -53
  127. data/lib/active_support/message_encryptors.rb +141 -0
  128. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  129. data/lib/active_support/message_pack/extensions.rb +305 -0
  130. data/lib/active_support/message_pack/serializer.rb +63 -0
  131. data/lib/active_support/message_pack.rb +50 -0
  132. data/lib/active_support/message_verifier.rb +220 -89
  133. data/lib/active_support/message_verifiers.rb +135 -0
  134. data/lib/active_support/messages/codec.rb +65 -0
  135. data/lib/active_support/messages/metadata.rb +111 -45
  136. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  137. data/lib/active_support/messages/rotator.rb +34 -32
  138. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  139. data/lib/active_support/multibyte/chars.rb +4 -2
  140. data/lib/active_support/multibyte/unicode.rb +9 -37
  141. data/lib/active_support/notifications/fanout.rb +248 -87
  142. data/lib/active_support/notifications/instrumenter.rb +93 -25
  143. data/lib/active_support/notifications.rb +29 -28
  144. data/lib/active_support/number_helper/number_converter.rb +16 -7
  145. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  147. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  148. data/lib/active_support/number_helper.rb +379 -318
  149. data/lib/active_support/option_merger.rb +2 -2
  150. data/lib/active_support/ordered_hash.rb +3 -3
  151. data/lib/active_support/ordered_options.rb +67 -15
  152. data/lib/active_support/parameter_filter.rb +84 -69
  153. data/lib/active_support/proxy_object.rb +8 -3
  154. data/lib/active_support/railtie.rb +25 -20
  155. data/lib/active_support/reloader.rb +12 -4
  156. data/lib/active_support/rescuable.rb +2 -0
  157. data/lib/active_support/secure_compare_rotator.rb +16 -9
  158. data/lib/active_support/string_inquirer.rb +4 -2
  159. data/lib/active_support/subscriber.rb +10 -27
  160. data/lib/active_support/syntax_error_proxy.rb +60 -0
  161. data/lib/active_support/tagged_logging.rb +64 -25
  162. data/lib/active_support/test_case.rb +156 -7
  163. data/lib/active_support/testing/assertions.rb +28 -12
  164. data/lib/active_support/testing/autorun.rb +0 -2
  165. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  166. data/lib/active_support/testing/deprecation.rb +20 -27
  167. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  168. data/lib/active_support/testing/isolation.rb +21 -9
  169. data/lib/active_support/testing/method_call_assertions.rb +7 -8
  170. data/lib/active_support/testing/parallelization/server.rb +3 -0
  171. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  172. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  173. data/lib/active_support/testing/stream.rb +1 -1
  174. data/lib/active_support/testing/strict_warnings.rb +43 -0
  175. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  176. data/lib/active_support/testing/time_helpers.rb +38 -16
  177. data/lib/active_support/time_with_zone.rb +12 -18
  178. data/lib/active_support/values/time_zone.rb +25 -14
  179. data/lib/active_support/version.rb +1 -1
  180. data/lib/active_support/xml_mini/jdom.rb +3 -10
  181. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  182. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  183. data/lib/active_support/xml_mini/rexml.rb +1 -1
  184. data/lib/active_support/xml_mini.rb +12 -3
  185. data/lib/active_support.rb +15 -3
  186. metadata +140 -19
  187. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  188. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
  189. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
  190. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  191. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
  192. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  193. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  194. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
  195. data/lib/active_support/core_ext/uri.rb +0 -5
  196. data/lib/active_support/deprecation/instance_delegator.rb +0 -38
  197. data/lib/active_support/per_thread_registry.rb +0 -65
  198. data/lib/active_support/ruby_features.rb +0 -7
@@ -3,7 +3,7 @@
3
3
  module ActiveSupport
4
4
  class Deprecation
5
5
  class DeprecationProxy # :nodoc:
6
- def self.new(*args, &block)
6
+ def self.new(*args, **kwargs, &block)
7
7
  object = args.first
8
8
 
9
9
  return object unless object
@@ -25,11 +25,10 @@ module ActiveSupport
25
25
  end
26
26
  end
27
27
 
28
- # DeprecatedObjectProxy transforms an object into a deprecated one. It
29
- # takes an object, a deprecation message, and optionally a deprecator. The
30
- # deprecator defaults to +ActiveSupport::Deprecator+ if none is specified.
28
+ # DeprecatedObjectProxy transforms an object into a deprecated one. It takes an object, a deprecation message, and
29
+ # a deprecator.
31
30
  #
32
- # deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, "This object is now deprecated")
31
+ # deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, "This object is now deprecated", ActiveSupport::Deprecation.new)
33
32
  # # => #<Object:0x007fb9b34c34b0>
34
33
  #
35
34
  # deprecated_object.to_s
@@ -37,7 +36,7 @@ module ActiveSupport
37
36
  # (Backtrace)
38
37
  # # => "#<Object:0x007fb9b34c34b0>"
39
38
  class DeprecatedObjectProxy < DeprecationProxy
40
- def initialize(object, message, deprecator = ActiveSupport::Deprecation.instance)
39
+ def initialize(object, message, deprecator)
41
40
  @object = object
42
41
  @message = message
43
42
  @deprecator = deprecator
@@ -53,15 +52,15 @@ module ActiveSupport
53
52
  end
54
53
  end
55
54
 
56
- # DeprecatedInstanceVariableProxy transforms an instance variable into a
57
- # deprecated one. It takes an instance of a class, a method on that class
58
- # and an instance variable. It optionally takes a deprecator as the last
59
- # argument. The deprecator defaults to +ActiveSupport::Deprecator+ if none
60
- # is specified.
55
+ # DeprecatedInstanceVariableProxy transforms an instance variable into a deprecated one. It takes an instance of a
56
+ # class, a method on that class, an instance variable, and a deprecator as the last argument.
57
+ #
58
+ # Trying to use the deprecated instance variable will result in a deprecation warning, pointing to the method as a
59
+ # replacement.
61
60
  #
62
61
  # class Example
63
62
  # def initialize
64
- # @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request)
63
+ # @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request, ActiveSupport::Deprecation.new)
65
64
  # @_request = :special_request
66
65
  # end
67
66
  #
@@ -86,7 +85,7 @@ module ActiveSupport
86
85
  # example.request.to_s
87
86
  # # => "special_request"
88
87
  class DeprecatedInstanceVariableProxy < DeprecationProxy
89
- def initialize(instance, method, var = "@#{method}", deprecator = ActiveSupport::Deprecation.instance)
88
+ def initialize(instance, method, var = "@#{method}", deprecator:)
90
89
  @instance = instance
91
90
  @method = method
92
91
  @var = var
@@ -103,18 +102,16 @@ module ActiveSupport
103
102
  end
104
103
  end
105
104
 
106
- # DeprecatedConstantProxy transforms a constant into a deprecated one. It
107
- # takes the names of an old (deprecated) constant and of a new constant
108
- # (both in string form) and optionally a deprecator. The deprecator defaults
109
- # to +ActiveSupport::Deprecator+ if none is specified. The deprecated constant
110
- # now returns the value of the new one.
105
+ # DeprecatedConstantProxy transforms a constant into a deprecated one. It takes the full names of an old
106
+ # (deprecated) constant and of a new constant (both in string form) and a deprecator. The deprecated constant now
107
+ # returns the value of the new one.
111
108
  #
112
109
  # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto)
113
110
  #
114
111
  # # (In a later update, the original implementation of `PLANETS` has been removed.)
115
112
  #
116
113
  # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
117
- # PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006')
114
+ # PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("PLANETS", "PLANETS_POST_2006", ActiveSupport::Deprecation.new)
118
115
  #
119
116
  # PLANETS.map { |planet| planet.capitalize }
120
117
  # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
@@ -128,7 +125,7 @@ module ActiveSupport
128
125
  super
129
126
  end
130
127
 
131
- def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
128
+ def initialize(old_const, new_const, deprecator, message: "#{old_const} is deprecated! Use #{new_const} instead.")
132
129
  Kernel.require "active_support/inflector/methods"
133
130
 
134
131
  @old_const = old_const
@@ -158,6 +155,21 @@ module ActiveSupport
158
155
  target.class
159
156
  end
160
157
 
158
+ def append_features(base)
159
+ @deprecator.warn(@message, caller_locations)
160
+ base.include(target)
161
+ end
162
+
163
+ def prepend_features(base)
164
+ @deprecator.warn(@message, caller_locations)
165
+ base.prepend(target)
166
+ end
167
+
168
+ def extended(base)
169
+ @deprecator.warn(@message, caller_locations)
170
+ base.extend(target)
171
+ end
172
+
161
173
  private
162
174
  def target
163
175
  ActiveSupport::Inflector.constantize(@new_const.to_s)
@@ -168,9 +180,9 @@ module ActiveSupport
168
180
  target.const_get(name)
169
181
  end
170
182
 
171
- def method_missing(called, *args, &block)
183
+ def method_missing(...)
172
184
  @deprecator.warn(@message, caller_locations)
173
- target.__send__(called, *args, &block)
185
+ target.__send__(...)
174
186
  end
175
187
  end
176
188
  end
@@ -11,34 +11,50 @@ module ActiveSupport
11
11
  attr_accessor :gem_name
12
12
 
13
13
  # Outputs a deprecation warning to the output configured by
14
- # <tt>ActiveSupport::Deprecation.behavior</tt>.
14
+ # ActiveSupport::Deprecation#behavior.
15
15
  #
16
- # ActiveSupport::Deprecation.warn('something broke!')
16
+ # ActiveSupport::Deprecation.new.warn('something broke!')
17
17
  # # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
18
18
  def warn(message = nil, callstack = nil)
19
19
  return if silenced
20
20
 
21
21
  callstack ||= caller_locations(2)
22
- deprecation_message(callstack, message).tap do |m|
22
+ deprecation_message(callstack, message).tap do |full_message|
23
23
  if deprecation_disallowed?(message)
24
- disallowed_behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
24
+ disallowed_behavior.each { |b| b.call(full_message, callstack, self) }
25
25
  else
26
- behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
26
+ behavior.each { |b| b.call(full_message, callstack, self) }
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
31
  # Silence deprecation warnings within the block.
32
32
  #
33
- # ActiveSupport::Deprecation.warn('something broke!')
33
+ # deprecator = ActiveSupport::Deprecation.new
34
+ # deprecator.warn('something broke!')
34
35
  # # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
35
36
  #
36
- # ActiveSupport::Deprecation.silence do
37
- # ActiveSupport::Deprecation.warn('something broke!')
37
+ # deprecator.silence do
38
+ # deprecator.warn('something broke!')
38
39
  # end
39
40
  # # => nil
40
41
  def silence(&block)
41
- @silenced_thread.bind(true, &block)
42
+ begin_silence
43
+ block.call
44
+ ensure
45
+ end_silence
46
+ end
47
+
48
+ def begin_silence # :nodoc:
49
+ @silence_counter.value += 1
50
+ end
51
+
52
+ def end_silence # :nodoc:
53
+ @silence_counter.value -= 1
54
+ end
55
+
56
+ def silenced
57
+ @silenced || @silence_counter.value.nonzero?
42
58
  end
43
59
 
44
60
  # Allow previously disallowed deprecation warnings within the block.
@@ -46,27 +62,28 @@ module ActiveSupport
46
62
  # expressions. (Symbols are treated as strings). These are compared against
47
63
  # the text of deprecation warning messages generated within the block.
48
64
  # Matching warnings will be exempt from the rules set by
49
- # +ActiveSupport::Deprecation.disallowed_warnings+
65
+ # ActiveSupport::Deprecation#disallowed_warnings.
50
66
  #
51
67
  # The optional <tt>if:</tt> argument accepts a truthy/falsy value or an object that
52
68
  # responds to <tt>.call</tt>. If truthy, then matching warnings will be allowed.
53
69
  # If falsey then the method yields to the block without allowing the warning.
54
70
  #
55
- # ActiveSupport::Deprecation.disallowed_behavior = :raise
56
- # ActiveSupport::Deprecation.disallowed_warnings = [
71
+ # deprecator = ActiveSupport::Deprecation.new
72
+ # deprecator.disallowed_behavior = :raise
73
+ # deprecator.disallowed_warnings = [
57
74
  # "something broke"
58
75
  # ]
59
76
  #
60
- # ActiveSupport::Deprecation.warn('something broke!')
77
+ # deprecator.warn('something broke!')
61
78
  # # => ActiveSupport::DeprecationException
62
79
  #
63
- # ActiveSupport::Deprecation.allow ['something broke'] do
64
- # ActiveSupport::Deprecation.warn('something broke!')
80
+ # deprecator.allow ['something broke'] do
81
+ # deprecator.warn('something broke!')
65
82
  # end
66
83
  # # => nil
67
84
  #
68
- # ActiveSupport::Deprecation.allow ['something broke'], if: Rails.env.production? do
69
- # ActiveSupport::Deprecation.warn('something broke!')
85
+ # deprecator.allow ['something broke'], if: Rails.env.production? do
86
+ # deprecator.warn('something broke!')
70
87
  # end
71
88
  # # => ActiveSupport::DeprecationException for dev/test, nil for production
72
89
  def allow(allowed_warnings = :all, if: true, &block)
@@ -79,10 +96,6 @@ module ActiveSupport
79
96
  end
80
97
  end
81
98
 
82
- def silenced
83
- @silenced || @silenced_thread.value
84
- end
85
-
86
99
  def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
87
100
  caller_backtrace ||= caller_locations(2)
88
101
  deprecated_method_warning(deprecated_method_name, message).tap do |msg|
@@ -125,18 +138,26 @@ module ActiveSupport
125
138
  end
126
139
 
127
140
  def extract_callstack(callstack)
141
+ return [] if callstack.empty?
128
142
  return _extract_callstack(callstack) if callstack.first.is_a? String
129
143
 
130
144
  offending_line = callstack.find { |frame|
131
- frame.absolute_path && !ignored_callstack(frame.absolute_path)
145
+ # Code generated with `eval` doesn't have an `absolute_path`, e.g. templates.
146
+ path = frame.absolute_path || frame.path
147
+ path && !ignored_callstack?(path)
132
148
  } || callstack.first
133
149
 
134
150
  [offending_line.path, offending_line.lineno, offending_line.label]
135
151
  end
136
152
 
137
153
  def _extract_callstack(callstack)
138
- warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
139
- offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
154
+ ActiveSupport.deprecator.warn(<<~MESSAGE)
155
+ Passing the result of `caller` to ActiveSupport::Deprecation#warn is deprecated and will be removed in Rails 8.0.
156
+
157
+ Please pass the result of `caller_locations` instead.
158
+ MESSAGE
159
+
160
+ offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first
140
161
 
141
162
  if offending_line
142
163
  if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
@@ -147,10 +168,11 @@ module ActiveSupport
147
168
  end
148
169
  end
149
170
 
150
- RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
171
+ RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/" # :nodoc:
172
+ LIB_DIR = RbConfig::CONFIG["libdir"] # :nodoc:
151
173
 
152
- def ignored_callstack(path)
153
- path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"])
174
+ def ignored_callstack?(path)
175
+ path.start_with?(RAILS_GEM_ROOT, LIB_DIR) || path.include?("<internal:")
154
176
  end
155
177
  end
156
178
  end
@@ -1,10 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "singleton"
4
-
5
3
  module ActiveSupport
6
- # \Deprecation specifies the API used by Rails to deprecate methods, instance
7
- # variables, objects, and constants.
4
+ # = Active Support \Deprecation
5
+ #
6
+ # \Deprecation specifies the API used by \Rails to deprecate methods, instance variables, objects, and constants. It's
7
+ # also available for gems or applications.
8
+ #
9
+ # For a gem, use Deprecation.new to create a Deprecation object and store it in your module or class (in order for
10
+ # users to be able to configure it).
11
+ #
12
+ # module MyLibrary
13
+ # def self.deprecator
14
+ # @deprecator ||= ActiveSupport::Deprecation.new("2.0", "MyLibrary")
15
+ # end
16
+ # end
17
+ #
18
+ # For a Railtie or Engine, you may also want to add it to the application's deprecators, so that the application's
19
+ # configuration can be applied to it.
20
+ #
21
+ # module MyLibrary
22
+ # class Railtie < Rails::Railtie
23
+ # initializer "my_library.deprecator" do |app|
24
+ # app.deprecators[:my_library] = MyLibrary.deprecator
25
+ # end
26
+ # end
27
+ # end
28
+ #
29
+ # With the above initializer, configuration settings like the following will affect +MyLibrary.deprecator+:
30
+ #
31
+ # # in config/environments/test.rb
32
+ # config.active_support.deprecation = :raise
8
33
  class Deprecation
9
34
  # active_support.rb sets an autoload for ActiveSupport::Deprecation.
10
35
  #
@@ -14,23 +39,28 @@ module ActiveSupport
14
39
  # a circular require warning for active_support/deprecation.rb.
15
40
  #
16
41
  # So, we define the constant first, and load dependencies later.
17
- require "active_support/deprecation/instance_delegator"
18
42
  require "active_support/deprecation/behaviors"
19
43
  require "active_support/deprecation/reporting"
20
44
  require "active_support/deprecation/disallowed"
21
45
  require "active_support/deprecation/constant_accessor"
22
46
  require "active_support/deprecation/method_wrappers"
23
47
  require "active_support/deprecation/proxy_wrappers"
48
+ require "active_support/deprecation/deprecators"
24
49
  require "active_support/core_ext/module/deprecation"
25
50
  require "concurrent/atomic/thread_local_var"
26
51
 
27
- include Singleton
28
- include InstanceDelegator
29
52
  include Behavior
30
53
  include Reporting
31
54
  include Disallowed
32
55
  include MethodWrapper
33
56
 
57
+ MUTEX = Mutex.new # :nodoc:
58
+ private_constant :MUTEX
59
+
60
+ def self._instance # :nodoc:
61
+ @_instance ||= MUTEX.synchronize { @_instance ||= new }
62
+ end
63
+
34
64
  # The version number in which the deprecated behavior will be removed, by default.
35
65
  attr_accessor :deprecation_horizon
36
66
 
@@ -38,13 +68,13 @@ module ActiveSupport
38
68
  # and the second is a library name.
39
69
  #
40
70
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
41
- def initialize(deprecation_horizon = "7.1", gem_name = "Rails")
71
+ def initialize(deprecation_horizon = "8.0", gem_name = "Rails")
42
72
  self.gem_name = gem_name
43
73
  self.deprecation_horizon = deprecation_horizon
44
74
  # By default, warnings are not silenced and debugging is off.
45
75
  self.silenced = false
46
76
  self.debug = false
47
- @silenced_thread = Concurrent::ThreadLocalVar.new(false)
77
+ @silence_counter = Concurrent::ThreadLocalVar.new(0)
48
78
  @explicitly_allowed_warnings = Concurrent::ThreadLocalVar.new(nil)
49
79
  end
50
80
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ def self.deprecator # :nodoc:
5
+ ActiveSupport::Deprecation._instance
6
+ end
7
+ end
@@ -1,218 +1,112 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "weakref"
4
- require "active_support/ruby_features"
5
4
 
6
5
  module ActiveSupport
6
+ # = Active Support Descendants Tracker
7
+ #
7
8
  # This module provides an internal implementation to track descendants
8
- # which is faster than iterating through ObjectSpace.
9
+ # which is faster than iterating through +ObjectSpace+.
10
+ #
11
+ # However Ruby 3.1 provide a fast native +Class#subclasses+ method,
12
+ # so if you know your code won't be executed on older rubies, including
13
+ # +ActiveSupport::DescendantsTracker+ does not provide any benefit.
9
14
  module DescendantsTracker
10
- class << self
11
- def direct_descendants(klass)
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)
17
- end
18
- end
19
-
20
15
  @clear_disabled = false
21
16
 
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
37
-
38
- def [](object)
39
- @map.key?(object.object_id)
40
- end
17
+ if RUBY_ENGINE == "ruby"
18
+ # On MRI `ObjectSpace::WeakMap` keys are weak references.
19
+ # So we can simply use WeakMap as a `Set`.
20
+ class WeakSet < ObjectSpace::WeakMap # :nodoc:
21
+ alias_method :to_a, :keys
41
22
 
42
- def []=(object, _present)
43
- @map[object.object_id] = object
44
- end
23
+ def <<(object)
24
+ self[object] = true
45
25
  end
46
- WeakSet.new
47
26
  end
48
-
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
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
56
36
  end
57
37
 
58
- def subclasses(klass)
59
- klass.subclasses
38
+ def [](object)
39
+ @map.key?(object.object_id)
60
40
  end
41
+ alias_method :include?, :[]
61
42
 
62
- def descendants(klass)
63
- klass.descendants
43
+ def []=(object, _present)
44
+ @map[object.object_id] = object
64
45
  end
65
46
 
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
73
- end
74
- end
47
+ def to_a
48
+ @map.values
75
49
  end
76
50
 
77
- def native? # :nodoc:
78
- true
51
+ def <<(object)
52
+ self[object] = true
79
53
  end
80
54
  end
55
+ end
56
+ @excluded_descendants = WeakSet.new
81
57
 
58
+ module ReloadedClassesFiltering # :nodoc:
82
59
  def subclasses
83
- subclasses = super
84
- subclasses.reject! { |d| @@excluded_descendants[d] }
85
- subclasses
60
+ DescendantsTracker.reject!(super)
86
61
  end
87
62
 
88
63
  def descendants
89
- subclasses.concat(subclasses.flat_map(&:descendants))
90
- end
91
-
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
64
+ DescendantsTracker.reject!(super)
98
65
  end
99
- else
100
- @@direct_descendants = {}
66
+ end
101
67
 
102
- class << self
103
- def disable_clear! # :nodoc:
68
+ class << self
69
+ def disable_clear! # :nodoc:
70
+ unless @clear_disabled
104
71
  @clear_disabled = true
72
+ ReloadedClassesFiltering.remove_method(:subclasses)
73
+ ReloadedClassesFiltering.remove_method(:descendants)
74
+ @excluded_descendants = nil
105
75
  end
76
+ end
106
77
 
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
78
+ def clear(classes) # :nodoc:
79
+ raise "DescendantsTracker.clear was disabled because config.enable_reloading is false" if @clear_disabled
117
80
 
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
128
- end
81
+ classes.each do |klass|
82
+ @excluded_descendants << klass
83
+ klass.descendants.each do |descendant|
84
+ @excluded_descendants << descendant
129
85
  end
130
86
  end
131
-
132
- def native? # :nodoc:
133
- false
134
- end
135
-
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
141
-
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
152
-
153
- def inherited(base)
154
- DescendantsTracker.store_inherited(self, base)
155
- super
156
87
  end
157
88
 
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)
89
+ def reject!(classes) # :nodoc:
90
+ if @excluded_descendants
91
+ classes.reject! { |d| @excluded_descendants.include?(d) }
92
+ end
93
+ classes
164
94
  end
95
+ end
165
96
 
166
- def subclasses
167
- DescendantsTracker.subclasses(self)
97
+ class << self
98
+ def subclasses(klass)
99
+ klass.subclasses
168
100
  end
169
101
 
170
- def descendants
171
- DescendantsTracker.descendants(self)
102
+ def descendants(klass)
103
+ klass.descendants
172
104
  end
105
+ end
173
106
 
174
- # DescendantsArray is an array that contains weak references to classes.
175
- class DescendantsArray # :nodoc:
176
- include Enumerable
177
-
178
- def initialize
179
- @refs = []
180
- end
181
-
182
- def initialize_copy(orig)
183
- @refs = @refs.dup
184
- end
185
-
186
- def <<(klass)
187
- @refs << WeakRef.new(klass)
188
- end
189
-
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
214
- end
215
- end
107
+ def descendants
108
+ subclasses = DescendantsTracker.reject!(self.subclasses)
109
+ subclasses.concat(subclasses.flat_map(&:descendants))
216
110
  end
217
111
  end
218
112
  end
@@ -102,12 +102,12 @@ module ActiveSupport
102
102
  raise_parsing_error("is empty duration") if parts.empty?
103
103
 
104
104
  # Mixing any of Y, M, D with W is invalid.
105
- if parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
105
+ if parts.key?(:weeks) && parts.keys.intersect?(DATE_COMPONENTS)
106
106
  raise_parsing_error("mixing weeks with other date parts not allowed")
107
107
  end
108
108
 
109
109
  # Specifying an empty T part is invalid.
110
- if mode == :time && (parts.keys & TIME_COMPONENTS).empty?
110
+ if mode == :time && !parts.keys.intersect?(TIME_COMPONENTS)
111
111
  raise_parsing_error("time part marker is present but time part is empty")
112
112
  end
113
113