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
@@ -0,0 +1,202 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module ActiveSupport
6
+ # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
7
+ # option is not used.
8
+ class DelegationError < NoMethodError
9
+ class << self
10
+ def nil_target(method_name, target) # :nodoc:
11
+ new("#{method_name} delegated to #{target}, but #{target} is nil")
12
+ end
13
+ end
14
+ end
15
+
16
+ module Delegation # :nodoc:
17
+ RUBY_RESERVED_KEYWORDS = %w(__ENCODING__ __LINE__ __FILE__ alias and BEGIN begin break
18
+ case class def defined? do else elsif END end ensure false for if in module next nil
19
+ not or redo rescue retry return self super then true undef unless until when while yield)
20
+ RESERVED_METHOD_NAMES = (RUBY_RESERVED_KEYWORDS + %w(_ arg args block)).to_set.freeze
21
+
22
+ class << self
23
+ def generate(owner, methods, location: nil, to: nil, prefix: nil, allow_nil: nil, nilable: true, private: nil, as: nil, signature: nil)
24
+ unless to
25
+ raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
26
+ end
27
+
28
+ if prefix == true && /^[^a-z_]/.match?(to)
29
+ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
30
+ end
31
+
32
+ method_prefix = \
33
+ if prefix
34
+ "#{prefix == true ? to : prefix}_"
35
+ else
36
+ ""
37
+ end
38
+
39
+ location ||= caller_locations(1, 1).first
40
+ file, line = location.path, location.lineno
41
+
42
+ receiver = if to.is_a?(Module)
43
+ if to.name.nil?
44
+ raise ArgumentError, "Can't delegate to anonymous class or module: #{to}"
45
+ end
46
+
47
+ unless Inflector.safe_constantize(to.name).equal?(to)
48
+ raise ArgumentError, "Can't delegate to detached class or module: #{to.name}"
49
+ end
50
+
51
+ "::#{to.name}"
52
+ else
53
+ to.to_s
54
+ end
55
+ receiver = "self.#{receiver}" if RESERVED_METHOD_NAMES.include?(receiver)
56
+
57
+ explicit_receiver = false
58
+ receiver_class = if as
59
+ explicit_receiver = true
60
+ as
61
+ elsif to.is_a?(Module)
62
+ to.singleton_class
63
+ elsif receiver == "self.class"
64
+ nilable = false # self.class can't possibly be nil
65
+ owner.singleton_class
66
+ end
67
+
68
+ method_def = []
69
+ method_names = []
70
+
71
+ method_def << "self.private" if private
72
+
73
+ methods.each do |method|
74
+ method_name = prefix ? "#{method_prefix}#{method}" : method
75
+ method_names << method_name.to_sym
76
+
77
+ # Attribute writer methods only accept one argument. Makes sure []=
78
+ # methods still accept two arguments.
79
+ definition = \
80
+ if signature
81
+ signature
82
+ elsif /[^\]]=\z/.match?(method)
83
+ "arg"
84
+ else
85
+ method_object = if receiver_class
86
+ begin
87
+ receiver_class.public_instance_method(method)
88
+ rescue NameError
89
+ raise if explicit_receiver
90
+ # Do nothing. Fall back to `"..."`
91
+ end
92
+ end
93
+
94
+ if method_object
95
+ parameters = method_object.parameters
96
+
97
+ if parameters.map(&:first).intersect?([:opt, :rest, :keyreq, :key, :keyrest])
98
+ "..."
99
+ else
100
+ defn = parameters.filter_map { |type, arg| arg if type == :req }
101
+ defn << "&"
102
+ defn.join(", ")
103
+ end
104
+ else
105
+ "..."
106
+ end
107
+ end
108
+
109
+ # The following generated method calls the target exactly once, storing
110
+ # the returned value in a dummy variable.
111
+ #
112
+ # Reason is twofold: On one hand doing less calls is in general better.
113
+ # On the other hand it could be that the target has side-effects,
114
+ # whereas conceptually, from the user point of view, the delegator should
115
+ # be doing one call.
116
+ if nilable == false
117
+ method_def <<
118
+ "def #{method_name}(#{definition})" <<
119
+ " (#{receiver}).#{method}(#{definition})" <<
120
+ "end"
121
+ elsif allow_nil
122
+ method = method.to_s
123
+
124
+ method_def <<
125
+ "def #{method_name}(#{definition})" <<
126
+ " _ = #{receiver}" <<
127
+ " if !_.nil? || nil.respond_to?(:#{method})" <<
128
+ " _.#{method}(#{definition})" <<
129
+ " end" <<
130
+ "end"
131
+ else
132
+ method = method.to_s
133
+ method_name = method_name.to_s
134
+
135
+ method_def <<
136
+ "def #{method_name}(#{definition})" <<
137
+ " _ = #{receiver}" <<
138
+ " _.#{method}(#{definition})" <<
139
+ "rescue NoMethodError => e" <<
140
+ " if _.nil? && e.name == :#{method}" <<
141
+ " raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
142
+ " else" <<
143
+ " raise" <<
144
+ " end" <<
145
+ "end"
146
+ end
147
+ end
148
+ owner.module_eval(method_def.join(";"), file, line)
149
+ method_names
150
+ end
151
+
152
+ def generate_method_missing(owner, target, allow_nil: nil)
153
+ target = target.to_s
154
+ target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target) || target == "__target"
155
+
156
+ if allow_nil
157
+ owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
158
+ def respond_to_missing?(name, include_private = false)
159
+ # It may look like an oversight, but we deliberately do not pass
160
+ # +include_private+, because they do not get delegated.
161
+
162
+ return false if name == :marshal_dump || name == :_dump
163
+ #{target}.respond_to?(name) || super
164
+ end
165
+
166
+ def method_missing(method, ...)
167
+ __target = #{target}
168
+ if __target.nil? && !nil.respond_to?(method)
169
+ nil
170
+ elsif __target.respond_to?(method)
171
+ __target.public_send(method, ...)
172
+ else
173
+ super
174
+ end
175
+ end
176
+ RUBY
177
+ else
178
+ owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
179
+ def respond_to_missing?(name, include_private = false)
180
+ # It may look like an oversight, but we deliberately do not pass
181
+ # +include_private+, because they do not get delegated.
182
+
183
+ return false if name == :marshal_dump || name == :_dump
184
+ #{target}.respond_to?(name) || super
185
+ end
186
+
187
+ def method_missing(method, ...)
188
+ __target = #{target}
189
+ if __target.nil? && !nil.respond_to?(method)
190
+ raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')
191
+ elsif __target.respond_to?(method)
192
+ __target.public_send(method, ...)
193
+ else
194
+ super
195
+ end
196
+ end
197
+ RUBY
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -3,10 +3,12 @@
3
3
  require "active_support/inflector/methods"
