Skip to content

Commit

Permalink
Version bump to 0.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
tadman committed Aug 25, 2010
1 parent f23b6be commit e22673e
Show file tree
Hide file tree
Showing 11 changed files with 423 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ rdoc
pkg pkg


## PROJECT::SPECIFIC ## PROJECT::SPECIFIC
tmp
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2009 tadman Copyright (c) 2010 Scott Tadman, The Working Group


Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
Expand Down
92 changes: 80 additions & 12 deletions README.rdoc
Original file line number Original file line Diff line number Diff line change
@@ -1,17 +1,85 @@
= sequel_simple_callbacks = sequel_simple_callbacks


Description goes here. This adds ActiveRecord style callback declarations to standard Sequel models.


== Note on Patches/Pull Requests Sequel::Model with no plugins:


* Fork the project. class MyModel < Sequel::Model
* Make your feature addition or bug fix. def before_validation
* Add tests for it. This is important so I don't break it in a check_something
future version unintentionally. check_something_else
* Commit, do not mess with rakefile, version, or history. end
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
* Send me a pull request. Bonus points for topic branches. def before_save
return unless (some_condition?)

do_something
end
end

Sequel::Model with SequelSimpleCallbacks plugin added:

Sequel::Model.plugin(SequelSimpleCallbacks)

class MyModel < Sequel::Model
before_validation :check_something, :check_something_else

before_save :do_something, :unless => :some_condition?
end

If any of the callbacks returns false then additional checking will be
pre-empted and the callback will return false. This will halt processing
of not only the chain, but the entire operation being performed, as is the
expected behavior of Sequel::Model.

Each of the callback methods takes zero or more method names to call as
part of that callback cycle:

before_save :method_1, :method_2

The execution of these methods can be limited conditionally using the
:if or :unless options either independently or in tandem:

before_save :method_1, :if => :working?, :unless => :on_break?

The blocks referenced by :if and :unless should return true or false,
but any value that evaluates as false for :if or true for :unless will
block execution of these callbacks. Note that this does not halt the
callback chain.

These arguments can be combined as demonstrated here:

before_save :method_1, :method_2,
:if => :method,
:unless => lambda { other_method },
:on => :create do
check_something
end

Any blocks given are evaluated within the context of the model in question,
but the model may be explicitly specified as a parameter to the block:

before_save do |model|
model.check_something
end

It is important to node that using these class-level declarations means that
the instance methods with the same name should not be defined:

before_save :do_something

def before_save
# WARNING: This will block the :do_something method from running,
# as this method over-rides that behavior. Calling super will not
# restore this functionality.

do_some_stuff

# Execute the default behavior as defined in the class if this mixed
# approach is strictly required. This is intended as a last-resort.
self.class.run_callbacks(self, :before_save)
end


== Copyright == Copyright


Copyright (c) 2010 tadman. See LICENSE for details. Copyright (c) 2010 Scott Tadman, The Working Group
10 changes: 5 additions & 5 deletions Rakefile
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ begin
require 'jeweler' require 'jeweler'
Jeweler::Tasks.new do |gem| Jeweler::Tasks.new do |gem|
gem.name = "sequel_simple_callbacks" gem.name = "sequel_simple_callbacks"
gem.summary = %Q{TODO: one-line summary of your gem} gem.summary = %Q[Sequel Plugin to add ActiveRecord style callback declarations]
gem.description = %Q{TODO: longer description of your gem} gem.description = %Q[This plugin makes it possible to declare simple before and after callbacks on the class level just like ActiveRecord]
gem.email = "github@tadman.ca" gem.email = "github@tadman.ca"
gem.homepage = "http://github.com/tadman/sequel_simple_callbacks" gem.homepage = "http://github.com/tadman/sequel_simple_callbacks"
gem.authors = ["tadman"] gem.authors = %w[ tadman ]
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings gem.add_development_dependency "sequel"
end end
Jeweler::GemcutterTasks.new Jeweler::GemcutterTasks.new
rescue LoadError rescue LoadError
Expand Down
1 change: 1 addition & 0 deletions VERSION
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
0.0.0
170 changes: 170 additions & 0 deletions lib/sequel_simple_callbacks.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,170 @@
module SimpleSequelCallbacks
SPECIAL_HOOKS = [
:before_validation,
:after_validation
].freeze

ADDITIONAL_HOOKS = [
:before_validation_on_create,
:before_validation_on_update,
:after_validation_on_create,
:after_validation_on_update
].freeze

STANDARD_HOOKS = (Sequel::Model::HOOKS - SPECIAL_HOOKS).freeze
INSTALLABLE_HOOKS = (Sequel::Model::HOOKS + ADDITIONAL_HOOKS).freeze

def apply(model_class)
end

