activesupport 6.0.6.1 → 7.1.3.2

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 (245) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +865 -438
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +30 -10
  8. data/lib/active_support/benchmarkable.rb +4 -3
  9. data/lib/active_support/broadcast_logger.rb +250 -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 +53 -20
  14. data/lib/active_support/cache/mem_cache_store.rb +208 -63
  15. data/lib/active_support/cache/memory_store.rb +120 -38
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +201 -208
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +73 -66
  20. data/lib/active_support/cache.rb +539 -261
  21. data/lib/active_support/callbacks.rb +273 -142
  22. data/lib/active_support/code_generator.rb +65 -0
  23. data/lib/active_support/concern.rb +53 -7
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/concurrency/share_lock.rb +2 -2
  27. data/lib/active_support/configurable.rb +19 -6
  28. data/lib/active_support/configuration_file.rb +51 -0
  29. data/lib/active_support/core_ext/array/access.rb +1 -5
  30. data/lib/active_support/core_ext/array/conversions.rb +15 -13
  31. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  33. data/lib/active_support/core_ext/benchmark.rb +2 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  36. data/lib/active_support/core_ext/class/subclasses.rb +19 -29
  37. data/lib/active_support/core_ext/date/blank.rb +1 -1
  38. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  39. data/lib/active_support/core_ext/date/conversions.rb +18 -16
  40. data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
  41. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  42. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  43. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  44. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  45. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  46. data/lib/active_support/core_ext/enumerable.rb +146 -72
  47. data/lib/active_support/core_ext/erb/util.rb +196 -0
  48. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  49. data/lib/active_support/core_ext/hash/conversions.rb +3 -4
  50. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  51. data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
  52. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  53. data/lib/active_support/core_ext/hash/keys.rb +5 -5
  54. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  55. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  56. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  57. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  58. data/lib/active_support/core_ext/load_error.rb +1 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
  62. data/lib/active_support/core_ext/module/concerning.rb +14 -8
  63. data/lib/active_support/core_ext/module/delegation.rb +75 -42
  64. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  65. data/lib/active_support/core_ext/module/introspection.rb +1 -26
  66. data/lib/active_support/core_ext/name_error.rb +23 -2
  67. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  68. data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
  69. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  70. data/lib/active_support/core_ext/object/blank.rb +2 -2
  71. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  72. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  73. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  74. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  75. data/lib/active_support/core_ext/object/json.rb +52 -28
  76. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  77. data/lib/active_support/core_ext/object/try.rb +20 -20
  78. data/lib/active_support/core_ext/object/with.rb +44 -0
  79. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  80. data/lib/active_support/core_ext/object.rb +1 -0
  81. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  82. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  83. data/lib/active_support/core_ext/pathname.rb +4 -0
  84. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  85. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  86. data/lib/active_support/core_ext/range/each.rb +1 -1
  87. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  88. data/lib/active_support/core_ext/range.rb +1 -2
  89. data/lib/active_support/core_ext/regexp.rb +8 -1
  90. data/lib/active_support/core_ext/securerandom.rb +25 -13
  91. data/lib/active_support/core_ext/string/access.rb +5 -24
  92. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  93. data/lib/active_support/core_ext/string/filters.rb +21 -15
  94. data/lib/active_support/core_ext/string/indent.rb +1 -1
  95. data/lib/active_support/core_ext/string/inflections.rb +51 -10
  96. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  97. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  98. data/lib/active_support/core_ext/string/output_safety.rb +85 -194
  99. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  100. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  101. data/lib/active_support/core_ext/symbol.rb +3 -0
  102. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  103. data/lib/active_support/core_ext/time/calculations.rb +46 -8
  104. data/lib/active_support/core_ext/time/conversions.rb +16 -13
  105. data/lib/active_support/core_ext/time/zones.rb +12 -28
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  108. data/lib/active_support/current_attributes.rb +54 -22
  109. data/lib/active_support/deep_mergeable.rb +53 -0
  110. data/lib/active_support/dependencies/autoload.rb +17 -12
  111. data/lib/active_support/dependencies/interlock.rb +10 -18
  112. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  113. data/lib/active_support/dependencies.rb +58 -769
  114. data/lib/active_support/deprecation/behaviors.rb +77 -38
  115. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  116. data/lib/active_support/deprecation/deprecators.rb +104 -0
  117. data/lib/active_support/deprecation/disallowed.rb +54 -0
  118. data/lib/active_support/deprecation/instance_delegator.rb +31 -5
  119. data/lib/active_support/deprecation/method_wrappers.rb +12 -28
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
  121. data/lib/active_support/deprecation/reporting.rb +76 -16
  122. data/lib/active_support/deprecation.rb +36 -4
  123. data/lib/active_support/deprecator.rb +7 -0
  124. data/lib/active_support/descendants_tracker.rb +150 -68
  125. data/lib/active_support/digest.rb +5 -3
  126. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  127. data/lib/active_support/duration/iso8601_serializer.rb +24 -12
  128. data/lib/active_support/duration.rb +136 -56
  129. data/lib/active_support/encrypted_configuration.rb +72 -9
  130. data/lib/active_support/encrypted_file.rb +46 -13
  131. data/lib/active_support/environment_inquirer.rb +40 -0
  132. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  133. data/lib/active_support/error_reporter.rb +203 -0
  134. data/lib/active_support/evented_file_update_checker.rb +86 -137
  135. data/lib/active_support/execution_context/test_helper.rb +13 -0
  136. data/lib/active_support/execution_context.rb +53 -0
  137. data/lib/active_support/execution_wrapper.rb +31 -12
  138. data/lib/active_support/executor/test_helper.rb +7 -0
  139. data/lib/active_support/file_update_checker.rb +4 -2
  140. data/lib/active_support/fork_tracker.rb +79 -0
  141. data/lib/active_support/gem_version.rb +5 -5
  142. data/lib/active_support/gzip.rb +2 -0
  143. data/lib/active_support/hash_with_indifferent_access.rb +86 -42
  144. data/lib/active_support/html_safe_translation.rb +53 -0
  145. data/lib/active_support/i18n.rb +2 -1
  146. data/lib/active_support/i18n_railtie.rb +29 -27
  147. data/lib/active_support/inflector/inflections.rb +26 -9
  148. data/lib/active_support/inflector/methods.rb +54 -64
  149. data/lib/active_support/inflector/transliterate.rb +7 -5
  150. data/lib/active_support/isolated_execution_state.rb +76 -0
  151. data/lib/active_support/json/decoding.rb +6 -5
  152. data/lib/active_support/json/encoding.rb +31 -45
  153. data/lib/active_support/key_generator.rb +32 -7
  154. data/lib/active_support/lazy_load_hooks.rb +33 -7
  155. data/lib/active_support/locale/en.yml +10 -4
  156. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  157. data/lib/active_support/log_subscriber.rb +101 -32
  158. data/lib/active_support/logger.rb +9 -60
  159. data/lib/active_support/logger_silence.rb +2 -26
  160. data/lib/active_support/logger_thread_safe_level.rb +24 -25
  161. data/lib/active_support/message_encryptor.rb +205 -58
  162. data/lib/active_support/message_encryptors.rb +141 -0
  163. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  164. data/lib/active_support/message_pack/extensions.rb +292 -0
  165. data/lib/active_support/message_pack/serializer.rb +63 -0
  166. data/lib/active_support/message_pack.rb +50 -0
  167. data/lib/active_support/message_verifier.rb +237 -86
  168. data/lib/active_support/message_verifiers.rb +135 -0
  169. data/lib/active_support/messages/codec.rb +65 -0
  170. data/lib/active_support/messages/metadata.rb +112 -46
  171. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  172. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  173. data/lib/active_support/messages/rotator.rb +35 -32
  174. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  175. data/lib/active_support/multibyte/chars.rb +15 -52
  176. data/lib/active_support/multibyte/unicode.rb +8 -122
  177. data/lib/active_support/multibyte.rb +1 -1
  178. data/lib/active_support/notifications/fanout.rb +310 -105
  179. data/lib/active_support/notifications/instrumenter.rb +113 -48
  180. data/lib/active_support/notifications.rb +56 -29
  181. data/lib/active_support/number_helper/number_converter.rb +15 -8
  182. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  183. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  184. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  185. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
  186. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  187. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  188. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  189. data/lib/active_support/number_helper.rb +379 -304
  190. data/lib/active_support/option_merger.rb +11 -18
  191. data/lib/active_support/ordered_hash.rb +4 -4
  192. data/lib/active_support/ordered_options.rb +23 -3
  193. data/lib/active_support/parameter_filter.rb +104 -75
  194. data/lib/active_support/proxy_object.rb +2 -0
  195. data/lib/active_support/rails.rb +1 -4
  196. data/lib/active_support/railtie.rb +90 -6
  197. data/lib/active_support/reloader.rb +12 -4
  198. data/lib/active_support/rescuable.rb +18 -16
  199. data/lib/active_support/ruby_features.rb +7 -0
  200. data/lib/active_support/secure_compare_rotator.rb +58 -0
  201. data/lib/active_support/security_utils.rb +19 -12
  202. data/lib/active_support/string_inquirer.rb +5 -3
  203. data/lib/active_support/subscriber.rb +23 -47
  204. data/lib/active_support/syntax_error_proxy.rb +70 -0
  205. data/lib/active_support/tagged_logging.rb +84 -23
  206. data/lib/active_support/test_case.rb +166 -27
  207. data/lib/active_support/testing/assertions.rb +73 -20
  208. data/lib/active_support/testing/autorun.rb +0 -2
  209. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  210. data/lib/active_support/testing/deprecation.rb +53 -2
  211. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  212. data/lib/active_support/testing/isolation.rb +30 -29
  213. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  214. data/lib/active_support/testing/parallelization/server.rb +82 -0
  215. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  216. data/lib/active_support/testing/parallelization.rb +16 -95
  217. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  218. data/lib/active_support/testing/stream.rb +4 -6
  219. data/lib/active_support/testing/strict_warnings.rb +39 -0
  220. data/lib/active_support/testing/tagged_logging.rb +1 -1
  221. data/lib/active_support/testing/time_helpers.rb +89 -19
  222. data/lib/active_support/time_with_zone.rb +105 -70
  223. data/lib/active_support/values/time_zone.rb +59 -26
  224. data/lib/active_support/version.rb +1 -1
  225. data/lib/active_support/xml_mini/jdom.rb +4 -11
  226. data/lib/active_support/xml_mini/libxml.rb +5 -5
  227. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  228. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  229. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  230. data/lib/active_support/xml_mini/rexml.rb +9 -2
  231. data/lib/active_support/xml_mini.rb +7 -6
  232. data/lib/active_support.rb +40 -1
  233. metadata +127 -40
  234. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  235. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  236. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  237. data/lib/active_support/core_ext/marshal.rb +0 -24
  238. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  239. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  240. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  241. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
  242. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  243. data/lib/active_support/core_ext/uri.rb +0 -25
  244. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  245. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -6,38 +6,94 @@ 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
 
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|
23
- behavior.each { |b| b.call(m, callstack, deprecation_horizon, gem_name) }
22
+ deprecation_message(callstack, message).tap do |full_message|
23
+ if deprecation_disallowed?(message)
24
+ disallowed_behavior.each { |b| b.call(full_message, callstack, self) }
25
+ else
26
+ behavior.each { |b| b.call(full_message, callstack, self) }
27
+ end
24
28
  end