4
4
 
5
5
  module ActiveSupport
6
+ # = Active Support \Autoload
7
+ #
6
8
  # Autoload and eager load conveniences for your library.
7
9
  #
8
10
  # This module allows you to define autoloads based on
9
- # Rails conventions (i.e. no need to define the path
11
+ # \Rails conventions (i.e. no need to define the path
10
12
  # it is automatically guessed based on the filename)
11
13
  # and also define a set of constants that needs to be
12
14
  # eager loaded:
@@ -25,15 +27,6 @@ module ActiveSupport
25
27
  #
26
28
  # MyLib.eager_load!
27
29
  module Autoload
28
- def self.extended(base) # :nodoc:
29
- base.class_eval do
30
- @_autoloads = {}
31
- @_under_path = nil
32
- @_at_path = nil
33
- @_eager_autoload = false
34
- end
35
- end
36
-
37
30
  def autoload(const_name, path = @_at_path)
38
31
  unless path
39
32
  full = [name, @_under_path, const_name.to_s].compact.join("::")
@@ -41,7 +34,8 @@ module ActiveSupport
41
34
  end
42
35
 
43
36
  if @_eager_autoload
44
- @_autoloads[const_name] = path
37
+ @_eagerloaded_constants ||= []
38
+ @_eagerloaded_constants << const_name
45
39
  end
46
40
 
47
41
  super const_name, path
@@ -69,11 +63,10 @@ module ActiveSupport
69
63
  end
70
64
 
71
65
  def eager_load!
72
- @_autoloads.each_value { |file| require file }
73
- end
74
-
75
- def autoloads
76
- @_autoloads
66
+ if @_eagerloaded_constants
67
+ @_eagerloaded_constants.each { |const_name| const_get(const_name) }
68
+ @_eagerloaded_constants = nil
69
+ end
77
70
  end