def configure(model_class, *arguments, &block)
end

module ClassMethods
# Add a callback hook to the model with parameters:
# * :if => One of [ Symbol, Proc ] (optional)
# * :unless => One of [ Symbol, Proc ] (optional)
# * :on => One of [ :create, :update ] (optional)

def add_callback(chain, *args, &block)
@callbacks ||= { }
callbacks = @callbacks[chain] ||= [ ]

# Extract the options from the arguments by testing if the last
# is a Hash, otherwise default to an empty set.
options = (args[-1].is_a?(Hash)) ? args.pop : { }
option_on = options[:on]
option_if = options[:if]
option_unless = options[:unless]

callbacks << lambda do |model|
result = nil

trigger =
case (option_on)
when :create
model.new?
when :update
!model.new?
else
true
end

if (trigger and !option_if.nil?)
trigger =
case (option_if)
when Symbol, String
model.send(option_if)
when Proc
if (option_if.arity == 0)
model.instance_eval(option_if)
else
option_if.call(model)
end
else
option_if
end
end

if (trigger and !option_unless.nil?)
trigger =
case (option_unless)
when Symbol, String
!model.send(option_unless)
when Proc
if (option_unless.arity == 0)
!model.instance_eval(option_unless)
else
!option_unless.call(model)
end
else
!option_unless
end
end

if (trigger)
args.each do |callback|
result =
case (callback)
when Symbol, String
model.send(callback)
else
if (callback.arity == 0)
model.instance_eval(callback)
else
callback.call(model)
end
end

break if (result === false)
end
end

if (trigger and block)
if (block.arity == 0)
model.instance_eval(&block)
else
block.call(model)
end
end

result
end
end

def run_callbacks(model, hook)
return unless (@callbacks)

callbacks = @callbacks[hook]

return unless (callbacks)

result = nil

callbacks.each do |callback|
result = callback.call(model)

break if (result === false)
end

result
end

INSTALLABLE_HOOKS.each do |hook|
eval %Q[
def #{hook}(*args, &block)
add_callback(:#{hook}, *args, &block)
end
]
end
end

module InstanceMethods
STANDARD_HOOKS.each do |hook|
define_method(hook) do
self.class.run_callbacks(self, hook)
end
end

SPECIAL_HOOKS.each do |hook|
define_method(hook) do
self.class.run_callbacks(self, hook)

if (new?)
self.class.run_callbacks(self, :"#{hook}_on_create")
else
self.class.run_callbacks(self, :"#{hook}_on_update")
end
end
end

# This method is provided as a simple method to call arbitrary callback
# chains without having to run through the specific method
def run_callbacks(hook)
self.class.run_callbacks(self, hook)
end
end

module DatasetMethods
end
end
5 changes: 4 additions & 1 deletion test/helper.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,9 +1,12 @@
require 'rubygems' require 'rubygems'
require 'test/unit' require 'test/unit'
require 'shoulda'


$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__)) $LOAD_PATH.unshift(File.dirname(__FILE__))

require 'sequel'
require 'sqlite3'

require 'sequel_simple_callbacks' require 'sequel_simple_callbacks'


class Test::Unit::TestCase class Test::Unit::TestCase
Expand Down
45 changes: 45 additions & 0 deletions test/models/conditional.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,45 @@
if (DB.table_exists?(:conditionals))
DB.drop_table(:conditionals)
end

DB.create_table(:conditionals) do
primary_key :id
string :name
end

class ConditionalModel < Sequel::Model(:conditionals)
include ModelTriggers
plugin SimpleSequelCallbacks

before_validation do |model|
model.trigger(:before_validation_with_model)
end

before_validation do
trigger(:before_validation_without_model)
end

after_validation :on => :create do
trigger(:after_validation_only_on_create)
end

before_save :if => nil, :unless => nil do
trigger(:before_save_with_nil)
end

before_save :if => true, :unless => false do
trigger(:before_save_with_true_false)
end

after_update :only => :never do
trigger(:after_update_never_called)
end

after_save :if => false do
trigger(:after_save_not_called)
end

def never
false
end
end
26 changes: 26 additions & 0 deletions test/models/example.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,26 @@
if (DB.table_exists?(:examples))
DB.drop_table(:examples)
end

DB.create_table(:examples) do
primary_key :id
string :name
end

class ExampleModel < Sequel::Model(:examples)
include ModelTriggers

plugin SimpleSequelCallbacks

SimpleSequelCallbacks::INSTALLABLE_HOOKS.each do |hook|
send(hook, :"do_#{hook}", :if => :triggers_active?)

define_method(:"do_#{hook}") do
trigger(hook)
end
end

def triggers_active?
!name or name != 'off'
end
end
Loading

0 comments on commit e22673e

Please sign in to comment.