25
29
  end
26
30
 
27
31
  # Silence deprecation warnings within the block.
28
32
  #
29
- # ActiveSupport::Deprecation.warn('something broke!')
33
+ # deprecator = ActiveSupport::Deprecation.new
34
+ # deprecator.warn('something broke!')
30
35
  # # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
31
36
  #
32
- # ActiveSupport::Deprecation.silence do
33
- # ActiveSupport::Deprecation.warn('something broke!')
37
+ # deprecator.silence do
38
+ # deprecator.warn('something broke!')
34
39
  # end
35
40
  # # => nil
36
- def silence
37
- old_silenced, @silenced = @silenced, true
38
- yield
41
+ def silence(&block)
42
+ begin_silence
43
+ block.call
39
44
  ensure
40
- @silenced = old_silenced
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?
58
+ end
59
+
60
+ # Allow previously disallowed deprecation warnings within the block.
61
+ # <tt>allowed_warnings</tt> can be an array containing strings, symbols, or regular
62
+ # expressions. (Symbols are treated as strings). These are compared against
63
+ # the text of deprecation warning messages generated within the block.
64
+ # Matching warnings will be exempt from the rules set by
65
+ # ActiveSupport::Deprecation#disallowed_warnings.
66
+ #
67
+ # The optional <tt>if:</tt> argument accepts a truthy/falsy value or an object that
68
+ # responds to <tt>.call</tt>. If truthy, then matching warnings will be allowed.
69
+ # If falsey then the method yields to the block without allowing the warning.
70
+ #
71
+ # deprecator = ActiveSupport::Deprecation.new
72
+ # deprecator.disallowed_behavior = :raise
73
+ # deprecator.disallowed_warnings = [
74
+ # "something broke"
75
+ # ]
76
+ #
77
+ # deprecator.warn('something broke!')
78
+ # # => ActiveSupport::DeprecationException
79
+ #
80
+ # deprecator.allow ['something broke'] do
81
+ # deprecator.warn('something broke!')
82
+ # end
83
+ # # => nil
84
+ #
85
+ # deprecator.allow ['something broke'], if: Rails.env.production? do
86
+ # deprecator.warn('something broke!')
87
+ # end
88
+ # # => ActiveSupport::DeprecationException for dev/test, nil for production
89
+ def allow(allowed_warnings = :all, if: true, &block)
90
+ conditional = binding.local_variable_get(:if)
91
+ conditional = conditional.call if conditional.respond_to?(:call)
92
+ if conditional
93
+ @explicitly_allowed_warnings.bind(allowed_warnings, &block)
94
+ else
95
+ yield
96
+ end
41
97
  end