78
71
  end
79
72
  end
@@ -11,18 +11,18 @@ module ActiveSupport
11
11
  class Deprecation
12
12
  # Default warning behaviors per Rails.env.
13
13
  DEFAULT_BEHAVIORS = {
14
- raise: ->(message, callstack, deprecation_horizon, gem_name) {
14
+ raise: ->(message, callstack, deprecator) do
15
15
  e = DeprecationException.new(message)
16
16
  e.set_backtrace(callstack.map(&:to_s))
17
17
  raise e
18
- },
18
+ end,
19
19
 
20
- stderr: ->(message, callstack, deprecation_horizon, gem_name) {
20
+ stderr: ->(message, callstack, deprecator) do
21
21
  $stderr.puts(message)
22
- $stderr.puts callstack.join("\n ") if debug
23
- },
22
+ $stderr.puts callstack.join("\n ") if deprecator.debug
23
+ end,
24
24
 
25
- log: ->(message, callstack, deprecation_horizon, gem_name) {
25
+ log: ->(message, callstack, deprecator) do
26
26
  logger =
27
27
  if defined?(Rails.logger) && Rails.logger
28
28
  Rails.logger
@@ -31,33 +31,41 @@ module ActiveSupport
31
31
  ActiveSupport::Logger.new($stderr)
32
32
  end
33
33
  logger.warn message
34
- logger.debug callstack.join("\n ") if debug
35
- },
36
-
37
- notify: ->(message, callstack, deprecation_horizon, gem_name) {
38
- notification_name = "deprecation.#{gem_name.underscore.tr('/', '_')}"
39
- ActiveSupport::Notifications.instrument(notification_name,
40
- message: message,
41
- callstack: callstack,
42
- gem_name: gem_name,
43
- deprecation_horizon: deprecation_horizon)
44
- },
45
-
46
- silence: ->(message, callstack, deprecation_horizon, gem_name) { },
34
+ logger.debug callstack.join("\n ") if deprecator.debug
35
+ end,
36
+
37
+ notify: ->(message, callstack, deprecator) do
38
+ ActiveSupport::Notifications.instrument(
39
+ "deprecation.#{deprecator.gem_name.underscore.tr("/", "_")}",
40
+ message: message,
41
+ callstack: callstack,
42
+ gem_name: deprecator.gem_name,
43
+ deprecation_horizon: deprecator.deprecation_horizon,
44
+ )
45
+ end,
46
+
47
+ silence: ->(message, callstack, deprecator) { },
48
+
49
+ report: ->(message, callstack, deprecator) do
50
+ error = DeprecationException.new(message)
51
+ error.set_backtrace(callstack.map(&:to_s))
52
+ ActiveSupport.error_reporter.report(error)
53
+ end
47
54
  }
48
55
 
49
56
  # Behavior module allows to determine how to display deprecation messages.
50
57
  # You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+
51
58
  # constant. Available behaviors are:
52
59
  #
53
- # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
54
- # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
55
- # [+log+] Log all deprecation warnings to +Rails.logger+.
56
- # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
57
- # [+silence+] Do nothing. On Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
60
+ # [+:raise+] Raise ActiveSupport::DeprecationException.
61
+ # [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
62
+ # [+:log+] Log all deprecation warnings to +Rails.logger+.
63
+ # [+:notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
64
+ # [+:report+] Use ActiveSupport::ErrorReporter to report deprecations.
65
+ # [+:silence+] Do nothing. On \Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
58
66
  #
59
67
  # Setting behaviors only affects deprecations that happen after boot time.
60
- # For more information you can read the documentation of the +behavior=+ method.
68
+ # For more information you can read the documentation of the #behavior= method.
61
69
  module Behavior
62
70
  # Whether to print a backtrace along with the warning.
63
71
  attr_accessor :debug
@@ -77,32 +85,36 @@ module ActiveSupport
77
85
  #
78
86
  # Available behaviors:
79
87
  #
80
- # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
81
- # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
82
- # [+log+] Log all deprecation warnings to +Rails.logger+.
83
- # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
84
- # [+silence+] Do nothing.
88
+ # [+:raise+] Raise ActiveSupport::DeprecationException.
89
+ # [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
90
+ # [+:log+] Log all deprecation warnings to +Rails.logger+.
91
+ # [+:notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
92
+ # [+:report+] Use ActiveSupport::ErrorReporter to report deprecations.
93
+ # [+:silence+] Do nothing.
85
94
  #
