mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Get rid of DeprecatedCallbacks in ActiveRecord::Associations and finally remove it.
This commit is contained in:
parent
e58ad8ed9c
commit
97a64b6b22
5 changed files with 9 additions and 289 deletions
|
@ -485,7 +485,14 @@ module ActiveRecord
|
|||
|
||||
def callback(method, record)
|
||||
callbacks_for(method).each do |callback|
|
||||
ActiveSupport::DeprecatedCallbacks::Callback.new(method, callback, record).call(@owner, record)
|
||||
case callback
|
||||
when Symbol
|
||||
@owner.send(callback, record)
|
||||
when Proc
|
||||
callback.call(@owner, record)
|
||||
else
|
||||
callback.send(method, @owner, record)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ module ActiveRecord
|
|||
|
||||
def deprecated_callback_method(symbol) #:nodoc:
|
||||
if respond_to?(symbol)
|
||||
ActiveSupport::Deprecation.warn("Base##{symbol} has been deprecated, please use Base.#{symbol} :method instead")
|
||||
ActiveSupport::Deprecation.warn("Overwriting #{symbol} in your models has been deprecated, please use Base##{symbol} :method_name instead")
|
||||
send(symbol)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,8 +17,6 @@ module ActiveRecord
|
|||
|
||||
module Validations
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include ActiveSupport::DeprecatedCallbacks
|
||||
include ActiveModel::Validations
|
||||
|
||||
included do
|
||||
|
|
|
@ -50,7 +50,6 @@ module ActiveSupport
|
|||
autoload :Callbacks
|
||||
autoload :Concern
|
||||
autoload :Configurable
|
||||
autoload :DeprecatedCallbacks
|
||||
autoload :Deprecation
|
||||
autoload :Gzip
|
||||
autoload :Inflector
|
||||
|
|
|
@ -1,284 +0,0 @@
|
|||
require 'active_support/core_ext/array/extract_options'
|
||||
require 'active_support/core_ext/array/wrap'
|
||||
|
||||
module ActiveSupport
|
||||
# Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
|
||||
# before or after an alteration of the object state.
|
||||
#
|
||||
# Mixing in this module allows you to define callbacks in your class.
|
||||
#
|
||||
# Example:
|
||||
# class Storage
|
||||
# include ActiveSupport::DeprecatedCallbacks
|
||||
#
|
||||
# define_callbacks :before_save, :after_save
|
||||
# end
|
||||
#
|
||||
# class ConfigStorage < Storage
|
||||
# before_save :saving_message
|
||||
# def saving_message
|
||||
# puts "saving..."
|
||||
# end
|
||||
#
|
||||
# after_save do |object|
|
||||
# puts "saved"
|
||||
# end
|
||||
#
|
||||
# def save
|
||||
# run_callbacks(:before_save)
|
||||
# puts "- save"
|
||||
# run_callbacks(:after_save)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# config = ConfigStorage.new
|
||||
# config.save
|
||||
#
|
||||
# Output:
|
||||
# saving...
|
||||
# - save
|
||||
# saved
|
||||
#
|
||||
# Callbacks from parent classes are inherited.
|
||||
#
|
||||
# Example:
|
||||
# class Storage
|
||||
# include ActiveSupport::DeprecatedCallbacks
|
||||
#
|
||||
# define_callbacks :before_save, :after_save
|
||||
#
|
||||
# before_save :prepare
|
||||
# def prepare
|
||||
# puts "preparing save"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# class ConfigStorage < Storage
|
||||
# before_save :saving_message
|
||||
# def saving_message
|
||||
# puts "saving..."
|
||||
# end
|
||||
#
|
||||
# after_save do |object|
|
||||
# puts "saved"
|
||||
# end
|
||||
#
|
||||
# def save
|
||||
# run_callbacks(:before_save)
|
||||
# puts "- save"
|
||||
# run_callbacks(:after_save)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# config = ConfigStorage.new
|
||||
# config.save
|
||||
#
|
||||
# Output:
|
||||
# preparing save
|
||||
# saving...
|
||||
# - save
|
||||
# saved
|
||||
module DeprecatedCallbacks
|
||||
class CallbackChain < Array
|
||||
def self.build(kind, *methods, &block)
|
||||
methods, options = extract_options(*methods, &block)
|
||||
methods.map! { |method| Callback.new(kind, method, options) }
|
||||
new(methods)
|
||||
end
|
||||
|
||||
def run(object, options = {}, &terminator)
|
||||
enumerator = options[:enumerator] || :each
|
||||
|
||||
unless block_given?
|
||||
send(enumerator) { |callback| callback.call(object) }
|
||||
else
|
||||
send(enumerator) do |callback|
|
||||
result = callback.call(object)
|
||||
break result if terminator.call(result, object)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Decompose into more Array like behavior
|
||||
def replace_or_append!(chain)
|
||||
if index = index(chain)
|
||||
self[index] = chain
|
||||
else
|
||||
self << chain
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def find(callback, &block)
|
||||
select { |c| c == callback && (!block_given? || yield(c)) }.first
|
||||
end
|
||||
|
||||
def delete(callback)
|
||||
super(callback.is_a?(Callback) ? callback : find(callback))
|
||||
end
|
||||
|
||||
private
|
||||
def self.extract_options(*methods, &block)
|
||||
methods.flatten!
|
||||
options = methods.extract_options!
|
||||
methods << block if block_given?
|
||||
return methods, options
|
||||
end
|
||||
|
||||
def extract_options(*methods, &block)
|
||||
self.class.extract_options(*methods, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class Callback
|
||||
attr_reader :kind, :method, :identifier, :options
|
||||
|
||||
def initialize(kind, method, options = {})
|
||||
@kind = kind
|
||||
@method = method
|
||||
@identifier = options[:identifier]
|
||||
@options = options
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
case other
|
||||
when Callback
|
||||
(self.identifier && self.identifier == other.identifier) || self.method == other.method
|
||||
else
|
||||
(self.identifier && self.identifier == other) || self.method == other
|
||||
end
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
self == other
|
||||
end
|
||||
|
||||
def dup
|
||||
self.class.new(@kind, @method, @options.dup)
|
||||
end
|
||||
|
||||
def hash
|
||||
if @identifier
|
||||
@identifier.hash
|
||||
else
|
||||
@method.hash
|
||||
end
|
||||
end
|
||||
|
||||
def call(*args, &block)
|
||||
evaluate_method(method, *args, &block) if should_run_callback?(*args)
|
||||
rescue LocalJumpError
|
||||
raise ArgumentError,
|
||||
"Cannot yield from a Proc type filter. The Proc must take two " +
|
||||
"arguments and execute #call on the second argument."
|
||||
end
|
||||
|
||||
private
|
||||
def evaluate_method(method, *args, &block)
|
||||
case method
|
||||
when Symbol
|
||||
object = args.shift
|
||||
object.send(method, *args, &block)
|
||||
when String
|
||||
eval(method, args.first.instance_eval { binding })
|
||||
when Proc, Method
|
||||
method.call(*args, &block)
|
||||
else
|
||||
if method.respond_to?(kind)
|
||||
method.send(kind, *args, &block)
|
||||
else
|
||||
raise ArgumentError,
|
||||
"Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
|
||||
"a block to be invoked, or an object responding to the callback method."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def should_run_callback?(*args)
|
||||
Array.wrap(options[:if]).flatten.compact.all? { |a| evaluate_method(a, *args) } &&
|
||||
!Array.wrap(options[:unless]).flatten.compact.any? { |a| evaluate_method(a, *args) }
|
||||
end
|
||||
end
|
||||
|
||||
def self.included(base)
|
||||
base.extend ClassMethods
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def define_callbacks(*callbacks)
|
||||
ActiveSupport::Deprecation.warn('ActiveSupport::DeprecatedCallbacks has been deprecated in favor of ActiveSupport::Callbacks', caller)
|
||||
|
||||
callbacks.each do |callback|
|
||||
class_eval <<-"end_eval", __FILE__, __LINE__ + 1
|
||||
def self.#{callback}(*methods, &block) # def self.before_save(*methods, &block)
|
||||
callbacks = CallbackChain.build(:#{callback}, *methods, &block) # callbacks = CallbackChain.build(:before_save, *methods, &block)
|
||||
@#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
|
||||
@#{callback}_callbacks.concat callbacks # @before_save_callbacks.concat callbacks
|
||||
end # end
|
||||
#
|
||||
def self.#{callback}_callback_chain # def self.before_save_callback_chain
|
||||
@#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
|
||||
#
|
||||
if superclass.respond_to?(:#{callback}_callback_chain) # if superclass.respond_to?(:before_save_callback_chain)
|
||||
CallbackChain.new( # CallbackChain.new(
|
||||
superclass.#{callback}_callback_chain + # superclass.before_save_callback_chain +
|
||||
@#{callback}_callbacks # @before_save_callbacks
|
||||
) # )
|
||||
else # else
|
||||
@#{callback}_callbacks # @before_save_callbacks
|
||||
end # end
|
||||
end # end
|
||||
end_eval
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Runs all the callbacks defined for the given options.
|
||||
#
|
||||
# If a block is given it will be called after each callback receiving as arguments:
|
||||
#
|
||||
# * the result from the callback
|
||||
# * the object which has the callback
|
||||
#
|
||||
# If the result from the block evaluates to +true+, the callback chain is stopped.
|
||||
#
|
||||
# Example:
|
||||
# class Storage
|
||||
# include ActiveSupport::DeprecatedCallbacks
|
||||
#
|
||||
# define_callbacks :before_save, :after_save
|
||||
# end
|
||||
#
|
||||
# class ConfigStorage < Storage
|
||||
# before_save :pass
|
||||
# before_save :pass
|
||||
# before_save :stop
|
||||
# before_save :pass
|
||||
#
|
||||
# def pass
|
||||
# puts "pass"
|
||||
# end
|
||||
#
|
||||
# def stop
|
||||
# puts "stop"
|
||||
# return false
|
||||
# end
|
||||
#
|
||||
# def save
|
||||
# result = run_callbacks(:before_save) { |result, object| result == false }
|
||||
# puts "- save" if result
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# config = ConfigStorage.new
|
||||
# config.save
|
||||
#
|
||||
# Output:
|
||||
# pass
|
||||
# pass
|
||||
# stop
|
||||
def run_callbacks(kind, options = {}, &block)
|
||||
self.class.send("#{kind}_callback_chain").run(self, options, &block)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue