1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
# frozen_string_literal: true
module ActiveSupport
class Deprecation
class DeprecationProxy # :nodoc:
def self.new(*args, **kwargs, &block)
object = args.first
return object unless object
super
end
instance_methods.each { |m| undef_method m unless /^__|^object_id$/.match?(m) }
# Don't give a deprecation warning on inspect since test/unit and error
# logs rely on it for diagnostics.
def inspect
target.inspect
end
private
def method_missing(called, *args, &block)
warn caller_locations, called, args
target.__send__(called, *args, &block)
end
end
# DeprecatedObjectProxy transforms an object into a deprecated one. It takes an object, a deprecation message, and
# a deprecator.
#
# deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, "This object is now deprecated", ActiveSupport::Deprecation.new)
# # => #<Object:0x007fb9b34c34b0>
#
# deprecated_object.to_s
# DEPRECATION WARNING: This object is now deprecated.
# (Backtrace)
# # => "#<Object:0x007fb9b34c34b0>"
class DeprecatedObjectProxy < DeprecationProxy
def initialize(object, message, deprecator)
@object = object
@message = message
@deprecator = deprecator
end
private
def target
@object
end
def warn(callstack, called, args)
@deprecator.warn(@message, callstack)
end
end
# DeprecatedInstanceVariableProxy transforms an instance variable into a deprecated one. It takes an instance of a
# class, a method on that class, an instance variable, and a deprecator as the last argument.
#
# Trying to use the deprecated instance variable will result in a deprecation warning, pointing to the method as a
# replacement.
#
# class Example
# def initialize
# @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request, ActiveSupport::Deprecation.new)
# @_request = :special_request
# end
#
# def request
# @_request
# end
#
# def old_request
# @request
# end
# end
#
# example = Example.new
# # => #<Example:0x007fb9b31090b8 @_request=:special_request, @request=:special_request>
#
# example.old_request.to_s
# # => DEPRECATION WARNING: @request is deprecated! Call request.to_s instead of
# @request.to_s
# (Backtrace information…)
# "special_request"
#
# example.request.to_s
# # => "special_request"
class DeprecatedInstanceVariableProxy < DeprecationProxy
def initialize(instance, method, var = "@#{method}", deprecator:)
@instance = instance
@method = method
@var = var
@deprecator = deprecator
end
private
def target
@instance.__send__(@method)
end
def warn(callstack, called, args)
@deprecator.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
end
end
# DeprecatedConstantProxy transforms a constant into a deprecated one. It takes the full names of an old
# (deprecated) constant and of a new constant (both in string form) and a deprecator. The deprecated constant now
# returns the value of the new one.
#
# 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)
# PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("PLANETS", "PLANETS_POST_2006", 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"]
class DeprecatedConstantProxy < Module
def self.new(*args, **options, &block)
object = args.first
return object unless object
super
end
def initialize(old_const, new_const, deprecator, message: "#{old_const} is deprecated! Use #{new_const} instead.")
Kernel.require "active_support/inflector/methods"
@old_const = old_const
@new_const = new_const
@deprecator = deprecator
@message = message
end
instance_methods.each { |m| undef_method m unless /^__|^object_id$/.match?(m) }
# Don't give a deprecation warning on inspect since test/unit and error
# logs rely on it for diagnostics.
def inspect
target.inspect
end
# Don't give a deprecation warning on methods that IRB may invoke
# during tab-completion.
delegate :hash, :instance_methods, :name, :respond_to?, to: :target
# Returns the class of the new constant.
#
# PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
# PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006')
# PLANETS.class # => Array
def class
target.class
end
def append_features(base)
@deprecator.warn(@message, caller_locations)
base.include(target)
end
def prepend_features(base)
@deprecator.warn(@message, caller_locations)
base.prepend(target)
end
def extended(base)
@deprecator.warn(@message, caller_locations)
base.extend(target)
end
private
def target
ActiveSupport::Inflector.constantize(@new_const.to_s)
end
def const_missing(name)
@deprecator.warn(@message, caller_locations)
target.const_get(name)
end
def method_missing(...)
@deprecator.warn(@message, caller_locations)
target.__send__(...)
end
end
end
end
|