86
95
  # Setting behaviors only affects deprecations that happen after boot time.
87
96
  # Deprecation warnings raised by gems are not affected by this setting
88
- # because they happen before Rails boots up.
97
+ # because they happen before \Rails boots up.
89
98
  #
90
- # ActiveSupport::Deprecation.behavior = :stderr
91
- # ActiveSupport::Deprecation.behavior = [:stderr, :log]
92
- # ActiveSupport::Deprecation.behavior = MyCustomHandler
93
- # ActiveSupport::Deprecation.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
99
+ # deprecator = ActiveSupport::Deprecation.new
100
+ # deprecator.behavior = :stderr
101
+ # deprecator.behavior = [:stderr, :log]
102
+ # deprecator.behavior = MyCustomHandler
103
+ # deprecator.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
94
104
  # # custom stuff
95
105
  # }
96
106
  #
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.
107
+ # If you are using \Rails, you can set
108
+ # <tt>config.active_support.report_deprecations = false</tt> to disable
109
+ # all deprecation behaviors. This is similar to the +:silence+ option but
110
+ # more performant.
99
111
  def behavior=(behavior)
100
112
  @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
101
113
  end
102
114
 
103
115
  # 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
116
+ # ActiveSupport::Deprecation#disallowed_warnings=) to the specified
117
+ # value. As with #behavior=, this can be a single value, array, or an
106
118
  # object that responds to +call+.
107
119
  def disallowed_behavior=(behavior)
108
120
  @disallowed_behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
@@ -114,12 +126,23 @@ module ActiveSupport
114
126
  raise ArgumentError, "#{behavior.inspect} is not a valid deprecation behavior."
115
127
  end
116
128
 
117
- if behavior.respond_to?(:arity) && behavior.arity == 2
118
- -> message, callstack, _, _ { behavior.call(message, callstack) }
119
- else
129
+ case arity_of_callable(behavior)
130
+ when 2
131
+ ->(message, callstack, deprecator) do
132
+ behavior.call(message, callstack)
133
+ end
134
+ when -2..3
120
135
  behavior
136
+ else
137
+ ->(message, callstack, deprecator) do
138
+ behavior.call(message, callstack, deprecator.deprecation_horizon, deprecator.gem_name)
139
+ end
121
140
  end
122
141
  end
142
+
143
+ def arity_of_callable(callable)
144
+ callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity
145
+ end
123
146
  end
124
147
  end
125
148
  end
@@ -2,29 +2,6 @@
2
2
 
3
3
  module ActiveSupport
4
4
  class Deprecation
5
- # DeprecatedConstantAccessor transforms a constant into a deprecated one by
6
- # hooking +const_missing+.
7
- #
8
- # It takes the names of an old (deprecated) constant and of a new constant
9
- # (both in string form) and optionally a deprecator. The deprecator defaults
10
- # to +ActiveSupport::Deprecator+ if none is specified.
11
- #
12
- # The deprecated constant now returns the same object as the new one rather
13
- # than a proxy object, so it can be used transparently in +rescue+ blocks
14
- # etc.
15
- #
16
- # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto)
17
- #
18
- # # (In a later update, the original implementation of `PLANETS` has been removed.)
19
- #
20
- # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
21
- # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
22
- # deprecate_constant 'PLANETS', 'PLANETS_POST_2006'
23
- #
24
- # PLANETS.map { |planet| planet.capitalize }
25
- # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
26
- # (Backtrace information…)
27
- # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
28
5
  module DeprecatedConstantAccessor
29
6
  def self.included(base)
30
7
  require "active_support/inflector/methods"
@@ -40,9 +17,54 @@ module ActiveSupport
40
17
  super
41
18
  end
42
19
 