42
98
 
43
99
  def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
@@ -82,10 +138,13 @@ module ActiveSupport
82
138
  end
83
139
 
84
140
  def extract_callstack(callstack)
141
+ return [] if callstack.empty?
85
142
  return _extract_callstack(callstack) if callstack.first.is_a? String
86
143
 
87
144
  offending_line = callstack.find { |frame|
88
- 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)
89
148
  } || callstack.first
90
149
 
91
150
  [offending_line.path, offending_line.lineno, offending_line.label]
@@ -93,7 +152,7 @@ module ActiveSupport
93
152
 
94
153
  def _extract_callstack(callstack)
95
154
  warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
96
- offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
155
+ offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first
97
156
 
98
157
  if offending_line
99
158
  if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
@@ -105,9 +164,10 @@ module ActiveSupport
105
164
  end
106
165
 
107
166
  RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
167
+ LIB_DIR = RbConfig::CONFIG["libdir"]
108
168
 
109
- def ignored_callstack(path)
110
- path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"])
169
+ def ignored_callstack?(path)
170
+ path.start_with?(RAILS_GEM_ROOT, LIB_DIR)
111
171
  end
112
172
  end
113
173
  end
@@ -3,8 +3,35 @@
3
3
  require "singleton"
4
4
 
5
5
  module ActiveSupport
6
- # \Deprecation specifies the API used by Rails to deprecate methods, instance
7
- # variables, objects and constants.
6
+ # = Active Support \Deprecation
7
+ #
8
+ # \Deprecation specifies the API used by \Rails to deprecate methods, instance variables, objects, and constants. It's
9
+ # also available for gems or applications.
10
+ #
11
+ # For a gem, use Deprecation.new to create a Deprecation object and store it in your module or class (in order for
12
+ # users to be able to configure it).
13
+ #
14
+ # module MyLibrary
15
+ # def self.deprecator
16
+ # @deprecator ||= ActiveSupport::Deprecation.new("2.0", "MyLibrary")
17
+ # end
18
+ # end
19
+ #
20
+ # For a Railtie or Engine, you may also want to add it to the application's deprecators, so that the application's
21
+ # configuration can be applied to it.
22
+ #
23
+ # module MyLibrary
24
+ # class Railtie < Rails::Railtie
25
+ # initializer "my_library.deprecator" do |app|
26
+ # app.deprecators[:my_library] = MyLibrary.deprecator
27
+ # end
28
+ # end
29
+ # end
30
+ #
31
+ # With the above initializer, configuration settings like the following will affect +MyLibrary.deprecator+:
32
+ #
33
+ # # in config/environments/test.rb
34
+ # config.active_support.deprecation = :raise
8
35
  class Deprecation
