sequel_simple_callbacks 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ tmp
23
+ *.gem
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Scott Tadman, The Working Group
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,85 @@
1
+ = sequel_simple_callbacks
2
+
3
+ This adds ActiveRecord style callback declarations to standard Sequel models.
4
+
5
+ Sequel::Model with no plugins:
6
+
7
+ class MyModel < Sequel::Model
8
+ def before_validation
9
+ check_something
10
+ check_something_else
11
+ end
12
+
13
+ def before_save
14
+ return unless (some_condition?)
15
+
16
+ do_something
17
+ end
18
+ end
19
+
20
+ Sequel::Model with SequelSimpleCallbacks plugin added:
21
+
22
+ Sequel::Model.plugin(SequelSimpleCallbacks)
23
+
24
+ class MyModel < Sequel::Model
25
+ before_validation :check_something, :check_something_else
26
+
27
+ before_save :do_something, :unless => :some_condition?
28
+ end
29
+
30
+ If any of the callbacks returns false then additional checking will be
31
+ pre-empted and the callback will return false. This will halt processing
32
+ of not only the chain, but the entire operation being performed, as is the
33
+ expected behavior of Sequel::Model.
34
+
35
+ Each of the callback methods takes zero or more method names to call as
36
+ part of that callback cycle:
37
+
38
+ before_save :method_1, :method_2
39
+
40
+ The execution of these methods can be limited conditionally using the
41
+ :if or :unless options either independently or in tandem:
42
+
43
+ before_save :method_1, :if => :working?, :unless => :on_break?
44
+
45
+ The blocks referenced by :if and :unless should return true or false,
46
+ but any value that evaluates as false for :if or true for :unless will
47
+ block execution of these callbacks. Note that this does not halt the
48
+ callback chain.
49
+
50
+ These arguments can be combined as demonstrated here:
51
+
52
+ before_save :method_1, :method_2,
53
+ :if => :method,
54
+ :unless => lambda { other_method },
55
+ :on => :create do
56
+ check_something
57
+ end
58
+
59
+ Any blocks given are evaluated within the context of the model in question,
60
+ but the model may be explicitly specified as a parameter to the block:
61
+
62
+ before_save do |model|
63
+ model.check_something
64
+ end
65
+
66
+ It is important to node that using these class-level declarations means that
67
+ the instance methods with the same name should not be defined:
68
+
69
+ before_save :do_something
70
+
71
+ def before_save
72
+ # WARNING: This will block the :do_something method from running,
73
+ # as this method over-rides that behavior. Calling super will not
74
+ # restore this functionality.
75
+
76
+ do_some_stuff
77
+
78
+ # Execute the default behavior as defined in the class if this mixed
79
+ # approach is strictly required. This is intended as a last-resort.
80
+ self.class.run_callbacks(self, :before_save)
81
+ end
82
+
83
+ == Copyright
84
+
85
+ Copyright (c) 2010 Scott Tadman, The Working Group
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "sequel_simple_callbacks"
8
+ gem.summary = %Q[Sequel Plugin to add ActiveRecord style callback declarations]
9
+ gem.description = %Q[This plugin makes it possible to declare simple before and after callbacks on the class level just like ActiveRecord]
10
+ gem.email = "github@tadman.ca"
11
+ gem.homepage = "http://github.com/tadman/sequel_simple_callbacks"
12
+ gem.authors = %w[ tadman ]
13
+
14
+ gem.add_development_dependency "sequel"
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "sequel_simple_callbacks #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,172 @@
1
+ module SimpleSequelCallbacks
2
+ SPECIAL_HOOKS = [
3
+ :before_validation,
4
+ :after_validation
5
+ ].freeze
6
+
7
+ ADDITIONAL_HOOKS = [
8
+ :before_validation_on_create,
9
+ :before_validation_on_update,
10
+ :after_validation_on_create,
11
+ :after_validation_on_update
12
+ ].freeze
13
+
14
+ STANDARD_HOOKS = (Sequel::Model::HOOKS - SPECIAL_HOOKS).freeze
15
+ INSTALLABLE_HOOKS = (Sequel::Model::HOOKS + ADDITIONAL_HOOKS).freeze
16
+
17
+ def apply(model_class)
18
+ end
19
+
20
+ def configure(model_class, *arguments, &block)
21
+ end
22
+
23
+ module ClassMethods
24
+ # Add a callback hook to the model with parameters:
25
+ # * :if => One of [ Symbol, Proc ] (optional)
26
+ # * :unless => One of [ Symbol, Proc ] (optional)
27
+ # * :on => One of [ :create, :update ] (optional)
28
+
29
+ def add_callback(chain, *args, &block)
30
+ @callbacks ||= { }
31
+ callbacks = @callbacks[chain] ||= [ ]
32
+
33
+ # Extract the options from the arguments by testing if the last
34
+ # is a Hash, otherwise default to an empty set.
35
+ options = (args[-1].is_a?(Hash)) ? args.pop : { }
36
+ option_on = options[:on]
37
+ option_if = options[:if]
38
+ option_unless = options[:unless]
39
+
40
+ callbacks << lambda do |model|
41
+ result = nil
42
+
43
+ trigger =
44
+ case (option_on)
45
+ when :create
46
+ model.new?
47
+ when :update
48
+ !model.new?
49
+ when nil
50
+ true
51
+ else
52
+ false
53
+ end
54
+
55
+ if (trigger and !option_if.nil?)
56
+ trigger =
57
+ case (option_if)
58
+ when Symbol, String
59
+ model.send(option_if)
60
+ when Proc
61
+ if (option_if.arity == 0)
62
+ model.instance_eval(option_if)
63
+ else
64
+ option_if.call(model)
65
+ end
66
+ else
67
+ option_if
68
+ end
69
+ end
70
+
71
+ if (trigger and !option_unless.nil?)
72
+ trigger =
73
+ case (option_unless)
74
+ when Symbol, String
75
+ !model.send(option_unless)
76
+ when Proc
77
+ if (option_unless.arity == 0)
78
+ !model.instance_eval(option_unless)
79
+ else
80
+ !option_unless.call(model)
81
+ end
82
+ else
83
+ !option_unless
84
+ end
85
+ end
86
+
87
+ if (trigger)
88
+ args.each do |callback|
89
+ result =
90
+ case (callback)
91
+ when Symbol, String
92
+ model.send(callback)
93
+ else
94
+ if (callback.arity == 0)
95
+ model.instance_eval(callback)
96
+ else
97
+ callback.call(model)
98
+ end
99
+ end
100
+
101
+ break if (result === false)
102
+ end
103
+ end
104
+
105
+ if (trigger and block)
106
+ if (block.arity == 0)
107
+ model.instance_eval(&block)
108
+ else
109
+ block.call(model)
110
+ end
111
+ end
112
+
113
+ result
114
+ end
115
+ end
116
+
117
+ def run_callbacks(model, hook)
118
+ return unless (@callbacks)
119
+
120
+ callbacks = @callbacks[hook]
121
+
122
+ return unless (callbacks)
123
+
124
+ result = nil
125
+
126
+ callbacks.each do |callback|
127
+ result = callback.call(model)
128
+
129
+ break if (result === false)
130
+ end
131
+
132
+ result
133
+ end
134
+
135
+ INSTALLABLE_HOOKS.each do |hook|
136
+ eval %Q[
137
+ def #{hook}(*args, &block)
138
+ add_callback(:#{hook}, *args, &block)
139
+ end
140
+ ]
141
+ end
142
+ end
143
+
144
+ module InstanceMethods
145
+ STANDARD_HOOKS.each do |hook|
146
+ define_method(hook) do
147
+ self.class.run_callbacks(self, hook)
148
+ end
149
+ end
150
+
151
+ SPECIAL_HOOKS.each do |hook|
152
+ define_method(hook) do
153
+ self.class.run_callbacks(self, hook)
154
+
155
+ if (new?)
156
+ self.class.run_callbacks(self, :"#{hook}_on_create")
157
+ else
158
+ self.class.run_callbacks(self, :"#{hook}_on_update")
159
+ end
160
+ end
161
+ end
162
+
163
+ # This method is provided as a simple method to call arbitrary callback
164
+ # chains without having to run through the specific method
165
+ def run_callbacks(hook)
166
+ self.class.run_callbacks(self, hook)
167
+ end
168
+ end
169
+
170
+ module DatasetMethods
171
+ end
172
+ end
@@ -0,0 +1,60 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{sequel_simple_callbacks}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["tadman"]
12
+ s.date = %q{2010-08-25}
13
+ s.description = %q{This plugin makes it possible to declare simple before and after callbacks on the class level just like ActiveRecord}
14
+ s.email = %q{github@tadman.ca}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/sequel_simple_callbacks.rb",
27
+ "sequel_simple_callbacks.gemspec",
28
+ "test/helper.rb",
29
+ "test/models/conditional.rb",
30
+ "test/models/example.rb",
31
+ "test/models/model_triggers.rb",
32
+ "test/test_sequel_simple_callbacks.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/tadman/sequel_simple_callbacks}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.7}
38
+ s.summary = %q{Sequel Plugin to add ActiveRecord style callback declarations}
39
+ s.test_files = [
40
+ "test/helper.rb",
41
+ "test/models/conditional.rb",
42
+ "test/models/example.rb",
43
+ "test/models/model_triggers.rb",
44
+ "test/test_sequel_simple_callbacks.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
52
+ s.add_development_dependency(%q<sequel>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<sequel>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<sequel>, [">= 0"])
58
+ end
59
+ end
60
+
data/test/helper.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require 'sequel'
8
+ require 'sqlite3'
9
+
10
+ require 'sequel_simple_callbacks'
11
+
12
+ class Test::Unit::TestCase
13
+ end
@@ -0,0 +1,62 @@
1
+ if (DB.table_exists?(:conditionals))
2
+ DB.drop_table(:conditionals)
3
+ end
4
+
5
+ DB.create_table(:conditionals) do
6
+ primary_key :id
7
+ string :name
8
+ end
9
+
10
+ class ConditionalModel < Sequel::Model(:conditionals)
11
+ include ModelTriggers
12
+ plugin SimpleSequelCallbacks
13
+
14
+ before_validation do |model|
15
+ model.trigger(:before_validation_with_model)
16
+ end
17
+
18
+ before_validation do
19
+ trigger(:before_validation_without_model)
20
+ end
21
+
22
+ after_validation :on => :create do
23
+ trigger(:after_validation_only_on_create)
24
+ end
25
+
26
+ before_save :if => nil, :unless => nil do
27
+ trigger(:before_save_with_nil)
28
+ end
29
+
30
+ before_save :if => true, :unless => false do
31
+ trigger(:before_save_with_true_false)
32
+ end
33
+
34
+ after_update :on => :never do
35
+ trigger(:after_update_never_called)
36
+ end
37
+
38
+ after_save :if => false do
39
+ trigger(:after_save_not_called)
40
+ end
41
+
42
+ after_update :returns_true, :returns_false, :returns_nil
43
+
44
+ def never
45
+ false
46
+ end
47
+
48
+ def returns_true
49
+ trigger(:returns_true)
50
+ true
51
+ end
52
+
53
+ def returns_false
54
+ trigger(:returns_false)
55
+ false
56
+ end
57
+
58
+ def returns_nil
59
+ trigger(:returns_nil)
60
+ nil
61
+ end
62
+ end
@@ -0,0 +1,26 @@
1
+ if (DB.table_exists?(:examples))
2
+ DB.drop_table(:examples)
3
+ end
4
+
5
+ DB.create_table(:examples) do
6
+ primary_key :id
7
+ string :name
8
+ end
9
+
10
+ class ExampleModel < Sequel::Model(:examples)
11
+ include ModelTriggers
12
+
13
+ plugin SimpleSequelCallbacks
14
+
15
+ SimpleSequelCallbacks::INSTALLABLE_HOOKS.each do |hook|
16
+ send(hook, :"do_#{hook}", :if => :triggers_active?)
17
+
18
+ define_method(:"do_#{hook}") do
19
+ trigger(hook)
20
+ end
21
+ end
22
+
23
+ def triggers_active?
24
+ !name or name != 'off'
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ module ModelTriggers
2
+ def clear_triggered!
3
+ @triggered = [ ]
4
+ end
5
+
6
+ def trigger(type)
7
+ @triggered ||= [ ]
8
+ @triggered << type
9
+ end
10
+
11
+ def triggered
12
+ @triggered ||= [ ]
13
+ end
14
+
15
+ def triggered?(type)
16
+ @triggered and @triggered.include?(type)
17
+ end
18
+ end
@@ -0,0 +1,83 @@
1
+ require 'helper'
2
+
3
+ DB_DIRECTORY = File.expand_path(File.join(*%w[ .. tmp ]), File.dirname(__FILE__))
4
+
5
+ unless (File.exist?(DB_DIRECTORY))
6
+ Dir.mkdir(DB_DIRECTORY)
7
+ end
8
+
9
+ DB = Sequel.sqlite(File.expand_path('test.sqlite3', DB_DIRECTORY))
10
+
11
+ require 'models/model_triggers'
12
+ require 'models/example'
13
+ require 'models/conditional'
14
+
15
+ class TestSequelSimpleCallbacks < Test::Unit::TestCase
16
+ def test_model_can_be_created
17
+ model = ExampleModel.new
18
+
19
+ assert model.triggers_active?
20
+
21
+ assert_equal [ :after_initialize ], model.triggered
22
+
23
+ model.save
24
+
25
+ assert_equal [ :after_initialize, :before_validation, :before_validation_on_create, :after_validation, :after_validation_on_create, :before_save, :before_create, :after_create, :after_save ], model.triggered
26
+
27
+ model.clear_triggered!
28
+
29
+ assert_equal [ ], model.triggered
30
+
31
+ assert model.id
32
+
33
+ model.name = 'Test'
34
+
35
+ model.save
36
+
37
+ assert_equal [ :before_validation, :before_validation_on_update, :after_validation, :after_validation_on_update, :before_save, :before_update, :after_update, :after_save ], model.triggered
38
+ end
39
+
40
+ def test_model_triggers_can_be_turned_off
41
+ model = ExampleModel.new(:name => 'off')
42
+
43
+ assert !model.triggers_active?
44
+
45
+ assert_equal [ ], model.triggered
46
+
47
+ model.save
48
+
49
+ assert_equal [ ], model.triggered
50
+
51
+ model.clear_triggered!
52
+
53
+ assert_equal [ ], model.triggered
54
+
55
+ assert model.id
56
+
57
+ model.name = 'Test'
58
+
59
+ model.save
60
+
61
+ assert_equal [ :before_validation, :before_validation_on_update, :after_validation, :after_validation_on_update, :before_save, :before_update, :after_update, :after_save ], model.triggered
62
+
63
+ model = ExampleModel.find(:id => model.id)
64
+ end
65
+
66
+ def test_model_conditional_triggers
67
+ model = ConditionalModel.new
68
+
69
+ assert_equal [ ], model.triggered
70
+
71
+ model.save
72
+
73
+ assert !model.new?
74
+
75
+ assert_equal [ :before_validation_with_model, :before_validation_without_model, :after_validation_only_on_create, :before_save_with_nil, :before_save_with_true_false ], model.triggered
76
+
77
+ model.clear_triggered!
78
+
79
+ model.save
80
+
81
+ assert_equal [ :before_validation_with_model, :before_validation_without_model, :before_save_with_nil, :before_save_with_true_false, :returns_true, :returns_false ], model.triggered
82
+ end
83
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sequel_simple_callbacks
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - tadman
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-25 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sequel
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ description: This plugin makes it possible to declare simple before and after callbacks on the class level just like ActiveRecord
34
+ email: github@tadman.ca
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - LICENSE
41
+ - README.rdoc
42
+ files:
43
+ - .document
44
+ - .gitignore
45
+ - LICENSE
46
+ - README.rdoc
47
+ - Rakefile
48
+ - VERSION
49
+ - lib/sequel_simple_callbacks.rb
50
+ - sequel_simple_callbacks.gemspec
51
+ - test/helper.rb
52
+ - test/models/conditional.rb
53
+ - test/models/example.rb
54
+ - test/models/model_triggers.rb
55
+ - test/test_sequel_simple_callbacks.rb
56
+ has_rdoc: true
57
+ homepage: http://github.com/tadman/sequel_simple_callbacks
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options:
62
+ - --charset=UTF-8
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Sequel Plugin to add ActiveRecord style callback declarations
88
+ test_files:
89
+ - test/helper.rb
90
+ - test/models/conditional.rb
91
+ - test/models/example.rb
92
+ - test/models/model_triggers.rb
93
+ - test/test_sequel_simple_callbacks.rb