43
- def deprecate_constant(const_name, new_constant, message: nil, deprecator: ActiveSupport::Deprecation.instance)
20
+ # Provides a way to rename constants with a deprecation cycle in which
21
+ # both the old and new names work, but using the old one prints a
22
+ # deprecation message.
23
+ #
24
+ # In order to rename <tt>A::B</tt> to <tt>C::D</tt>, you need to delete the
25
+ # definition of <tt>A::B</tt> and declare the deprecation in +A+:
26
+ #
27
+ # require "active_support/deprecation"
28
+ #
29
+ # module A
30
+ # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
31
+ #
32
+ # deprecate_constant "B", "C::D", deprecator: ActiveSupport::Deprecation.new
33
+ # end
34
+ #
35
+ # The first argument is a constant name (no colons). It is the name of
36
+ # the constant you want to deprecate in the enclosing class or module.
37
+ #
38
+ # The second argument is the constant path of the replacement. That
39
+ # has to be a full path even if the replacement is defined in the same
40
+ # namespace as the deprecated one was.
41
+ #
42
+ # In both cases, strings and symbols are supported.
43
+ #
44
+ # The +deprecator+ keyword argument is the object that will print the
45
+ # deprecation message, an instance of ActiveSupport::Deprecation.
46
+ #
47
+ # With that in place, references to <tt>A::B</tt> still work, they
48
+ # evaluate to <tt>C::D</tt> now, and trigger a deprecation warning:
49
+ #
50
+ # DEPRECATION WARNING: A::B is deprecated! Use C::D instead.
51
+ # (called from ...)
52
+ #
53
+ # The message can be customized with the optional +message+ keyword
54
+ # argument.
55
+ #
56
+ # For this to work, a +const_missing+ hook is installed. When client
57
+ # code references the deprecated constant, the callback prints the
58
+ # message and constantizes the replacement.
59
+ #
60
+ # Caveat: If the deprecated constant name is reachable in a different
61
+ # namespace and Ruby constant lookup finds it, the hook won't be
62
+ # called and the deprecation won't work as intended. This may happen,
63
+ # for example, if an ancestor of the enclosing namespace has a
64
+ # constant with the same name. This is an unsupported edge case.
65
+ def deprecate_constant(old_constant_name, new_constant_path, deprecator:, message: nil)
44
66
  class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
45
- class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
67
+ class_variable_get(:@@_deprecated_constants)[old_constant_name.to_s] = { new: new_constant_path, message: message, deprecator: deprecator }
46
68
  end
47
69
  end
48
70
  base.singleton_class.prepend extension
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ class Deprecation
5
+ # A managed collection of deprecators. Configuration methods, such as
6
+ # #behavior=, affect all deprecators in the collection. Additionally, the
7
+ # #silence method silences all deprecators in the collection for the
8
+ # duration of a given block.
9
+ class Deprecators
10
+ def initialize
11
+ @options = {}
12
+ @deprecators = {}
13
+ end
14
+
15
+ # Returns a deprecator added to this collection via #[]=.
16
+ def [](name)
17
+ @deprecators[name]
18
+ end
19
+
20
+ # Adds a given +deprecator+ to this collection. The deprecator will be
21
+ # immediately configured with any options previously set on this
22
+ # collection.
23
+ #
24
+ # deprecators = ActiveSupport::Deprecation::Deprecators.new
25
+ # deprecators.debug = true
26
+ #
27
+ # foo_deprecator = ActiveSupport::Deprecation.new("2.0", "Foo")
28
+ # foo_deprecator.debug # => false
29
+ #
30
+ # deprecators[:foo] = foo_deprecator
31
+ # deprecators[:foo].debug # => true
32
+ # foo_deprecator.debug # => true
33
+ #
34
+ def []=(name, deprecator)
35
+ apply_options(deprecator)
36
+ @deprecators[name] = deprecator
37
+ end
38
+
39
+ # Iterates over all deprecators in this collection. If no block is given,
40
+ # returns an +Enumerator+.
41
+ def each(&block)
42
+ return to_enum(__method__) unless block
43
+ @deprecators.each_value(&block)
44
+ end
45
+
46
+ # Sets the silenced flag for all deprecators in this collection.
47
+ def silenced=(silenced)
48
+ set_option(:silenced, silenced)
49
+ end
50
+
51
+ # Sets the debug flag for all deprecators in this collection.
52
+ def debug=(debug)
53
+ set_option(:debug, debug)
54
+ end
55
+
56
+ # Sets the deprecation warning behavior for all deprecators in this
57
+ # collection.
58
+ #
59
+ # See ActiveSupport::Deprecation#behavior=.
60
+ def behavior=(behavior)
61
+ set_option(:behavior, behavior)
62
+ end
63
+
64
+ # Sets the disallowed deprecation warning behavior for all deprecators in
65
+ # this collection.
66
+ #
67
+ # See ActiveSupport::Deprecation#disallowed_behavior=.
68
+ def disallowed_behavior=(disallowed_behavior)
69
+ set_option(:disallowed_behavior, disallowed_behavior)
70
+ end
71
+
72
+ # Sets the disallowed deprecation warnings for all deprecators in this
73
+ # collection.
74
+ #
75
+ # See ActiveSupport::Deprecation#disallowed_warnings=.
76
+ def disallowed_warnings=(disallowed_warnings)
77
+ set_option(:disallowed_warnings, disallowed_warnings)
78
+ end
79
+
80
+ # Silences all deprecators in this collection for the duration of the
81
+ # given block.
82
+ #
83
+ # See ActiveSupport::Deprecation#silence.
84
+ def silence(&block)
85
+ each { |deprecator| deprecator.begin_silence }
86
+ block.call
87
+ ensure
88
+ each { |deprecator| deprecator.end_silence }
89
+ end
90
+
91
+ private
92
+ def set_option(name, value)
93
+ @options[name] = value
94
+ each { |deprecator| deprecator.public_send("#{name}=", value) }
95
+ end
96
+
97
+ def apply_options(deprecator)
98
+ @options.each do |name, value|
99
+ deprecator.public_send("#{name}=", value)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -24,10 +24,9 @@ module ActiveSupport
24
24
 
