Dice up ActiveSupport::Deprecation
This commit is contained in:
parent
3202671dc9
commit
727e9dc18a
|
@ -0,0 +1,9 @@
|
|||
class Module
|
||||
# Declare that a method has been deprecated.
|
||||
# deprecate :foo
|
||||
# deprecate :bar => 'message'
|
||||
# deprecate :foo, :bar, :baz => 'warning!', :qux => 'gone!'
|
||||
def deprecate(*method_names)
|
||||
ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
|
||||
end
|
||||
end
|
|
@ -1,194 +1,18 @@
|
|||
require 'yaml'
|
||||
require 'active_support/deprecation/behaviors'
|
||||
require 'active_support/deprecation/reporting'
|
||||
require 'active_support/deprecation/method_wrappers'
|
||||
require 'active_support/deprecation/proxy_wrappers'
|
||||
|
||||
module ActiveSupport
|
||||
module Deprecation #:nodoc:
|
||||
mattr_accessor :debug
|
||||
self.debug = false
|
||||
|
||||
# Choose the default warn behavior according to RAILS_ENV.
|
||||
# Ignore deprecation warnings in production.
|
||||
DEFAULT_BEHAVIORS = {
|
||||
'test' => Proc.new { |message, callstack|
|
||||
$stderr.puts(message)
|
||||
$stderr.puts callstack.join("\n ") if debug
|
||||
},
|
||||
'development' => Proc.new { |message, callstack|
|
||||
logger = defined?(Rails) ? Rails.logger : Logger.new($stderr)
|
||||
logger.warn message
|
||||
logger.debug callstack.join("\n ") if debug
|
||||
}
|
||||
}
|
||||
|
||||
class << self
|
||||
def warn(message = nil, callstack = caller)
|
||||
behavior.call(deprecation_message(callstack, message), callstack) if behavior && !silenced?
|
||||
end
|
||||
|
||||
def default_behavior
|
||||
if defined?(RAILS_ENV)
|
||||
DEFAULT_BEHAVIORS[RAILS_ENV.to_s]
|
||||
else
|
||||
DEFAULT_BEHAVIORS['test']
|
||||
end
|
||||
end
|
||||
|
||||
# Have deprecations been silenced?
|
||||
def silenced?
|
||||
@silenced = false unless defined?(@silenced)
|
||||
@silenced
|
||||
end
|
||||
|
||||
# Silence deprecation warnings within the block.
|
||||
def silence
|
||||
old_silenced, @silenced = @silenced, true
|
||||
yield
|
||||
ensure
|
||||
@silenced = old_silenced
|
||||
end
|
||||
|
||||
attr_writer :silenced
|
||||
|
||||
|
||||
private
|
||||
def deprecation_message(callstack, message = nil)
|
||||
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
|
||||
"DEPRECATION WARNING: #{message}. #{deprecation_caller_message(callstack)}"
|
||||
end
|
||||
|
||||
def deprecation_caller_message(callstack)
|
||||
file, line, method = extract_callstack(callstack)
|
||||
if file
|
||||
if line && method
|
||||
"(called from #{method} at #{file}:#{line})"
|
||||
else
|
||||
"(called from #{file}:#{line})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def extract_callstack(callstack)
|
||||
if md = callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
|
||||
md.captures
|
||||
else
|
||||
callstack.first
|
||||
end
|
||||
end
|
||||
# The version the deprecated behavior will be removed, by default.
|
||||
attr_accessor :deprecation_horizon
|
||||
end
|
||||
self.deprecation_horizon = '3.0'
|
||||
|
||||
# Behavior is a block that takes a message argument.
|
||||
mattr_accessor :behavior
|
||||
self.behavior = default_behavior
|
||||
|
||||
# Warnings are not silenced by default.
|
||||
# By default, warnings are not silenced and debugging is off.
|
||||
self.silenced = false
|
||||
|
||||
module ClassMethods #:nodoc:
|
||||
# Declare that a method has been deprecated.
|
||||
def deprecate(*method_names)
|
||||
options = method_names.extract_options!
|
||||
method_names = method_names + options.keys
|
||||
method_names.each do |method_name|
|
||||
alias_method_chain(method_name, :deprecation) do |target, punctuation|
|
||||
class_eval(<<-EOS, __FILE__, __LINE__)
|
||||
def #{target}_with_deprecation#{punctuation}(*args, &block) # def generate_secret_with_deprecation(*args, &block)
|
||||
::ActiveSupport::Deprecation.warn( # ::ActiveSupport::Deprecation.warn(
|
||||
self.class.deprecated_method_warning( # self.class.deprecated_method_warning(
|
||||
:#{method_name}, # :generate_secret,
|
||||
#{options[method_name].inspect}), # "You should use ActiveSupport::SecureRandom.hex(64)"),
|
||||
caller # caller
|
||||
) # )
|
||||
#{target}_without_deprecation#{punctuation}(*args, &block) # generate_secret_without_deprecation(*args, &block)
|
||||
end # end
|
||||
EOS
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def deprecated_method_warning(method_name, message=nil)
|
||||
warning = "#{method_name} is deprecated and will be removed from Rails #{deprecation_horizon}"
|
||||
case message
|
||||
when Symbol then "#{warning} (use #{message} instead)"
|
||||
when String then "#{warning} (#{message})"
|
||||
else warning
|
||||
end
|
||||
end
|
||||
|
||||
def deprecation_horizon
|
||||
'2.3'
|
||||
end
|
||||
end
|
||||
|
||||
class DeprecationProxy #:nodoc:
|
||||
instance_methods.each { |m| undef_method m unless 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, called, args
|
||||
target.__send__(called, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class DeprecatedObjectProxy < DeprecationProxy
|
||||
def initialize(object, message)
|
||||
@object = object
|
||||
@message = message
|
||||
end
|
||||
|
||||
private
|
||||
def target
|
||||
@object
|
||||
end
|
||||
|
||||
def warn(callstack, called, args)
|
||||
ActiveSupport::Deprecation.warn(@message, callstack)
|
||||
end
|
||||
end
|
||||
|
||||
# Stand-in for <tt>@request</tt>, <tt>@attributes</tt>, <tt>@params</tt>, etc.
|
||||
# which emits deprecation warnings on any method call (except +inspect+).
|
||||
class DeprecatedInstanceVariableProxy < DeprecationProxy #:nodoc:
|
||||
def initialize(instance, method, var = "@#{method}")
|
||||
@instance, @method, @var = instance, method, var
|
||||
end
|
||||
|
||||
private
|
||||
def target
|
||||
@instance.__send__(@method)
|
||||
end
|
||||
|
||||
def warn(callstack, called, args)
|
||||
ActiveSupport::Deprecation.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
|
||||
end
|
||||
end
|
||||
|
||||
class DeprecatedConstantProxy < DeprecationProxy #:nodoc:
|
||||
def initialize(old_const, new_const)
|
||||
@old_const = old_const
|
||||
@new_const = new_const
|
||||
end
|
||||
|
||||
def class
|
||||
target.class
|
||||
end
|
||||
|
||||
private
|
||||
def target
|
||||
@new_const.to_s.constantize
|
||||
end
|
||||
|
||||
def warn(callstack, called, args)
|
||||
ActiveSupport::Deprecation.warn("#{@old_const} is deprecated! Use #{@new_const} instead.", callstack)
|
||||
end
|
||||
end
|
||||
self.debug = false
|
||||
end
|
||||
end
|
||||
|
||||
class Module
|
||||
include ActiveSupport::Deprecation::ClassMethods
|
||||
end
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
module ActiveSupport
|
||||
module Deprecation
|
||||
class << self
|
||||
# Behavior is a block that takes a message argument.
|
||||
attr_writer :behavior
|
||||
|
||||
# Whether to print a backtrace along with the warning.
|
||||
attr_accessor :debug
|
||||
|
||||
def behavior
|
||||
@behavior ||= default_behavior
|
||||
end
|
||||
|
||||
def default_behavior
|
||||
Deprecation::DEFAULT_BEHAVIORS[defined?(Rails) ? Rails.env.to_s : 'test']
|
||||
end
|
||||
end
|
||||
|
||||
# Default warning behaviors per Rails.env. Ignored in production.
|
||||
DEFAULT_BEHAVIORS = {
|
||||
'test' => Proc.new { |message, callstack|
|
||||
$stderr.puts(message)
|
||||
$stderr.puts callstack.join("\n ") if debug
|
||||
},
|
||||
'development' => Proc.new { |message, callstack|
|
||||
logger = defined?(Rails) ? Rails.logger : Logger.new($stderr)
|
||||
logger.warn message
|
||||
logger.debug callstack.join("\n ") if debug
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
require 'active_support/core_ext/module/deprecation'
|
||||
|
||||
module ActiveSupport
|
||||
class << Deprecation
|
||||
# Declare that a method has been deprecated.
|
||||
def deprecate_methods(target_module, *method_names)
|
||||
options = method_names.extract_options!
|
||||
method_names += options.keys
|
||||
|
||||
method_names.each do |method_name|
|
||||
target_module.alias_method_chain(method_name, :deprecation) do |target, punctuation|
|
||||
target_module.module_eval(<<-end_eval, __FILE__, __LINE__)
|
||||
def #{target}_with_deprecation#{punctuation}(*args, &block) # def generate_secret_with_deprecation(*args, &block)
|
||||
::ActiveSupport::Deprecation.warn( # ::ActiveSupport::Deprecation.warn(
|
||||
::ActiveSupport::Deprecation.deprecated_method_warning( # ::ActiveSupport::Deprecation.deprecated_method_warning(
|
||||
:#{method_name}, # :generate_secret,
|
||||
#{options[method_name].inspect}), # "You should use ActiveSupport::SecureRandom.hex(64)"),
|
||||
caller # caller
|
||||
) # )
|
||||
#{target}_without_deprecation#{punctuation}(*args, &block) # generate_secret_without_deprecation(*args, &block)
|
||||
end # end
|
||||
end_eval
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,72 @@
|
|||
module ActiveSupport
|
||||
module Deprecation
|
||||
class DeprecationProxy #:nodoc:
|
||||
instance_methods.each { |m| undef_method m unless 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, called, args
|
||||
target.__send__(called, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class DeprecatedObjectProxy < DeprecationProxy #:nodoc:
|
||||
def initialize(object, message)
|
||||
@object = object
|
||||
@message = message
|
||||
end
|
||||
|
||||
private
|
||||
def target
|
||||
@object
|
||||
end
|
||||
|
||||
def warn(callstack, called, args)
|
||||
ActiveSupport::Deprecation.warn(@message, callstack)
|
||||
end
|
||||
end
|
||||
|
||||
# Stand-in for <tt>@request</tt>, <tt>@attributes</tt>, <tt>@params</tt>, etc.
|
||||
# which emits deprecation warnings on any method call (except +inspect+).
|
||||
class DeprecatedInstanceVariableProxy < DeprecationProxy #:nodoc:
|
||||
def initialize(instance, method, var = "@#{method}")
|
||||
@instance, @method, @var = instance, method, var
|
||||
end
|
||||
|
||||
private
|
||||
def target
|
||||
@instance.__send__(@method)
|
||||
end
|
||||
|
||||
def warn(callstack, called, args)
|
||||
ActiveSupport::Deprecation.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
|
||||
end
|
||||
end
|
||||
|
||||
class DeprecatedConstantProxy < DeprecationProxy #:nodoc:
|
||||
def initialize(old_const, new_const)
|
||||
@old_const = old_const
|
||||
@new_const = new_const
|
||||
end
|
||||
|
||||
def class
|
||||
target.class
|
||||
end
|
||||
|
||||
private
|
||||
def target
|
||||
@new_const.to_s.constantize
|
||||
end
|
||||
|
||||
def warn(callstack, called, args)
|
||||
ActiveSupport::Deprecation.warn("#{@old_const} is deprecated! Use #{@new_const} instead.", callstack)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
module ActiveSupport
|
||||
module Deprecation
|
||||
class << self
|
||||
attr_accessor :silenced
|
||||
|
||||
def warn(message = nil, callstack = caller)
|
||||
if behavior && !silenced
|
||||
behavior.call(deprecation_message(callstack, message), callstack)
|
||||
end
|
||||
end
|
||||
|
||||
# Silence deprecation warnings within the block.
|
||||
def silence
|
||||
old_silenced, @silenced = @silenced, true
|
||||
yield
|
||||
ensure
|
||||
@silenced = old_silenced
|
||||
end
|
||||
|
||||
def deprecated_method_warning(method_name, message = nil)
|
||||
warning = "#{method_name} is deprecated and will be removed from Rails #{deprecation_horizon}"
|
||||
case message
|
||||
when Symbol then "#{warning} (use #{message} instead)"
|
||||
when String then "#{warning} (#{message})"
|
||||
else warning
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def deprecation_message(callstack, message = nil)
|
||||
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
|
||||
"DEPRECATION WARNING: #{message}. #{deprecation_caller_message(callstack)}"
|
||||
end
|
||||
|
||||
def deprecation_caller_message(callstack)
|
||||
file, line, method = extract_callstack(callstack)
|
||||
if file
|
||||
if line && method
|
||||
"(called from #{method} at #{file}:#{line})"
|
||||
else
|
||||
"(called from #{file}:#{line})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def extract_callstack(callstack)
|
||||
if md = callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
|
||||
md.captures
|
||||
else
|
||||
callstack.first
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue