Skip to content

Commit

Permalink
Dice up ActiveSupport::Deprecation
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy committed Apr 18, 2009
1 parent 3202671 commit 727e9dc
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 185 deletions.
Original file line number Diff line number Diff line change
@@ -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
194 changes: 9 additions & 185 deletions activesupport/lib/active_support/deprecation.rb
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions activesupport/lib/active_support/deprecation/behaviors.rb
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions activesupport/lib/active_support/deprecation/method_wrappers.rb
Original file line number Diff line number Diff line change
@@ -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
72 changes: 72 additions & 0 deletions activesupport/lib/active_support/deprecation/proxy_wrappers.rb
Original file line number Diff line number Diff line change
@@ -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 comments on commit 727e9dc

Please sign in to comment.