Skip to content

Commit

Permalink
Callback are implemented with ActiveModel framework
Browse files Browse the repository at this point in the history
  • Loading branch information
kazjote committed Aug 18, 2010
1 parent 2491e5a commit 7ae9a51
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 78 deletions.
3 changes: 3 additions & 0 deletions couch_potato.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,16 @@ Gem::Specification.new do |s|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<json>, [">= 0"])
s.add_runtime_dependency(%q<couchrest>, [">= 0.24"])
s.add_runtime_dependency(%q<activemodel>, [">= 0"])
else
s.add_dependency(%q<json>, [">= 0"])
s.add_dependency(%q<couchrest>, [">= 0.24"])
s.add_dependency(%q<activemodel>, [">= 0"])
end
else
s.add_dependency(%q<json>, [">= 0"])
s.add_dependency(%q<couchrest>, [">= 0.24"])
s.add_dependency(%q<activemodel>, [">= 0"])
end
end

54 changes: 29 additions & 25 deletions lib/couch_potato/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ def save_document!(document)
alias_method :save!, :save_document!

def destroy_document(document)
document.run_callbacks :before_destroy
document._deleted = true
database.delete_doc document.to_hash
document.run_callbacks :after_destroy
document.run_callbacks :destroy do
document._deleted = true
database.delete_doc document.to_hash
end
document._id = nil
document._rev = nil
end
Expand Down Expand Up @@ -112,35 +112,39 @@ def create_document(document, validate)

if validate
document.errors.clear
document.run_callbacks :before_validation_on_save
document.run_callbacks :before_validation_on_create
return false unless valid_document?(document)
document.run_callbacks :validation_on_save do
document.run_callbacks :validation_on_create do
return false unless valid_document?(document)
end
end
end

document.run_callbacks :before_save
document.run_callbacks :before_create
res = database.save_doc document.to_hash
document._rev = res['rev']
document._id = res['id']
document.run_callbacks :after_save
document.run_callbacks :after_create
document.run_callbacks :save do
document.run_callbacks :create do
res = database.save_doc document.to_hash
document._rev = res['rev']
document._id = res['id']
end
end
true
end

def update_document(document, validate)
if validate
document.errors.clear
document.run_callbacks :before_validation_on_save
document.run_callbacks :before_validation_on_update
return false unless valid_document?(document)
document.run_callbacks :validation_on_save do
document.run_callbacks :validation_on_update do
return false unless valid_document?(document)
end
end
end

document.run_callbacks :save do
document.run_callbacks :update do
res = database.save_doc document.to_hash
document._rev = res['rev']
end
end

document.run_callbacks :before_save
document.run_callbacks :before_update
res = database.save_doc document.to_hash
document._rev = res['rev']
document.run_callbacks :after_save
document.run_callbacks :after_update
true
end

Expand All @@ -158,4 +162,4 @@ def database
end

end
end
end
55 changes: 11 additions & 44 deletions lib/couch_potato/persistence/callbacks.rb
Original file line number Diff line number Diff line change
@@ -1,62 +1,29 @@
require 'active_support/concern'
require 'active_model/callbacks'

module CouchPotato
module Persistence
module Callbacks
def self.included(base) #:nodoc:
base.extend ClassMethods
base.extend ActiveModel::Callbacks

base.class_eval do
attr_accessor :skip_callbacks
def self.callbacks #:nodoc:
@callbacks ||= {:before_validation => [], :before_validation_on_create => [],
:before_validation_on_update => [], :before_validation_on_save => [], :before_create => [],
:after_create => [], :before_update => [], :after_update => [],
:before_save => [], :after_save => [],
:before_destroy => [], :after_destroy => []}
end

define_model_callbacks :create, :save, :update, :destroy
define_model_callbacks *[:save, :create, :update].map {|c| :"validation_on_#{c}"}
define_model_callbacks :validation unless Config.validation_framework == :active_model
end
end

# Runs all callbacks on a model with the given name, e.g. :after_create.
#
# This method is called by the CouchPotato::Database object when saving/destroying an object
def run_callbacks(name)
def run_callbacks(name, &block)
return if skip_callbacks

callbacks = self.class.ancestors.map do |clazz|
clazz.callbacks[name] if clazz.respond_to?(:callbacks)
end.flatten.compact.uniq

callbacks.each do |callback|
if [Symbol, String].include?(callback.class)
send callback
elsif callback.is_a?(Proc)
callback.call self
else
raise "Don't know how to handle callback of type #{callback.class.name}"
end
end
end

module ClassMethods
[
:before_validation,
:before_validation_on_create,
:before_validation_on_update,
:before_validation_on_save,
:before_create,
:before_save,
:before_update,
:before_destroy,
:after_update,
:after_save,
:after_create,
:after_destroy
].each do |callback|
define_method callback do |*names|
callbacks[callback].push *names
end
end
send(:"_run_#{name}_callbacks", &block)
end
end
end
end
end
11 changes: 6 additions & 5 deletions lib/couch_potato/validation/with_validatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ def self.included(base)
# Override the validate method to first run before_validation callback
def valid?
errors.clear
run_callbacks :before_validation
before_validation_errors = errors.errors.dup
super
before_validation_errors.each do |k, v|
v.each {|message| errors.add(k, message)}
run_callbacks :validation do
before_validation_errors = errors.errors.dup
super
before_validation_errors.each do |k, v|
v.each {|message| errors.add(k, message)}
end
end
errors.empty?
end
Expand Down
6 changes: 3 additions & 3 deletions spec/callbacks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def eat_apple

it "should run all callback methods given to the callback method call" do
monkey = Monkey.new
monkey.run_callbacks :before_create
monkey.run_callbacks :create
monkey.eaten_banana.should be_true
monkey.eaten_apple.should be_true
end
Expand Down Expand Up @@ -266,7 +266,7 @@ def eat_apple
describe "lambda callbacks" do
it "should run the lambda" do
recorder = CallbackRecorder.new
recorder.run_callbacks :before_create
recorder.run_callbacks :create
recorder.lambda_works.should be_true
end
end
Expand Down Expand Up @@ -305,4 +305,4 @@ def check_name
user.valid?.should == true
user.errors.on(:name).should == nil
end
end
end
2 changes: 1 addition & 1 deletion spec/unit/callbacks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ def watered?
end
end

end
end

2 comments on commit 7ae9a51

@langalex
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work. do we really need the activesupport dependency though?

@kazjote
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks :)

If it is for require 'active_support/concern' - I think it might be the bug in ActiveModel and it should be required by ActiveModel itself.

Anyway ActiveModel depends on ActiveRecord so using ActiveModel we depend on ActiveSupport.

Please sign in to comment.