9
36
  # active_support.rb sets an autoload for ActiveSupport::Deprecation.
10
37
  #
@@ -17,15 +44,18 @@ module ActiveSupport
17
44
  require "active_support/deprecation/instance_delegator"
18
45
  require "active_support/deprecation/behaviors"
19
46
  require "active_support/deprecation/reporting"
47
+ require "active_support/deprecation/disallowed"
20
48
  require "active_support/deprecation/constant_accessor"
21
49
  require "active_support/deprecation/method_wrappers"
22
50
  require "active_support/deprecation/proxy_wrappers"
51
+ require "active_support/deprecation/deprecators"
23
52
  require "active_support/core_ext/module/deprecation"
53
+ require "concurrent/atomic/thread_local_var"
24
54
 
25
- include Singleton
26
55
  include InstanceDelegator
27
56
  include Behavior
28
57
  include Reporting
58
+ include Disallowed
29
59
  include MethodWrapper
30
60
 
31
61
  # The version number in which the deprecated behavior will be removed, by default.
@@ -35,12 +65,14 @@ module ActiveSupport
35
65
  # and the second is a library name.
36
66
  #
37
67
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
38
- def initialize(deprecation_horizon = "6.1", gem_name = "Rails")
68
+ def initialize(deprecation_horizon = "7.2", gem_name = "Rails")
39
69
  self.gem_name = gem_name
40
70
  self.deprecation_horizon = deprecation_horizon
41
71
  # By default, warnings are not silenced and debugging is off.
42
72
  self.silenced = false
43
73
  self.debug = false
74
+ @silence_counter = Concurrent::ThreadLocalVar.new(0)
75
+ @explicitly_allowed_warnings = Concurrent::ThreadLocalVar.new(nil)
44
76
  end
45
77
  end
46
78
  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,108 +1,190 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "weakref"
4
+ require "active_support/ruby_features"
4
5
 
5
6
  module ActiveSupport
7
+ # = Active Support Descendants Tracker
8
+ #
6
9
  # This module provides an internal implementation to track descendants
7
- # which is faster than iterating through ObjectSpace.
10
+ # which is faster than iterating through +ObjectSpace+.
11
+ #
12
+ # However Ruby 3.1 provide a fast native +Class#subclasses+ method,
13
+ # so if you know your code won't be executed on older rubies, including
14
+ # +ActiveSupport::DescendantsTracker+ does not provide any benefit.
8
15
  module DescendantsTracker
9
- @@direct_descendants = {}
16
+ @clear_disabled = false
10
17
 
11
- class << self
12
- def direct_descendants(klass)
13
- descendants = @@direct_descendants[klass]
14
- descendants ? descendants.to_a : []
15
- end
18
+ if RUBY_ENGINE == "ruby"
19
+ # On MRI `ObjectSpace::WeakMap` keys are weak references.
20
+ # So we can simply use WeakMap as a `Set`.
21
+ class WeakSet < ObjectSpace::WeakMap # :nodoc:
22
+ alias_method :to_a, :keys
16
23
 
17
- def descendants(klass)
18
- arr = []
19
- accumulate_descendants(klass, arr)
20
- arr
24
+ def <<(object)
25
+ self[object] = true
26
+ end
21
27
  end
28
+ else
29
+ # On TruffleRuby `ObjectSpace::WeakMap` keys are strong references.
30
+ # So we use `object_id` as a key and the actual object as a value.
31
+ #
32
+ # JRuby for now doesn't have Class#descendant, but when it will, it will likely
33
+ # have the same WeakMap semantic than Truffle so we future proof this as much as possible.
34
+ class WeakSet # :nodoc:
35
+ def initialize
36
+ @map = ObjectSpace::WeakMap.new
37
+ end
22
38
 
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) }
30
- end
31
- end
32
- else
33
- @@direct_descendants.clear
39
+ def [](object)
40
+ @map.key?(object.object_id)
34
41
  end