25
25
  private
26
26
  def deprecation_disallowed?(message)
27
- disallowed = ActiveSupport::Deprecation.disallowed_warnings
28
27
  return false if explicitly_allowed?(message)
29
- return true if disallowed == :all
30
- disallowed.any? do |rule|
28
+ return true if disallowed_warnings == :all
29
+ message && disallowed_warnings.any? do |rule|
31
30
  case rule
32
31
  when String, Symbol
33
32
  message.include?(rule.to_s)
@@ -41,8 +40,7 @@ module ActiveSupport
41
40
  allowances = @explicitly_allowed_warnings.value
42
41
  return false unless allowances
43
42
  return true if allowances == :all
44
- allowances = [allowances] unless allowances.kind_of?(Array)
45
- allowances.any? do |rule|
43
+ message && Array(allowances).any? do |rule|
46
44
  case rule
47
45
  when String, Symbol
48
46
  message.include?(rule.to_s)
@@ -16,38 +16,21 @@ module ActiveSupport
16
16
  # def eee; end
17
17
  # end
18
18
  #
19
- # Using the default deprecator:
20
- # ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')
19
+ # deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
20
+ #
21
+ # deprecator.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')
21
22
  # # => Fred
22
23
  #
23
24
  # Fred.new.aaa
24
- # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.1. (called from irb_binding at (irb):10)
25
+ # # DEPRECATION WARNING: aaa is deprecated and will be removed from MyGem next-release. (called from irb_binding at (irb):10)
25
26
  # # => nil
26
27
  #
27
28
  # Fred.new.bbb
28
- # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.1 (use zzz instead). (called from irb_binding at (irb):11)
29
+ # # DEPRECATION WARNING: bbb is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):11)
29
30
  # # => nil
30
31
  #
31
32
  # Fred.new.ccc
32
- # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.1 (use Bar#ccc instead). (called from irb_binding at (irb):12)
33
- # # => nil
34
- #
35
- # Passing in a custom deprecator:
36
- # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
37
- # ActiveSupport::Deprecation.deprecate_methods(Fred, ddd: :zzz, deprecator: custom_deprecator)
38
- # # => [:ddd]
39
- #
40
- # Fred.new.ddd
41
- # DEPRECATION WARNING: ddd is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):15)
42
- # # => nil
43
- #
44
- # Using a custom deprecator directly:
45
- # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
46
- # custom_deprecator.deprecate_methods(Fred, eee: :zzz)
47
- # # => [:eee]
48
- #
49
- # Fred.new.eee
50
- # DEPRECATION WARNING: eee is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):18)
33
+ # # DEPRECATION WARNING: ccc is deprecated and will be removed from MyGem next-release (use Bar#ccc instead). (called from irb_binding at (irb):12)
51
34
  # # => nil
52
35
  def deprecate_methods(target_module, *method_names)
53
36
  options = method_names.extract_options!