From 6d390671f639b3314437054df0d393cef10493bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 29 Dec 2009 01:15:39 +0100 Subject: Move ActiveRecord callbacks implementation to ActiveModel and make use of it. Signed-off-by: Yehuda Katz --- activemodel/lib/active_model.rb | 1 + activemodel/lib/active_model/callbacks.rb | 91 +++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 activemodel/lib/active_model/callbacks.rb (limited to 'activemodel/lib') diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index ed32a89971..f14016027c 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -30,6 +30,7 @@ module ActiveModel extend ActiveSupport::Autoload autoload :AttributeMethods + autoload :Callbacks autoload :Conversion autoload :DeprecatedErrorMethods autoload :Dirty diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb new file mode 100644 index 0000000000..f66a1ddcaa --- /dev/null +++ b/activemodel/lib/active_model/callbacks.rb @@ -0,0 +1,91 @@ +require 'active_support/callbacks' + +module ActiveModel + module Callbacks + def self.extended(base) + base.class_eval do + include ActiveSupport::Callbacks + end + end + + # Define callbacks similar to ActiveRecord ones. It means: + # + # * The callback chain is aborted whenever the block given to + # _run_callbacks returns false. + # + # * If a class is given to the fallback, it will search for + # before_create, around_create and after_create methods. + # + # == Usage + # + # First you need to define which callbacks your model will have: + # + # class MyModel + # define_model_callbacks :create + # end + # + # This will define three class methods: before_create, around_create, + # and after_create. They accept a symbol, a string, an object or a block. + # + # After you create a callback, you need to tell when they are executed. + # For example, you could do: + # + # def create + # _run_create_callbacks do + # super + # end + # end + # + # == Options + # + # define_model_callbacks accepts all options define_callbacks does, in + # case you want to overwrite a default. Besides that, it also accepts + # an :only option, where you can choose if you want all types (before, + # around or after) or just some: + # + # define_model_callbacks :initializer, :only => :after + # + def define_model_callbacks(*callbacks) + options = callbacks.extract_options! + options = { :terminator => "result == false", :scope => [:kind, :name] }.merge(options) + + types = Array(options.delete(:only)) + types = [:before, :around, :after] if types.empty? + + callbacks.each do |callback| + define_callbacks(callback, options) + + types.each do |type| + send(:"_define_#{type}_model_callback", self, callback) + end + end + end + + def _define_before_model_callback(klass, callback) #:nodoc: + klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + def self.before_#{callback}(*args, &block) + set_callback(:#{callback}, :before, *args, &block) + end + CALLBACK + end + + def _define_around_model_callback(klass, callback) #:nodoc: + klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + def self.around_#{callback}(*args, &block) + set_callback(:#{callback}, :around, *args, &block) + end + CALLBACK + end + + def _define_after_model_callback(klass, callback) #:nodoc: + klass.class_eval <<-CALLBACK, __FILE__, __LINE__ + def self.after_#{callback}(*args, &block) + options = args.extract_options! + options[:prepend] = true + options[:if] = Array(options[:if]) << "!halted && value != false" + set_callback(:#{callback}, :after, *(args << options), &block) + end + CALLBACK + end + end +end \ No newline at end of file -- cgit v1.2.3