diff options
Diffstat (limited to 'activesupport/lib/active_support/deprecation')
4 files changed, 115 insertions, 43 deletions
diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb index 328b8c320a..28d2d78643 100644 --- a/activesupport/lib/active_support/deprecation/behaviors.rb +++ b/activesupport/lib/active_support/deprecation/behaviors.rb @@ -20,7 +20,7 @@ module ActiveSupport log: ->(message, callstack) { logger = - if defined?(Rails) && Rails.logger + if defined?(Rails.logger) && Rails.logger Rails.logger else require 'active_support/logger' @@ -38,6 +38,18 @@ module ActiveSupport silence: ->(message, callstack) {}, } + # Behavior module allows to determine how to display deprecation messages. + # You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+ + # constant. Available behaviors are: + # + # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>. + # [+stderr+] Log all deprecation warnings to +$stderr+. + # [+log+] Log all deprecation warnings to +Rails.logger+. + # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+. + # [+silence+] Do nothing. + # + # Setting behaviors only affects deprecations that happen after boot time. + # For more information you can read the documentation of the +behavior=+ method. module Behavior # Whether to print a backtrace along with the warning. attr_accessor :debug diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb index cab8a1b14d..32fe8025fe 100644 --- a/activesupport/lib/active_support/deprecation/method_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb @@ -9,35 +9,61 @@ module ActiveSupport # module Fred # extend self # - # def foo; end - # def bar; end - # def baz; end + # def aaa; end + # def bbb; end + # def ccc; end + # def ddd; end + # def eee; end # end # - # ActiveSupport::Deprecation.deprecate_methods(Fred, :foo, bar: :qux, baz: 'use Bar#baz instead') - # # => [:foo, :bar, :baz] + # Using the default deprecator: + # ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead') + # # => [:aaa, :bbb, :ccc] # - # Fred.foo - # # => "DEPRECATION WARNING: foo is deprecated and will be removed from Rails 4.1." + # Fred.aaa + # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.0. (called from irb_binding at (irb):10) + # # => nil # - # Fred.bar - # # => "DEPRECATION WARNING: bar is deprecated and will be removed from Rails 4.1 (use qux instead)." + # Fred.bbb + # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.0 (use zzz instead). (called from irb_binding at (irb):11) + # # => nil # - # Fred.baz - # # => "DEPRECATION WARNING: baz is deprecated and will be removed from Rails 4.1 (use Bar#baz instead)." + # Fred.ccc + # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.0 (use Bar#ccc instead). (called from irb_binding at (irb):12) + # # => nil + # + # Passing in a custom deprecator: + # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem') + # ActiveSupport::Deprecation.deprecate_methods(Fred, ddd: :zzz, deprecator: custom_deprecator) + # # => [:ddd] + # + # Fred.ddd + # DEPRECATION WARNING: ddd is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):15) + # # => nil + # + # Using a custom deprecator directly: + # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem') + # custom_deprecator.deprecate_methods(Fred, eee: :zzz) + # # => [:eee] + # + # Fred.eee + # DEPRECATION WARNING: eee is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):18) + # # => nil def deprecate_methods(target_module, *method_names) options = method_names.extract_options! - deprecator = options.delete(:deprecator) || ActiveSupport::Deprecation.instance + deprecator = options.delete(:deprecator) || self method_names += options.keys - method_names.each do |method_name| - target_module.alias_method_chain(method_name, :deprecation) do |target, punctuation| - target_module.send(:define_method, "#{target}_with_deprecation#{punctuation}") do |*args, &block| + mod = Module.new do + method_names.each do |method_name| + define_method(method_name) do |*args, &block| deprecator.deprecation_warning(method_name, options[method_name]) - send(:"#{target}_without_deprecation#{punctuation}", *args, &block) + super(*args, &block) end end end + + target_module.prepend(mod) end end end diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb index a03a66b96b..6f0ad445fc 100644 --- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb @@ -20,20 +20,22 @@ module ActiveSupport private def method_missing(called, *args, &block) - warn caller, called, args + warn caller_locations, called, args target.__send__(called, *args, &block) end end - # This DeprecatedObjectProxy transforms object to deprecated object. + # DeprecatedObjectProxy transforms an object into a deprecated one. It + # takes an object, a deprecation message and optionally a deprecator. The + # deprecator defaults to +ActiveSupport::Deprecator+ if none is specified. # - # @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!") - # @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!", deprecator_instance) + # deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, "This object is now deprecated") + # # => #<Object:0x007fb9b34c34b0> # - # When someone executes any method except +inspect+ on proxy object this will - # trigger +warn+ method on +deprecator_instance+. - # - # Default deprecator is <tt>ActiveSupport::Deprecation</tt> + # deprecated_object.to_s + # DEPRECATION WARNING: This object is now deprecated. + # (Backtrace) + # # => "#<Object:0x007fb9b34c34b0>" class DeprecatedObjectProxy < DeprecationProxy def initialize(object, message, deprecator = ActiveSupport::Deprecation.instance) @object = object @@ -51,13 +53,16 @@ module ActiveSupport end end - # This DeprecatedInstanceVariableProxy transforms instance variable to - # deprecated instance variable. + # DeprecatedInstanceVariableProxy transforms an instance variable into a + # deprecated one. It takes an instance of a class, a method on that class + # and an instance variable. It optionally takes a deprecator as the last + # argument. The deprecator defaults to +ActiveSupport::Deprecator+ if none + # is specified. # # class Example - # def initialize(deprecator) - # @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request, deprecator) - # @_request = :a_request + # def initialize + # @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request) + # @_request = :special_request # end # # def request @@ -69,12 +74,17 @@ module ActiveSupport # end # end # - # When someone execute any method on @request variable this will trigger - # +warn+ method on +deprecator_instance+ and will fetch <tt>@_request</tt> - # variable via +request+ method and execute the same method on non-proxy - # instance variable. + # 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 + # (Bactrace information…) + # "special_request" # - # Default deprecator is <tt>ActiveSupport::Deprecation</tt>. + # example.request.to_s + # # => "special_request" class DeprecatedInstanceVariableProxy < DeprecationProxy def initialize(instance, method, var = "@#{method}", deprecator = ActiveSupport::Deprecation.instance) @instance = instance @@ -93,15 +103,23 @@ module ActiveSupport end end - # This DeprecatedConstantProxy transforms constant to deprecated constant. + # DeprecatedConstantProxy transforms a constant into a deprecated one. It + # takes the names of an old (deprecated) constant and of a new constant + # (both in string form) and optionally a deprecator. The deprecator defaults + # to +ActiveSupport::Deprecator+ if none is specified. The deprecated constant + # now returns the value of the new one. + # + # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto) # - # OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST') - # OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST', deprecator_instance) + # (In a later update, the original implementation of `PLANETS` has been removed.) # - # When someone use old constant this will trigger +warn+ method on - # +deprecator_instance+. + # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune) + # PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006') # - # Default deprecator is <tt>ActiveSupport::Deprecation</tt>. + # PLANETS.map { |planet| planet.capitalize } + # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead. + # (Bactrace information…) + # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"] class DeprecatedConstantProxy < DeprecationProxy def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance) @old_const = old_const @@ -109,6 +127,11 @@ module ActiveSupport @deprecator = deprecator end + # 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 diff --git a/activesupport/lib/active_support/deprecation/reporting.rb b/activesupport/lib/active_support/deprecation/reporting.rb index a7d265d732..bbe25c9260 100644 --- a/activesupport/lib/active_support/deprecation/reporting.rb +++ b/activesupport/lib/active_support/deprecation/reporting.rb @@ -14,7 +14,7 @@ module ActiveSupport def warn(message = nil, callstack = nil) return if silenced - callstack ||= caller(2) + callstack ||= caller_locations(2) deprecation_message(callstack, message).tap do |m| behavior.each { |b| b.call(m, callstack) } end @@ -37,7 +37,7 @@ module ActiveSupport end def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil) - caller_backtrace ||= caller(2) + caller_backtrace ||= caller_locations(2) deprecated_method_warning(deprecated_method_name, message).tap do |msg| warn(msg, caller_backtrace) end @@ -79,6 +79,17 @@ module ActiveSupport end def extract_callstack(callstack) + return _extract_callstack(callstack) if callstack.first.is_a? String + + rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/" + offending_line = callstack.find { |frame| + !frame.absolute_path.start_with?(rails_gem_root) + } || callstack.first + [offending_line.path, offending_line.lineno, offending_line.label] + end + + def _extract_callstack(callstack) + warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/" offending_line = callstack.find { |line| !line.start_with?(rails_gem_root) } || callstack.first if offending_line |