mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
250 lines
7.3 KiB
Ruby
250 lines
7.3 KiB
Ruby
require 'yaml'
|
|
|
|
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_DEFAULT_LOGGER) ? ::RAILS_DEFAULT_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
|
|
end
|
|
|
|
# Behavior is a block that takes a message argument.
|
|
mattr_accessor :behavior
|
|
self.behavior = default_behavior
|
|
|
|
# Warnings are not silenced by default.
|
|
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)
|
|
::ActiveSupport::Deprecation.warn(self.class.deprecated_method_warning(:#{method_name}, #{options[method_name].inspect}), caller)
|
|
#{target}_without_deprecation#{punctuation}(*args, &block)
|
|
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
|
|
|
|
module Assertions #:nodoc:
|
|
def assert_deprecated(match = nil, &block)
|
|
result, warnings = collect_deprecations(&block)
|
|
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
|
|
if match
|
|
match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
|
|
assert warnings.any? { |w| w =~ match }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
|
|
end
|
|
result
|
|
end
|
|
|
|
def assert_not_deprecated(&block)
|
|
result, deprecations = collect_deprecations(&block)
|
|
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
|
|
result
|
|
end
|
|
|
|
private
|
|
def collect_deprecations
|
|
old_behavior = ActiveSupport::Deprecation.behavior
|
|
deprecations = []
|
|
ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack|
|
|
deprecations << message
|
|
end
|
|
result = yield
|
|
[result, deprecations]
|
|
ensure
|
|
ActiveSupport::Deprecation.behavior = old_behavior
|
|
end
|
|
end
|
|
|
|
class DeprecationProxy #:nodoc:
|
|
silence_warnings do
|
|
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
|
end
|
|
|
|
# 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
|
|
end
|
|
end
|
|
|
|
class Module
|
|
include ActiveSupport::Deprecation::ClassMethods
|
|
end
|
|
|
|
|
|
require 'active_support/test_case'
|
|
|
|
class ActiveSupport::TestCase
|
|
include ActiveSupport::Deprecation::Assertions
|
|
end
|
|
|
|
begin
|
|
require 'test/unit/error'
|
|
|
|
module Test
|
|
module Unit
|
|
class Error # :nodoc:
|
|
# Silence warnings when reporting test errors.
|
|
def message_with_silenced_deprecation
|
|
ActiveSupport::Deprecation.silence do
|
|
message_without_silenced_deprecation
|
|
end
|
|
end
|
|
|
|
alias_method_chain :message, :silenced_deprecation
|
|
end
|
|
end
|
|
end
|
|
rescue LoadError
|
|
# Using miniunit, ignore.
|
|
end
|