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
|
# frozen_string_literal: true
require "active_support/notifications"
module ActiveSupport
# Raised when ActiveSupport::Deprecation::Behavior#behavior is set with <tt>:raise</tt>.
# You would set <tt>:raise</tt>, as a behavior to raise errors and proactively report exceptions from deprecations.
class DeprecationException < StandardError
end
class Deprecation
# Default warning behaviors per Rails.env.
DEFAULT_BEHAVIORS = {
raise: ->(message, callstack, deprecator) do
e = DeprecationException.new(message)
e.set_backtrace(callstack.map(&:to_s))
raise e
end,
stderr: ->(message, callstack, deprecator) do
$stderr.puts(message)
$stderr.puts callstack.join("\n ") if deprecator.debug
end,
log: ->(message, callstack, deprecator) do
logger =
if defined?(Rails.logger) && Rails.logger
Rails.logger
else
require "active_support/logger"
ActiveSupport::Logger.new($stderr)
end
logger.warn message
logger.debug callstack.join("\n ") if deprecator.debug
end,
notify: ->(message, callstack, deprecator) do
ActiveSupport::Notifications.instrument(
"deprecation.#{deprecator.gem_name.underscore.tr("/", "_")}",
message: message,
callstack: callstack,
gem_name: deprecator.gem_name,
deprecation_horizon: deprecator.deprecation_horizon,
)
end,
silence: ->(message, callstack, deprecator) { },
report: ->(message, callstack, deprecator) do
error = DeprecationException.new(message)
error.set_backtrace(callstack.map(&:to_s))
ActiveSupport.error_reporter.report(error)
end
}
# 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 ActiveSupport::DeprecationException.
# [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
# [+:log+] Log all deprecation warnings to +Rails.logger+.
# [+:notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
# [+:report+] Use ActiveSupport::ErrorReporter to report deprecations.
# [+:silence+] Do nothing. On \Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
#
# 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
# Returns the current behavior or if one isn't set, defaults to +:stderr+.
def behavior
@behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
end
# Returns the current behavior for disallowed deprecations or if one isn't set, defaults to +:raise+.
def disallowed_behavior
@disallowed_behavior ||= [DEFAULT_BEHAVIORS[:raise]]
end
# Sets the behavior to the specified value. Can be a single value, array,
# or an object that responds to +call+.
#
# Available behaviors:
#
# [+:raise+] Raise ActiveSupport::DeprecationException.
# [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
# [+:log+] Log all deprecation warnings to +Rails.logger+.
# [+:notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
# [+:report+] Use ActiveSupport::ErrorReporter to report deprecations.
# [+:silence+] Do nothing.
#
# Setting behaviors only affects deprecations that happen after boot time.
# Deprecation warnings raised by gems are not affected by this setting
# because they happen before \Rails boots up.
#
# deprecator = ActiveSupport::Deprecation.new
# deprecator.behavior = :stderr
# deprecator.behavior = [:stderr, :log]
# deprecator.behavior = MyCustomHandler
# deprecator.behavior = ->(message, callstack, deprecation_horizon, gem_name) {
# # custom stuff
# }
#
# If you are using \Rails, you can set
# <tt>config.active_support.report_deprecations = false</tt> to disable
# all deprecation behaviors. This is similar to the +:silence+ option but
# more performant.
def behavior=(behavior)
@behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
end
# Sets the behavior for disallowed deprecations (those configured by
# ActiveSupport::Deprecation#disallowed_warnings=) to the specified
# value. As with #behavior=, this can be a single value, array, or an
# object that responds to +call+.
def disallowed_behavior=(behavior)
@disallowed_behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
end
private
def arity_coerce(behavior)
unless behavior.respond_to?(:call)
raise ArgumentError, "#{behavior.inspect} is not a valid deprecation behavior."
end
case arity_of_callable(behavior)
when 2
->(message, callstack, deprecator) do
behavior.call(message, callstack)
end
when -2..3
behavior
else
->(message, callstack, deprecator) do
behavior.call(message, callstack, deprecator.deprecation_horizon, deprecator.gem_name)
end
end
end
def arity_of_callable(callable)
callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity
end
end
end
end
|