35
- end
42
+ alias_method :include?, :[]
36
43
 
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
41
- end
44
+ def []=(object, _present)
45
+ @map[object.object_id] = object
46
+ end
42
47
 
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)
49
- end
50
- end
48
+ def to_a
49
+ @map.values
51
50
  end
52
- end
53
51
 
54
- def inherited(base)
55
- DescendantsTracker.store_inherited(self, base)
56
- super
52
+ def <<(object)
53
+ self[object] = true
54
+ end
55
+ end
57
56
  end
57
+ @excluded_descendants = WeakSet.new
58
+
59
+ module ReloadedClassesFiltering # :nodoc:
60
+ def subclasses
61
+ DescendantsTracker.reject!(super)
62
+ end
58
63
 
59
- def direct_descendants
60
- DescendantsTracker.direct_descendants(self)
64
+ def descendants
65
+ DescendantsTracker.reject!(super)
66
+ end
61
67
  end
62
68
 
63
- def descendants
64
- DescendantsTracker.descendants(self)
69
+ class << self
70
+ def disable_clear! # :nodoc:
71
+ unless @clear_disabled
72
+ @clear_disabled = true
73
+ ReloadedClassesFiltering.remove_method(:subclasses)
74
+ ReloadedClassesFiltering.remove_method(:descendants)
75
+ @excluded_descendants = nil
76
+ end
77
+ end
78
+
79
+ def clear(classes) # :nodoc:
80
+ raise "DescendantsTracker.clear was disabled because config.enable_reloading is false" if @clear_disabled
81
+
82
+ classes.each do |klass|
83
+ @excluded_descendants << klass
84
+ klass.descendants.each do |descendant|
85
+ @excluded_descendants << descendant
86
+ end
87
+ end
88
+ end
89
+
90
+ def reject!(classes) # :nodoc:
91
+ if @excluded_descendants
92
+ classes.reject! { |d| @excluded_descendants.include?(d) }
93
+ end
94
+ classes
95
+ end
65
96
  end
66
97
 
67
- # DescendantsArray is an array that contains weak references to classes.
68
- class DescendantsArray # :nodoc:
69
- include Enumerable
98
+ if RubyFeatures::CLASS_SUBCLASSES
99
+ class << self
100
+ def subclasses(klass)
101
+ klass.subclasses
102
+ end
70
103
 
71
- def initialize
72
- @refs = []
104
+ def descendants(klass)
105
+ klass.descendants
106
+ end
73
107
  end
74
108
 
75
- def initialize_copy(orig)
76
- @refs = @refs.dup
109
+ def descendants
110
+ subclasses = DescendantsTracker.reject!(self.subclasses)
111
+ subclasses.concat(subclasses.flat_map(&:descendants))
77
112
  end
113
+ else
114
+ # DescendantsArray is an array that contains weak references to classes.
115
+ # Note: DescendantsArray is redundant with WeakSet, however WeakSet when used
116
+ # on Ruby 2.7 or 3.0 can trigger a Ruby crash: https://bugs.ruby-lang.org/issues/18928
117
+ class DescendantsArray # :nodoc:
118
+ include Enumerable
119
+
120
+ def initialize
121
+ @refs = []
122
+ end
123
+
124
+ def <<(klass)
125
+ @refs << WeakRef.new(klass)
126
+ end
127
+
128
+ def each
129
+ @refs.reject! do |ref|
130
+ yield ref.__getobj__
131
+ false
132
+ rescue WeakRef::RefError
133
+ true
134
+ end
135
+ self
136
+ end
137
+
138
+ def refs_size
139
+ @refs.size
140
+ end
141
+
142
+ def cleanup!
143
+ @refs.delete_if { |ref| !ref.weakref_alive? }
144
+ end
78
145
 
79
- def <<(klass)
80
- cleanup!
81
- @refs << WeakRef.new(klass)
146
+ def reject!
147
+ @refs.reject! do |ref|
148
+ yield ref.__getobj__
149
+ rescue WeakRef::RefError
150
+ true
151
+ end
152
+ end
82
153
  end
83
154
 
