diff --git a/activesupport/lib/active_support/deprecation/constant_accessor.rb b/activesupport/lib/active_support/deprecation/constant_accessor.rb
index 8763c6d5a6..0eaaabb8a4 100644
--- a/activesupport/lib/active_support/deprecation/constant_accessor.rb
+++ b/activesupport/lib/active_support/deprecation/constant_accessor.rb
@@ -2,28 +2,6 @@
module ActiveSupport
class Deprecation
- # DeprecatedConstantAccessor transforms a constant into a deprecated one by
- # hooking +const_missing+.
- #
- # It takes the names of an old (deprecated) constant and of a new constant
- # (both in string form) and a deprecator.
- #
- # The deprecated constant now returns the same object as the new one rather
- # than a proxy object, so it can be used transparently in +rescue+ blocks
- # etc.
- #
- # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto)
- #
- # # (In a later update, the original implementation of `PLANETS` has been removed.)
- #
- # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
- # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
- # deprecate_constant 'PLANETS', 'PLANETS_POST_2006', deprecator: ActiveSupport::Deprecation.new
- #
- # PLANETS.map { |planet| planet.capitalize }
- # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
- # (Backtrace information…)
- # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
module DeprecatedConstantAccessor
def self.included(base)
require "active_support/inflector/methods"
@@ -39,9 +17,53 @@ def const_missing(missing_const_name)
super
end
- def deprecate_constant(const_name, new_constant, deprecator:, message: nil)
+ # Provides a way to rename constants with a deprecation cycle in which
+ # both the old and new names work, but using the old one prints a
+ # deprecation message.
+ #
+ # In order to rename A::B to C::D, you need to delete the
+ # definition of A::B and declare the deprecation in +A+:
+ #
+ # require "active_support/deprecation"
+ #
+ # module A
+ # include ActiveSupport::Deprecation::DeprecatedConstantAccessor
+ #
+ # deprecate_constant "B", "C::D", deprecator: ActiveSupport::Deprecation.new
+ # end
+ #
+ # The first argument is a constant name (no colons). It is the name of
+ # the constant you want to deprecate in the enclosing class or module.
+ #
+ # The second argument is the constant path of the replacement. That
+ # has to be a full path even if the replacement is defined in the same
+ # namespace as the deprecated one was.
+ #
+ # In both cases, strings and symbols are supported.
+ #
+ # The +deprecator+ keyword argument is the object that will print the
+ # deprecation message, an instance of ActiveSupport::Deprecation.
+ #
+ # With that in place, client code referencing A::B will see
+ #
+ # DEPRECATION WARNING: A::B is deprecated! Use C::D instead.
+ # (called from ...)
+ #
+ # The message can be customized with the optional +message+ keyword
+ # argument.
+ #
+ # For this to work, a +const_missing+ hook is installed. When client
+ # code references the deprecated constant, the callback prints the
+ # message and constantizes the replacement.
+ #
+ # Caveat: If the deprecated constant name is reachable in a different
+ # namespace and Ruby constant lookup finds it, the hook won't be
+ # called and the deprecation won't work as intended. This may happen,
+ # for example, if an ancestor of the enclosing namespace has a
+ # constant with the same name. This is an unsupported edge case.
+ def deprecate_constant(old_constant_name, new_constant_path, deprecator:, message: nil)
class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
- class_variable_get(:@@_deprecated_constants)[const_name.to_s] = { new: new_constant, message: message, deprecator: deprecator }
+ class_variable_get(:@@_deprecated_constants)[old_constant_name.to_s] = { new: new_constant_path, message: message, deprecator: deprecator }
end
end
base.singleton_class.prepend extension