-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
423 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
|
@@ -19,3 +19,4 @@ rdoc | ||
pkg | pkg | ||
|
|
||
## PROJECT::SPECIFIC | ## PROJECT::SPECIFIC | ||
tmp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
0.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.