84
- def each
85
- @refs.each do |ref|
86
- yield ref.__getobj__
87
- rescue WeakRef::RefError
155
+ @direct_descendants = {}
156
+
157
+ class << self
158
+ def subclasses(klass)
159
+ descendants = @direct_descendants[klass]
160
+ descendants ? DescendantsTracker.reject!(descendants.to_a) : []
161
+ end
162
+
163
+ def descendants(klass)
164
+ subclasses = self.subclasses(klass)
165
+ subclasses.concat(subclasses.flat_map { |k| descendants(k) })
166
+ end
167
+
168
+ # This is the only method that is not thread safe, but is only ever called
169
+ # during the eager loading phase.
170
+ def store_inherited(klass, descendant) # :nodoc:
171
+ (@direct_descendants[klass] ||= DescendantsArray.new) << descendant
88
172
  end
89
173
  end
90
174
 
91
- def refs_size
92
- @refs.size
175
+ def subclasses
176
+ DescendantsTracker.subclasses(self)
93
177
  end
94
178
 
95
- def cleanup!
96
- @refs.delete_if { |ref| !ref.weakref_alive? }
179
+ def descendants
180
+ DescendantsTracker.descendants(self)
97
181
  end
98
182
 
99
- def reject!
100
- @refs.reject! do |ref|
101
- yield ref.__getobj__
102
- rescue WeakRef::RefError
103
- true
183
+ private
184
+ def inherited(base) # :nodoc:
185
+ DescendantsTracker.store_inherited(self, base)
186
+ super
104
187
  end
105
- end
106
188
  end
107
189
  end
108
190
  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 }
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/blank"
4
-
5
3
  module ActiveSupport
6
4
  class Duration
7
5
  # Serializes duration to string according to ISO 8601 Duration format.
8
6
  class ISO8601Serializer # :nodoc:
7
+ DATE_COMPONENTS = %i(years months days)
8
+
9
9
  def initialize(duration, precision: nil)
10
10
  @duration = duration
11
11
  @precision = precision
@@ -13,22 +13,22 @@ module ActiveSupport
13
13
 
14
14
  # Builds and returns output string.
15
15
  def serialize
16
- parts, sign = normalize
16
+ parts = normalize
17
17
  return "PT0S" if parts.empty?
18
18
 
19
19
  output = +"P"
20
20
  output << "#{parts[:years]}Y" if parts.key?(:years)
21
21
  output << "#{parts[:months]}M" if parts.key?(:months)
22
- output << "#{parts[:weeks]}W" if parts.key?(:weeks)
23
22
  output << "#{parts[:days]}D" if parts.key?(:days)
23
+ output << "#{parts[:weeks]}W" if parts.key?(:weeks)
24
24
  time = +""
25
25
  time << "#{parts[:hours]}H" if parts.key?(:hours)
26
26
  time << "#{parts[:minutes]}M" if parts.key?(:minutes)
27
27
  if parts.key?(:seconds)
28
- time << "#{sprintf(@precision ? "%0.0#{@precision}f" : '%g', parts[:seconds])}S"
28
+ time << "#{format_seconds(parts[:seconds])}S"
29
29
  end
30
30
  output << "T#{time}" unless time.empty?
31
- "#{sign}#{output}"
31
+ output
32
32
  end
33
33
 
34
34
  private
@@ -40,13 +40,25 @@ module ActiveSupport
40
40
  parts = @duration.parts.each_with_object(Hash.new(0)) do |(k, v), p|
41
41
  p[k] += v unless v.zero?
42
42
  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!(&:-@)
43
+
44
+ # Convert weeks to days and remove weeks if mixed with date parts
45
+ if week_mixed_with_date?(parts)
46
+ parts[:days] += parts.delete(:weeks) * SECONDS_PER_WEEK / SECONDS_PER_DAY
47
+ end
48
+
49
+ parts
50
+ end
51
+
52
+ def week_mixed_with_date?(parts)
53
+ parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
54
+ end
55
+
56
+ def format_seconds(seconds)
57
+ if @precision
58
+ sprintf("%0.0#{@precision}f", seconds)
59
+ else
60
+ seconds.to_s
48
61
  end
49
- [parts, sign]
50
62
  end
51
63
  end
52
64
  end