sequel_model 0.1 → 0.2
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/CHANGELOG +18 -0
- data/Rakefile +5 -5
- data/lib/sequel_model/base.rb +2 -2
- data/lib/sequel_model/hooks.rb +46 -113
- data/lib/sequel_model/plugins.rb +3 -0
- data/lib/sequel_model/record.rb +9 -14
- data/lib/sequel_model/relations.rb +0 -18
- data/lib/sequel_model/schema.rb +3 -7
- data/lib/sequel_model/validations.rb +13 -17
- data/lib/sequel_model.rb +2 -9
- data/spec/hooks_spec.rb +234 -72
- data/spec/model_spec.rb +4 -12
- data/spec/plugins_spec.rb +17 -4
- data/spec/record_spec.rb +59 -10
- data/spec/relations_spec.rb +1 -1
- data/spec/schema_spec.rb +8 -21
- data/spec/validations_spec.rb +6 -24
- metadata +5 -6
data/CHANGELOG
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
=== 0.2 (2008-01-02)
|
2
|
+
|
3
|
+
* Removed deprecated Model.recreate_table method.
|
4
|
+
|
5
|
+
* Removed deprecated :class and :on options from one_to_many macro.
|
6
|
+
|
7
|
+
* Removed deprecated :class option from one_to_one macro.
|
8
|
+
|
9
|
+
* Removed deprecated Model#pkey method.
|
10
|
+
|
11
|
+
* Changed dependency to sequel_core.
|
12
|
+
|
13
|
+
* Removed examples from sequel core.
|
14
|
+
|
15
|
+
* Additional specs. We're now at 100% coverage.
|
16
|
+
|
17
|
+
* Refactored hooks code. Hooks are now inheritable, and can be defined by supplying a block or a method name, or by overriding the hook instance method. Hook chains can now be broken by returning false (#111, #112).
|
18
|
+
|
1
19
|
=== 0.1 (2007-12-30)
|
2
20
|
|
3
21
|
* Moved model code from sequel into separate model sub-project.
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ include FileUtils
|
|
9
9
|
# Configuration
|
10
10
|
##############################################################################
|
11
11
|
NAME = "sequel_model"
|
12
|
-
VERS = "0.
|
12
|
+
VERS = "0.2"
|
13
13
|
CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
|
14
14
|
RDOC_OPTS = [
|
15
15
|
"--quiet",
|
@@ -30,7 +30,7 @@ Rake::RDocTask.new do |rdoc|
|
|
30
30
|
rdoc.options += RDOC_OPTS
|
31
31
|
rdoc.main = "README"
|
32
32
|
rdoc.title = "Sequel: Lightweight ORM for Ruby"
|
33
|
-
rdoc.rdoc_files.add ["README", "COPYING", "lib/
|
33
|
+
rdoc.rdoc_files.add ["README", "COPYING", "lib/sequel_model.rb", "lib/**/*.rb"]
|
34
34
|
end
|
35
35
|
|
36
36
|
##############################################################################
|
@@ -42,13 +42,13 @@ task :package => [:clean]
|
|
42
42
|
|
43
43
|
spec = Gem::Specification.new do |s|
|
44
44
|
s.name = NAME
|
45
|
-
s.rubyforge_project =
|
45
|
+
s.rubyforge_project = 'sequel'
|
46
46
|
s.version = VERS
|
47
47
|
s.platform = Gem::Platform::RUBY
|
48
48
|
s.has_rdoc = true
|
49
49
|
s.extra_rdoc_files = ["README", "CHANGELOG", "COPYING"]
|
50
50
|
s.rdoc_options += RDOC_OPTS +
|
51
|
-
["--exclude", "^(examples|extras)\/", "--exclude", "lib/
|
51
|
+
["--exclude", "^(examples|extras)\/", "--exclude", "lib/sequel_model.rb"]
|
52
52
|
s.summary = "Lightweight ORM for Ruby"
|
53
53
|
s.description = s.summary
|
54
54
|
s.author = "Sharon Rosner"
|
@@ -65,7 +65,7 @@ spec = Gem::Specification.new do |s|
|
|
65
65
|
s.platform = Gem::Platform::RUBY
|
66
66
|
end
|
67
67
|
|
68
|
-
s.add_dependency("
|
68
|
+
s.add_dependency("sequel_core", '>= 0.5')
|
69
69
|
s.add_dependency("validatable")
|
70
70
|
|
71
71
|
s.files = %w(COPYING README Rakefile) + Dir.glob("{doc,spec,lib}/**/*")
|
data/lib/sequel_model/base.rb
CHANGED
@@ -19,8 +19,8 @@ module Sequel
|
|
19
19
|
|
20
20
|
# Returns the dataset associated with the Model class.
|
21
21
|
def self.dataset
|
22
|
-
@dataset
|
23
|
-
|
22
|
+
(@dataset ||= super_dataset) ||
|
23
|
+
(raise Error, "No dataset associated with #{self}")
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.super_dataset # :nodoc:
|
data/lib/sequel_model/hooks.rb
CHANGED
@@ -1,122 +1,55 @@
|
|
1
1
|
module Sequel
|
2
2
|
class Model
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@hooks ||= Hash.new { |h, k| h[k] = [] }
|
29
|
-
end
|
30
|
-
|
31
|
-
# Adds block to chain of Hooks for <tt>:before_save</tt>.
|
32
|
-
# It can either be prepended (default) or appended.
|
33
|
-
#
|
34
|
-
# Returns the chain itself.
|
35
|
-
#
|
36
|
-
# Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
|
37
|
-
def self.before_save(verb = :prepend, &block)
|
38
|
-
hooks[:before_save].send VERB_TO_METHOD.fetch(verb), block if block
|
39
|
-
hooks[:before_save]
|
40
|
-
end
|
41
|
-
# Adds block to chain of Hooks for <tt>:before_create</tt>.
|
42
|
-
# It can either be prepended (default) or appended.
|
43
|
-
#
|
44
|
-
# Returns the chain itself.
|
45
|
-
#
|
46
|
-
# Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
|
47
|
-
def self.before_create(verb = :prepend, &block)
|
48
|
-
hooks[:before_create].send VERB_TO_METHOD.fetch(verb), block if block
|
49
|
-
hooks[:before_create]
|
50
|
-
end
|
51
|
-
# Adds block to chain of Hooks for <tt>:before_update</tt>.
|
52
|
-
# It can either be prepended (default) or appended.
|
53
|
-
#
|
54
|
-
# Returns the chain itself.
|
55
|
-
#
|
56
|
-
# Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
|
57
|
-
def self.before_update(verb = :prepend, &block)
|
58
|
-
hooks[:before_update].send VERB_TO_METHOD.fetch(verb), block if block
|
59
|
-
hooks[:before_update]
|
60
|
-
end
|
61
|
-
# Adds block to chain of Hooks for <tt>:before_destroy</tt>.
|
62
|
-
# It can either be prepended (default) or appended.
|
63
|
-
#
|
64
|
-
# Returns the chain itself.
|
65
|
-
#
|
66
|
-
# Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
|
67
|
-
def self.before_destroy(verb = :prepend, &block)
|
68
|
-
hooks[:before_destroy].send VERB_TO_METHOD.fetch(verb), block if block
|
69
|
-
hooks[:before_destroy]
|
70
|
-
end
|
71
|
-
|
72
|
-
# Adds block to chain of Hooks for <tt>:after_save</tt>.
|
73
|
-
# It can either be prepended or appended (default).
|
74
|
-
#
|
75
|
-
# Returns the chain itself.
|
76
|
-
#
|
77
|
-
# Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
|
78
|
-
def self.after_save(verb = :append, &block)
|
79
|
-
hooks[:after_save].send VERB_TO_METHOD.fetch(verb), block if block
|
80
|
-
hooks[:after_save]
|
81
|
-
end
|
82
|
-
# Adds block to chain of Hooks for <tt>:after_create</tt>.
|
83
|
-
# It can either be prepended or appended (default).
|
84
|
-
#
|
85
|
-
# Returns the chain itself.
|
86
|
-
#
|
87
|
-
# Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
|
88
|
-
def self.after_create(verb = :append, &block)
|
89
|
-
hooks[:after_create].send VERB_TO_METHOD.fetch(verb), block if block
|
90
|
-
hooks[:after_create]
|
3
|
+
HOOKS = [
|
4
|
+
:after_initialize,
|
5
|
+
:before_create,
|
6
|
+
:after_create,
|
7
|
+
:before_update,
|
8
|
+
:after_update,
|
9
|
+
:before_save,
|
10
|
+
:after_save,
|
11
|
+
:before_destroy,
|
12
|
+
:after_destroy
|
13
|
+
]
|
14
|
+
|
15
|
+
# Some fancy code generation here in order to define the hook class methods...
|
16
|
+
HOOK_METHOD_STR = %Q{
|
17
|
+
def self.%s(method = nil, &block)
|
18
|
+
unless block
|
19
|
+
(raise SequelError, 'No hook method specified') unless method
|
20
|
+
block = proc {send method}
|
21
|
+
end
|
22
|
+
add_hook(%s, &block)
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
def self.def_hook_method(m) #:nodoc:
|
27
|
+
instance_eval(HOOK_METHOD_STR % [m.to_s, m.inspect])
|
91
28
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
hooks[:after_update].send VERB_TO_METHOD.fetch(verb), block if block
|
100
|
-
hooks[:after_update]
|
29
|
+
|
30
|
+
HOOKS.each {|h| define_method(h) {}}
|
31
|
+
HOOKS.each {|h| def_hook_method(h)}
|
32
|
+
|
33
|
+
# Returns the hooks hash for the model class.
|
34
|
+
def self.hooks #:nodoc:
|
35
|
+
@hooks ||= Hash.new {|h, k| h[k] = []}
|
101
36
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
hooks[:after_destroy]
|
37
|
+
|
38
|
+
def self.add_hook(hook, &block) #:nodoc:
|
39
|
+
chain = hooks[hook]
|
40
|
+
chain << block
|
41
|
+
define_method(hook) do
|
42
|
+
return false if super == false
|
43
|
+
chain.each {|h| break false if instance_eval(&h) == false}
|
44
|
+
end
|
111
45
|
end
|
112
46
|
|
113
|
-
#
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
|
47
|
+
# Returns true if the model class or any of its ancestors have defined
|
48
|
+
# hooks for the given hook key. Notice that this method cannot detect
|
49
|
+
# hooks defined using overridden methods.
|
118
50
|
def self.has_hooks?(key)
|
119
|
-
hooks[key] && !hooks[key].empty?
|
51
|
+
has = hooks[key] && !hooks[key].empty?
|
52
|
+
has || ((self != Model) && superclass.has_hooks?(key))
|
120
53
|
end
|
121
54
|
end
|
122
|
-
end
|
55
|
+
end
|
data/lib/sequel_model/plugins.rb
CHANGED
@@ -19,6 +19,9 @@ module Sequel
|
|
19
19
|
metaclass.send(:include, m::ClassMethods)
|
20
20
|
end
|
21
21
|
if m.const_defined?("DatasetMethods")
|
22
|
+
unless @dataset
|
23
|
+
raise Sequel::Error, "Plugin cannot be applied because the model class has no dataset"
|
24
|
+
end
|
22
25
|
dataset.meta_def(:"#{plugin}_opts") {args.first}
|
23
26
|
dataset.metaclass.send(:include, m::DatasetMethods)
|
24
27
|
end
|
data/lib/sequel_model/record.rb
CHANGED
@@ -158,12 +158,6 @@ module Sequel
|
|
158
158
|
@primary_key ||= self.class.primary_key
|
159
159
|
end
|
160
160
|
|
161
|
-
# Returns value for primary key.
|
162
|
-
def pkey
|
163
|
-
warn "Model#pkey is deprecated. Please use Model#pk instead."
|
164
|
-
@pkey ||= @values[self.class.primary_key]
|
165
|
-
end
|
166
|
-
|
167
161
|
# Returns the primary key value identifying the model instance. Stock implementation.
|
168
162
|
def pk
|
169
163
|
@pk ||= @values[:id]
|
@@ -192,6 +186,7 @@ module Sequel
|
|
192
186
|
end
|
193
187
|
|
194
188
|
block[self] if block
|
189
|
+
after_initialize
|
195
190
|
end
|
196
191
|
|
197
192
|
# Returns true if the current instance represents a new record.
|
@@ -208,9 +203,9 @@ module Sequel
|
|
208
203
|
# Creates or updates the associated record. This method can also
|
209
204
|
# accept a list of specific columns to update.
|
210
205
|
def save(*columns)
|
211
|
-
|
206
|
+
before_save
|
212
207
|
if @new
|
213
|
-
|
208
|
+
before_create
|
214
209
|
iid = model.dataset.insert(@values)
|
215
210
|
# if we have a regular primary key and it's not set in @values,
|
216
211
|
# we assume it's the last inserted id
|
@@ -222,9 +217,9 @@ module Sequel
|
|
222
217
|
refresh
|
223
218
|
end
|
224
219
|
@new = false
|
225
|
-
|
220
|
+
after_create
|
226
221
|
else
|
227
|
-
|
222
|
+
before_update
|
228
223
|
if columns.empty?
|
229
224
|
this.update(@values)
|
230
225
|
@changed_columns = []
|
@@ -232,9 +227,9 @@ module Sequel
|
|
232
227
|
this.update(@values.reject {|k, v| !columns.include?(k)})
|
233
228
|
@changed_columns.reject! {|c| columns.include?(c)}
|
234
229
|
end
|
235
|
-
|
230
|
+
after_update
|
236
231
|
end
|
237
|
-
|
232
|
+
after_save
|
238
233
|
self
|
239
234
|
end
|
240
235
|
|
@@ -260,9 +255,9 @@ module Sequel
|
|
260
255
|
# Like delete but runs hooks before and after delete.
|
261
256
|
def destroy
|
262
257
|
db.transaction do
|
263
|
-
|
258
|
+
before_destroy
|
264
259
|
delete
|
265
|
-
|
260
|
+
after_destroy
|
266
261
|
end
|
267
262
|
end
|
268
263
|
|
@@ -28,12 +28,6 @@ module Sequel
|
|
28
28
|
# node.producer_id #=> 1234
|
29
29
|
#
|
30
30
|
def self.one_to_one(name, opts)
|
31
|
-
# deprecation
|
32
|
-
if opts[:class]
|
33
|
-
warn "The :class option has been deprecated. Please use :from instead."
|
34
|
-
opts[:from] = opts[:class]
|
35
|
-
end
|
36
|
-
|
37
31
|
from = opts[:from]
|
38
32
|
from || (raise Error, "No association source defined (use :from option)")
|
39
33
|
key = opts[:key] || (name.to_s + ID_POSTFIX).to_sym
|
@@ -80,18 +74,6 @@ module Sequel
|
|
80
74
|
# one_to_many :books, :from => Book, :key => :author_id
|
81
75
|
#
|
82
76
|
def self.one_to_many(name, opts)
|
83
|
-
# deprecation
|
84
|
-
if opts[:class]
|
85
|
-
warn "The :class option has been deprecated. Please use :from instead."
|
86
|
-
opts[:from] = opts[:class]
|
87
|
-
end
|
88
|
-
# deprecation
|
89
|
-
if opts[:on]
|
90
|
-
warn "The :on option has been deprecated. Please use :key instead."
|
91
|
-
opts[:key] = opts[:on]
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
77
|
from = opts[:from]
|
96
78
|
from || (raise Error, "No association source defined (use :from option)")
|
97
79
|
key = opts[:key] || (self.to_s + ID_POSTFIX).to_sym
|
data/lib/sequel_model/schema.rb
CHANGED
@@ -5,7 +5,9 @@ module Sequel
|
|
5
5
|
# This is only needed if you want to use the create_table or drop_table
|
6
6
|
# methods.
|
7
7
|
def self.set_schema(name = nil, &block)
|
8
|
-
|
8
|
+
if name
|
9
|
+
set_dataset(db[name])
|
10
|
+
end
|
9
11
|
@schema = Schema::Generator.new(db, &block)
|
10
12
|
if @schema.primary_key_name
|
11
13
|
set_primary_key @schema.primary_key_name
|
@@ -42,11 +44,5 @@ module Sequel
|
|
42
44
|
drop_table if table_exists?
|
43
45
|
create_table
|
44
46
|
end
|
45
|
-
|
46
|
-
# Deprecated, use create_table! instead.
|
47
|
-
def self.recreate_table
|
48
|
-
warn "Model.recreate_table is deprecated. Please use Model.create_table! instead."
|
49
|
-
create_table!
|
50
|
-
end
|
51
47
|
end
|
52
48
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'validatable'
|
2
|
+
|
1
3
|
module Sequel
|
2
4
|
class Model
|
3
5
|
# =Basic Sequel Validations
|
@@ -96,22 +98,16 @@ module Sequel
|
|
96
98
|
end
|
97
99
|
end
|
98
100
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
rescue LoadError
|
111
|
-
STDERR.puts <<-MESSAGE
|
112
|
-
Install the validatable gem in order to use Sequel Model validations
|
113
|
-
If you would like model validations to work, install the validatable gem
|
114
|
-
MESSAGE
|
101
|
+
|
102
|
+
include ::Validatable
|
103
|
+
|
104
|
+
def self.validates(&block)
|
105
|
+
Validations::Generator.new(self, &block)
|
106
|
+
end
|
107
|
+
|
108
|
+
# return true if there are validations stored, false otherwise
|
109
|
+
def self.has_validations?
|
110
|
+
validations.length > 0 ? true : false
|
115
111
|
end
|
116
112
|
end
|
117
|
-
end
|
113
|
+
end
|
data/lib/sequel_model.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
gem 'sequel', '>= 0.5'
|
2
|
-
require 'sequel'
|
3
|
-
|
4
1
|
module Sequel
|
5
2
|
# == Sequel Models
|
6
3
|
#
|
@@ -108,7 +105,7 @@ module Sequel
|
|
108
105
|
# set(:created_at => Time.now)
|
109
106
|
# end
|
110
107
|
#
|
111
|
-
# after_destroy
|
108
|
+
# after_destroy do
|
112
109
|
# author.update_post_count
|
113
110
|
# end
|
114
111
|
# end
|
@@ -287,11 +284,7 @@ module Sequel
|
|
287
284
|
|
288
285
|
# Like delete_all, but invokes before_destroy and after_destroy hooks if used.
|
289
286
|
def self.destroy_all
|
290
|
-
|
291
|
-
dataset.destroy
|
292
|
-
else
|
293
|
-
dataset.delete
|
294
|
-
end
|
287
|
+
dataset.destroy
|
295
288
|
end
|
296
289
|
|
297
290
|
def self.is_dataset_magic_method?(m)
|
data/spec/hooks_spec.rb
CHANGED
@@ -1,107 +1,269 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
2
|
|
3
|
-
describe
|
4
|
-
|
3
|
+
describe "Model hooks" do
|
5
4
|
before do
|
6
5
|
MODEL_DB.reset
|
7
|
-
Sequel::Model.hooks.clear
|
8
6
|
|
9
|
-
@hooks =
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
@hooks = [
|
8
|
+
:after_initialize,
|
9
|
+
:before_create,
|
10
|
+
:after_create,
|
11
|
+
:before_update,
|
12
|
+
:after_update,
|
13
|
+
:before_save,
|
14
|
+
:after_save,
|
15
|
+
:before_destroy,
|
16
|
+
:after_destroy
|
17
|
+
]
|
18
|
+
|
19
|
+
# @hooks.each {|h| Sequel::Model.class_def(h) {}}
|
13
20
|
end
|
14
|
-
|
15
|
-
|
16
|
-
Sequel::Model
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
|
22
|
+
specify "should be definable using def <hook name>" do
|
23
|
+
c = Class.new(Sequel::Model) do
|
24
|
+
def before_save
|
25
|
+
"hi there"
|
26
|
+
end
|
20
27
|
end
|
28
|
+
|
29
|
+
c.new.before_save.should == 'hi there'
|
21
30
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
Sequel::Model.send(hook.to_sym) { nil }
|
31
|
+
|
32
|
+
specify "should be definable using a block" do
|
33
|
+
$adds = []
|
34
|
+
c = Class.new(Sequel::Model) do
|
35
|
+
before_save {$adds << 'hi'}
|
28
36
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
37
|
+
|
38
|
+
c.new.before_save
|
39
|
+
$adds.should == ['hi']
|
32
40
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@hooks.each do |hook|
|
41
|
-
Sequel::Model.send(hook.to_sym) { test.run }
|
41
|
+
|
42
|
+
specify "should be definable using a method name" do
|
43
|
+
$adds = []
|
44
|
+
c = Class.new(Sequel::Model) do
|
45
|
+
def bye; $adds << 'bye'; end
|
46
|
+
before_save :bye
|
42
47
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
model_instance = model.new
|
48
|
-
@hooks.each { |hook| model_instance.run_hooks(hook) }
|
48
|
+
|
49
|
+
c.new.before_save
|
50
|
+
$adds.should == ['bye']
|
49
51
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
|
53
|
+
specify "should be additive" do
|
54
|
+
$adds = []
|
55
|
+
c = Class.new(Sequel::Model) do
|
56
|
+
before_save {$adds << 'hyiyie'}
|
57
|
+
before_save {$adds << 'byiyie'}
|
58
|
+
end
|
59
|
+
|
60
|
+
c.new.before_save
|
61
|
+
$adds.should == ['hyiyie', 'byiyie']
|
53
62
|
end
|
54
|
-
|
55
|
-
|
56
|
-
pending
|
63
|
+
|
64
|
+
specify "should be inheritable" do
|
65
|
+
# pending
|
66
|
+
|
67
|
+
$adds = []
|
68
|
+
a = Class.new(Sequel::Model) do
|
69
|
+
before_save {$adds << '123'}
|
70
|
+
end
|
71
|
+
|
72
|
+
b = Class.new(a) do
|
73
|
+
before_save {$adds << '456'}
|
74
|
+
before_save {$adds << '789'}
|
75
|
+
end
|
76
|
+
|
77
|
+
b.new.before_save
|
78
|
+
$adds.should == ['123', '456', '789']
|
57
79
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
80
|
+
|
81
|
+
specify "should be overridable in descendant classes" do
|
82
|
+
$adds = []
|
83
|
+
a = Class.new(Sequel::Model) do
|
84
|
+
before_save {$adds << '123'}
|
85
|
+
end
|
86
|
+
|
87
|
+
b = Class.new(a) do
|
88
|
+
def before_save; $adds << '456'; end
|
89
|
+
end
|
90
|
+
|
91
|
+
a.new.before_save
|
92
|
+
$adds.should == ['123']
|
93
|
+
$adds = []
|
94
|
+
b.new.before_save
|
95
|
+
$adds.should == ['456']
|
61
96
|
end
|
97
|
+
|
98
|
+
specify "should stop processing if a hook returns false" do
|
99
|
+
$flag = true
|
100
|
+
$adds = []
|
101
|
+
|
102
|
+
a = Class.new(Sequel::Model) do
|
103
|
+
before_save {$adds << 'blah'; $flag}
|
104
|
+
before_save {$adds << 'cruel'}
|
105
|
+
end
|
106
|
+
|
107
|
+
a.new.before_save
|
108
|
+
$adds.should == ['blah', 'cruel']
|
62
109
|
|
110
|
+
# chain should not break on nil
|
111
|
+
$adds = []
|
112
|
+
$flag = nil
|
113
|
+
a.new.before_save
|
114
|
+
$adds.should == ['blah', 'cruel']
|
115
|
+
|
116
|
+
$adds = []
|
117
|
+
$flag = false
|
118
|
+
a.new.before_save
|
119
|
+
$adds.should == ['blah']
|
120
|
+
|
121
|
+
b = Class.new(a) do
|
122
|
+
before_save {$adds << 'mau'}
|
123
|
+
end
|
124
|
+
|
125
|
+
$adds = []
|
126
|
+
b.new.before_save
|
127
|
+
$adds.should == ['blah']
|
128
|
+
end
|
63
129
|
end
|
64
130
|
|
65
|
-
describe "Model
|
131
|
+
describe "Model#after_initialize" do
|
132
|
+
specify "should be called after initialization" do
|
133
|
+
$values1 = nil
|
134
|
+
|
135
|
+
a = Class.new(Sequel::Model) do
|
136
|
+
after_initialize do
|
137
|
+
$values1 = @values.clone
|
138
|
+
raise Sequel::Error if @values[:blow]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
a.new(:x => 1, :y => 2)
|
143
|
+
$values1.should == {:x => 1, :y => 2}
|
144
|
+
|
145
|
+
proc {a.new(:blow => true)}.should raise_error(Sequel::Error)
|
146
|
+
end
|
147
|
+
end
|
66
148
|
|
67
|
-
|
149
|
+
describe "Model#before_create && Model#after_create" do
|
150
|
+
setup do
|
68
151
|
MODEL_DB.reset
|
69
152
|
|
70
153
|
@c = Class.new(Sequel::Model(:items)) do
|
71
|
-
|
72
|
-
|
73
|
-
|
154
|
+
no_primary_key
|
155
|
+
|
156
|
+
before_create {MODEL_DB << "BLAH before"}
|
157
|
+
after_create {MODEL_DB << "BLAH after"}
|
74
158
|
end
|
159
|
+
end
|
160
|
+
|
161
|
+
specify "should be called around new record creation" do
|
162
|
+
@c.create(:x => 2)
|
163
|
+
MODEL_DB.sqls.should == [
|
164
|
+
'BLAH before',
|
165
|
+
'INSERT INTO items (x) VALUES (2)',
|
166
|
+
'BLAH after'
|
167
|
+
]
|
168
|
+
end
|
169
|
+
end
|
75
170
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
171
|
+
describe "Model#before_update && Model#after_update" do
|
172
|
+
setup do
|
173
|
+
MODEL_DB.reset
|
174
|
+
|
175
|
+
@c = Class.new(Sequel::Model(:items)) do
|
176
|
+
before_update {MODEL_DB << "BLAH before"}
|
177
|
+
after_update {MODEL_DB << "BLAH after"}
|
80
178
|
end
|
81
179
|
end
|
180
|
+
|
181
|
+
specify "should be called around record update" do
|
182
|
+
m = @c.new(:id => 2233)
|
183
|
+
m.save
|
184
|
+
MODEL_DB.sqls.should == [
|
185
|
+
'BLAH before',
|
186
|
+
'UPDATE items SET id = 2233 WHERE (id = 2233)',
|
187
|
+
'BLAH after'
|
188
|
+
]
|
189
|
+
end
|
190
|
+
end
|
82
191
|
|
83
|
-
|
84
|
-
|
192
|
+
describe "Model#before_save && Model#after_save" do
|
193
|
+
setup do
|
194
|
+
MODEL_DB.reset
|
85
195
|
|
86
|
-
@c.
|
87
|
-
|
196
|
+
@c = Class.new(Sequel::Model(:items)) do
|
197
|
+
before_save {MODEL_DB << "BLAH before"}
|
198
|
+
after_save {MODEL_DB << "BLAH after"}
|
88
199
|
end
|
89
|
-
|
90
|
-
n = @c.create(:x => 1)
|
91
|
-
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
92
|
-
s.should == ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
93
200
|
end
|
201
|
+
|
202
|
+
specify "should be called around record update" do
|
203
|
+
m = @c.new(:id => 2233)
|
204
|
+
m.save
|
205
|
+
MODEL_DB.sqls.should == [
|
206
|
+
'BLAH before',
|
207
|
+
'UPDATE items SET id = 2233 WHERE (id = 2233)',
|
208
|
+
'BLAH after'
|
209
|
+
]
|
210
|
+
end
|
211
|
+
|
212
|
+
specify "should be called around record creation" do
|
213
|
+
@c.no_primary_key
|
214
|
+
@c.create(:x => 2)
|
215
|
+
MODEL_DB.sqls.should == [
|
216
|
+
'BLAH before',
|
217
|
+
'INSERT INTO items (x) VALUES (2)',
|
218
|
+
'BLAH after'
|
219
|
+
]
|
220
|
+
end
|
221
|
+
end
|
94
222
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
self.id = 2
|
99
|
-
save
|
100
|
-
end
|
223
|
+
describe "Model#before_destroy && Model#after_destroy" do
|
224
|
+
setup do
|
225
|
+
MODEL_DB.reset
|
101
226
|
|
102
|
-
|
103
|
-
|
227
|
+
@c = Class.new(Sequel::Model(:items)) do
|
228
|
+
before_destroy {MODEL_DB << "BLAH before"}
|
229
|
+
after_destroy {MODEL_DB << "BLAH after"}
|
230
|
+
|
231
|
+
def delete
|
232
|
+
MODEL_DB << "DELETE BLAH"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
specify "should be called around record update" do
|
238
|
+
m = @c.new(:id => 2233)
|
239
|
+
m.destroy
|
240
|
+
MODEL_DB.sqls.should == [
|
241
|
+
'BLAH before',
|
242
|
+
'DELETE BLAH',
|
243
|
+
'BLAH after'
|
244
|
+
]
|
104
245
|
end
|
105
|
-
|
106
246
|
end
|
107
247
|
|
248
|
+
describe "Model#has_hooks?" do
|
249
|
+
setup do
|
250
|
+
@c = Class.new(Sequel::Model)
|
251
|
+
end
|
252
|
+
|
253
|
+
specify "should return false if no hooks are defined" do
|
254
|
+
@c.has_hooks?(:before_save).should be_false
|
255
|
+
end
|
256
|
+
|
257
|
+
specify "should return true if hooks are defined" do
|
258
|
+
@c.before_save {'blah'}
|
259
|
+
@c.has_hooks?(:before_save).should be_true
|
260
|
+
end
|
261
|
+
|
262
|
+
specify "should return true if hooks are inherited" do
|
263
|
+
@d = Class.new(@c)
|
264
|
+
@d.has_hooks?(:before_save).should be_false
|
265
|
+
|
266
|
+
@c.before_save :blah
|
267
|
+
@d.has_hooks?(:before_save).should be_true
|
268
|
+
end
|
269
|
+
end
|
data/spec/model_spec.rb
CHANGED
@@ -344,23 +344,15 @@ describe Sequel::Model, ".destroy_all" do
|
|
344
344
|
end
|
345
345
|
|
346
346
|
it "should delete all records in the dataset" do
|
347
|
+
@c.dataset.meta_def(:destroy) {MODEL_DB << "DESTROY this stuff"}
|
347
348
|
@c.destroy_all
|
348
|
-
MODEL_DB.sqls.should == ["
|
349
|
+
MODEL_DB.sqls.should == ["DESTROY this stuff"]
|
349
350
|
end
|
350
351
|
|
351
|
-
it "should call dataset
|
352
|
-
@c.dataset.
|
353
|
-
@c.should_receive(:has_hooks?).with(:before_destroy).and_return(true)
|
352
|
+
it "should call dataset.destroy" do
|
353
|
+
@c.dataset.should_receive(:destroy).and_return(true)
|
354
354
|
@c.destroy_all
|
355
355
|
end
|
356
|
-
|
357
|
-
it "should call dataset delete method if no hooks are present" do
|
358
|
-
@c.dataset.stub!(:delete).and_return(true)
|
359
|
-
@c.should_receive(:has_hooks?).with(:before_destroy).and_return(false)
|
360
|
-
@c.should_receive(:has_hooks?).with(:after_destroy).and_return(false)
|
361
|
-
@c.destroy_all
|
362
|
-
end
|
363
|
-
|
364
356
|
end
|
365
357
|
|
366
358
|
describe Sequel::Model, ".join" do
|
data/spec/plugins_spec.rb
CHANGED
@@ -17,10 +17,9 @@ module Sequel::Plugins
|
|
17
17
|
def deff; timestamped_opts; end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
# end
|
20
|
+
module DatasetMethods
|
21
|
+
def ghi; timestamped_opts; end
|
22
|
+
end
|
24
23
|
end
|
25
24
|
|
26
25
|
end
|
@@ -39,6 +38,7 @@ describe Sequel::Model, "using a plugin" do
|
|
39
38
|
c = nil
|
40
39
|
proc do
|
41
40
|
c = Class.new(Sequel::Model) do
|
41
|
+
set_dataset MODEL_DB[:items]
|
42
42
|
is :timestamped, :a => 1, :b => 2
|
43
43
|
end
|
44
44
|
end.should_not raise_error(LoadError)
|
@@ -46,6 +46,7 @@ describe Sequel::Model, "using a plugin" do
|
|
46
46
|
c.should respond_to(:stamp_opts)
|
47
47
|
c.stamp_opts.should == {:a => 1, :b => 2}
|
48
48
|
|
49
|
+
# instance methods
|
49
50
|
m = c.new
|
50
51
|
m.should respond_to(:get_stamp)
|
51
52
|
m.should respond_to(:abc)
|
@@ -54,8 +55,20 @@ describe Sequel::Model, "using a plugin" do
|
|
54
55
|
m[:stamp] = t
|
55
56
|
m.get_stamp.should == t
|
56
57
|
|
58
|
+
# class methods
|
57
59
|
c.should respond_to(:deff)
|
58
60
|
c.deff.should == {:a => 1, :b => 2}
|
61
|
+
|
62
|
+
# dataset methods
|
63
|
+
c.dataset.should respond_to(:ghi)
|
64
|
+
c.dataset.ghi.should == {:a => 1, :b => 2}
|
59
65
|
end
|
60
66
|
|
67
|
+
it "should fail to apply if the plugin has DatasetMethod and the model has no datset" do
|
68
|
+
proc do
|
69
|
+
Class.new(Sequel::Model) do
|
70
|
+
is :timestamped, :a => 1, :b => 2
|
71
|
+
end
|
72
|
+
end.should raise_error(Sequel::Error)
|
73
|
+
end
|
61
74
|
end
|
data/spec/record_spec.rb
CHANGED
@@ -217,7 +217,6 @@ describe Sequel::Model, "with this" do
|
|
217
217
|
end
|
218
218
|
|
219
219
|
describe "Model#pk" do
|
220
|
-
|
221
220
|
before(:each) do
|
222
221
|
@m = Class.new(Sequel::Model)
|
223
222
|
end
|
@@ -248,11 +247,9 @@ describe "Model#pk" do
|
|
248
247
|
m = @m.new(:id => 111, :x => 2, :y => 3)
|
249
248
|
proc {m.pk}.should raise_error(Sequel::Error)
|
250
249
|
end
|
251
|
-
|
252
250
|
end
|
253
251
|
|
254
252
|
describe "Model#pk_hash" do
|
255
|
-
|
256
253
|
before(:each) do
|
257
254
|
@m = Class.new(Sequel::Model)
|
258
255
|
end
|
@@ -345,18 +342,70 @@ describe Sequel::Model, "#destroy" do
|
|
345
342
|
end
|
346
343
|
|
347
344
|
describe Sequel::Model, "#exists?" do
|
348
|
-
|
349
345
|
before(:each) do
|
350
346
|
@model = Class.new(Sequel::Model(:items))
|
351
|
-
@
|
347
|
+
@m = @model.new
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should returns true when #this.count > 0" do
|
351
|
+
@m.this.meta_def(:count) {1}
|
352
|
+
@m.exists?.should be_true
|
353
|
+
end
|
354
|
+
|
355
|
+
it "should return false when #this.count == 0" do
|
356
|
+
@m.this.meta_def(:count) {0}
|
357
|
+
@m.exists?.should be_false
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
describe Sequel::Model, "#each" do
|
362
|
+
setup do
|
363
|
+
@model = Class.new(Sequel::Model(:items))
|
364
|
+
@m = @model.new(:a => 1, :b => 2, :id => 4444)
|
365
|
+
end
|
366
|
+
|
367
|
+
specify "should iterate over the values" do
|
368
|
+
h = {}
|
369
|
+
@m.each {|k, v| h[k] = v}
|
370
|
+
h.should == {:a => 1, :b => 2, :id => 4444}
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
describe Sequel::Model, "#keys" do
|
375
|
+
setup do
|
376
|
+
@model = Class.new(Sequel::Model(:items))
|
377
|
+
@m = @model.new(:a => 1, :b => 2, :id => 4444)
|
352
378
|
end
|
379
|
+
|
380
|
+
specify "should return the value keys" do
|
381
|
+
@m.keys.size.should == 3
|
382
|
+
@m.keys.should include(:a, :b, :id)
|
383
|
+
|
384
|
+
@m = @model.new()
|
385
|
+
@m.keys.should == []
|
386
|
+
end
|
387
|
+
end
|
353
388
|
|
354
|
-
|
355
|
-
|
389
|
+
describe Sequel::Model, "#===" do
|
390
|
+
specify "should compare instances by values" do
|
391
|
+
a = Sequel::Model.new(:id => 1, :x => 3)
|
392
|
+
b = Sequel::Model.new(:id => 1, :x => 4)
|
393
|
+
c = Sequel::Model.new(:id => 1, :x => 3)
|
394
|
+
|
395
|
+
a.should_not == b
|
396
|
+
a.should == c
|
397
|
+
b.should_not == c
|
356
398
|
end
|
399
|
+
end
|
357
400
|
|
358
|
-
|
359
|
-
|
401
|
+
describe Sequel::Model, "#===" do
|
402
|
+
specify "should compare instances by pk only" do
|
403
|
+
a = Sequel::Model.new(:id => 1, :x => 3)
|
404
|
+
b = Sequel::Model.new(:id => 1, :x => 4)
|
405
|
+
c = Sequel::Model.new(:id => 2, :x => 3)
|
406
|
+
|
407
|
+
a.should === b
|
408
|
+
a.should_not === c
|
360
409
|
end
|
410
|
+
end
|
361
411
|
|
362
|
-
end
|
data/spec/relations_spec.rb
CHANGED
@@ -120,7 +120,7 @@ describe Sequel::Model, "one_to_many" do
|
|
120
120
|
a.should be_a_kind_of(Sequel::Dataset)
|
121
121
|
a.sql.should == 'SELECT * FROM attributes WHERE (node_id = 1234)'
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
it "should support plain dataset in the from option" do
|
125
125
|
@c2.one_to_many :attributes, :from => MODEL_DB[:xyz], :key => :node_id
|
126
126
|
|
data/spec/schema_spec.rb
CHANGED
@@ -19,16 +19,18 @@ describe Sequel::Model, "create_table" do
|
|
19
19
|
|
20
20
|
before(:each) do
|
21
21
|
MODEL_DB.reset
|
22
|
-
@model = Class.new(Sequel::Model
|
22
|
+
@model = Class.new(Sequel::Model) do
|
23
|
+
set_dataset MODEL_DB[:items]
|
24
|
+
set_schema do
|
25
|
+
text :name
|
26
|
+
float :price, :null => false
|
27
|
+
end
|
28
|
+
end
|
23
29
|
end
|
24
30
|
|
25
31
|
it "should get the create table SQL list from the db and execute it line by line" do
|
26
|
-
#db.create_table_sql_list(table_name, *schema.create_info).each {|s| db << s}
|
27
|
-
@model.should_receive(:table_name).and_return(:items)
|
28
|
-
@model.schema.should_receive(:create_info)
|
29
|
-
@model.db.should_receive(:create_table_sql_list)
|
30
|
-
pending("Finish specing this")
|
31
32
|
@model.create_table
|
33
|
+
MODEL_DB.sqls.should == ['CREATE TABLE items (name text, price float NOT NULL)']
|
32
34
|
end
|
33
35
|
|
34
36
|
end
|
@@ -65,18 +67,3 @@ describe Sequel::Model, "create_table!" do
|
|
65
67
|
end
|
66
68
|
|
67
69
|
end
|
68
|
-
|
69
|
-
describe Sequel::Model, "recreate_table" do
|
70
|
-
|
71
|
-
before(:each) do
|
72
|
-
MODEL_DB.reset
|
73
|
-
@model = Class.new(Sequel::Model(:items))
|
74
|
-
end
|
75
|
-
|
76
|
-
it "should raise a depreciation warning and then call create_table!" do
|
77
|
-
@model.should_receive(:warn)
|
78
|
-
@model.should_receive(:create_table!).and_return(true)
|
79
|
-
@model.recreate_table
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
data/spec/validations_spec.rb
CHANGED
@@ -109,7 +109,7 @@ describe Sequel::Model, "Validations" do
|
|
109
109
|
@person.valid?.should be_true
|
110
110
|
end
|
111
111
|
|
112
|
-
it "should allow for :with_exactly => /[a-zA-Z/, which wraps the supplied regex with ^<regex>$" do
|
112
|
+
it "should allow for :with_exactly => /[a-zA-Z]/, which wraps the supplied regex with ^<regex>$" do
|
113
113
|
pending("TODO: Add this option to Validatable#validates_format_of")
|
114
114
|
end
|
115
115
|
|
@@ -208,13 +208,7 @@ describe Sequel::Model, "Validations" do
|
|
208
208
|
Sequel::Model.should respond_to(:validates_format_of) # validatable gem
|
209
209
|
Sequel::Model.should respond_to(:validations) # Validations module
|
210
210
|
end
|
211
|
-
|
212
|
-
it "should description" do
|
213
|
-
Sequel::Model.should_receive(:require).with("validatable").and_raise(LoadError)
|
214
|
-
STDERR.should_receive(:puts)
|
215
|
-
load File.join(File.dirname(__FILE__), "../lib/sequel_model/validations.rb")
|
216
|
-
end
|
217
|
-
|
211
|
+
|
218
212
|
it "should allow 'longhand' validations direcly within the model." do
|
219
213
|
lambda {
|
220
214
|
class Person < Sequel::Model(:people)
|
@@ -275,20 +269,8 @@ describe Sequel::Model, "validates" do
|
|
275
269
|
end
|
276
270
|
end
|
277
271
|
|
278
|
-
it "should runs the validations block on the model & store as :default when only a validations block is passed in"
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
it "should store the block under the name passed in when both a name and a validations block are passed in" do
|
283
|
-
pending
|
284
|
-
end
|
285
|
-
|
286
|
-
it "should return the stored validations block corresponding to the name given, if only a name is given (no block)" do
|
287
|
-
pending
|
288
|
-
end
|
289
|
-
|
290
|
-
it "should return true or false based on if validations exist on the model if no arguments are given" do
|
291
|
-
pending
|
292
|
-
end
|
293
|
-
|
272
|
+
it "should runs the validations block on the model & store as :default when only a validations block is passed in"
|
273
|
+
it "should store the block under the name passed in when both a name and a validations block are passed in"
|
274
|
+
it "should return the stored validations block corresponding to the name given, if only a name is given (no block)"
|
275
|
+
it "should return true or false based on if validations exist on the model if no arguments are given"
|
294
276
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2008-01-02 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: sequel_core
|
17
17
|
version_requirement:
|
18
18
|
version_requirements: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
@@ -44,7 +44,6 @@ files:
|
|
44
44
|
- COPYING
|
45
45
|
- README
|
46
46
|
- Rakefile
|
47
|
-
- doc/rdoc
|
48
47
|
- spec/base_spec.rb
|
49
48
|
- spec/caching_spec.rb
|
50
49
|
- spec/hooks_spec.rb
|
@@ -85,7 +84,7 @@ rdoc_options:
|
|
85
84
|
- --exclude
|
86
85
|
- ^(examples|extras)/
|
87
86
|
- --exclude
|
88
|
-
- lib/
|
87
|
+
- lib/sequel_model.rb
|
89
88
|
require_paths:
|
90
89
|
- lib
|
91
90
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -102,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
101
|
version:
|
103
102
|
requirements: []
|
104
103
|
|
105
|
-
rubyforge_project:
|
104
|
+
rubyforge_project: sequel
|
106
105
|
rubygems_version: 1.0.1
|
107
106
|
signing_key:
|
108
107
|
specification_version: 2
|