sequel_model 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
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.1"
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/sequel.rb", "lib/**/*.rb"]
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 = NAME
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/sequel.rb"]
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("sequel", '>= 0.5')
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}/**/*")
@@ -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 || super_dataset or
23
- raise Error, "No dataset associated with #{self}"
22
+ (@dataset ||= super_dataset) ||
23
+ (raise Error, "No dataset associated with #{self}")
24
24
  end
25
25
 
26
26
  def self.super_dataset # :nodoc:
@@ -1,122 +1,55 @@
1
1
  module Sequel
2
2
  class Model
3
- # This Hash translates verbs to methodnames used in chain manipulation
4
- # methods.
5
- VERB_TO_METHOD = {:prepend => :unshift, :append => :push}
6
-
7
- # Returns @hooks which is an instance of Hash with its hook identifier
8
- # (Symbol) as key and the chain of hooks (Array) as value.
9
- #
10
- # If it is not already set it'll be with an empty set of hooks.
11
- # This behaviour will change in the future to allow inheritance.
12
- #
13
- # For the time being, you should be able to do:
14
- #
15
- # class A < Sequel::Model(:a)
16
- # before_save { 'Do something...' }
17
- # end
18
- #
19
- # class B < A
20
- # @hooks = superclass.hooks.clone
21
- # before_save # => [#<Proc:0x0000c6e8@(example.rb):123>]
22
- # end
23
- #
24
- # In this case you should remember that the clone doesn't create any new
25
- # instances of your chains, so if you change the chain here it changes in
26
- # its superclass, too.
27
- def self.hooks
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
- # Adds block to chain of Hooks for <tt>:after_update</tt>.
93
- # It can either be prepended or appended (default).
94
- #
95
- # Returns the chain itself.
96
- #
97
- # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
98
- def self.after_update(verb = :append, &block)
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
- # Adds block to chain of Hooks for <tt>:after_destroy</tt>.
103
- # It can either be prepended or appended (default).
104
- #
105
- # Returns the chain itself.
106
- #
107
- # Valid verbs are <tt>:prepend</tt> and <tt>:append</tt>.
108
- def self.after_destroy(verb = :append, &block)
109
- hooks[:after_destroy].send VERB_TO_METHOD.fetch(verb), block if block
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
- # Evaluates specified chain of Hooks through <tt>instance_eval</tt>.
114
- def run_hooks(key)
115
- model.hooks[key].each {|h| instance_eval(&h)}
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
@@ -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
@@ -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
- run_hooks(:before_save)
206
+ before_save
212
207
  if @new
213
- run_hooks(:before_create)
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
- run_hooks(:after_create)
220
+ after_create
226
221
  else
227
- run_hooks(:before_update)
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
- run_hooks(:after_update)
230
+ after_update
236
231
  end
237
- run_hooks(:after_save)
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
- run_hooks(:before_destroy)
258
+ before_destroy
264
259
  delete
265
- run_hooks(:after_destroy)
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
@@ -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
- name ? set_dataset(db[name]) : name = table_name
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
- begin
101
- require "validatable"
102
- include ::Validatable
103
- def self.validates(&block)
104
- Validations::Generator.new(self, &block)
105
- end
106
- # return true if there are validations stored, false otherwise
107
- def self.has_validations?
108
- validations.length > 0 ? true : false
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
- if has_hooks?(:before_destroy) || has_hooks?(:after_destroy)
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 Sequel::Model, "hooks" do
4
-
3
+ describe "Model hooks" do
5
4
  before do
6
5
  MODEL_DB.reset
7
- Sequel::Model.hooks.clear
8
6
 
9
- @hooks = %w[
10
- before_save before_create before_update before_destroy
11
- after_save after_create after_update after_destroy
12
- ].select { |hook| !hook.empty? }
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
- it "should have hooks for everything" do
16
- Sequel::Model.methods.should include('hooks')
17
- Sequel::Model.methods.should include(*@hooks)
18
- @hooks.each do |hook|
19
- Sequel::Model.hooks[hook.to_sym].should be_an_instance_of(Array)
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
- it "should be inherited" do
24
- pending 'soon'
25
-
26
- @hooks.each do |hook|
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
- model = Class.new Sequel::Model(:models)
31
- model.hooks.should == Sequel::Model.hooks
37
+
38
+ c.new.before_save
39
+ $adds.should == ['hi']
32
40
  end
33
-
34
- it "should run hooks" do
35
- pending 'soon'
36
-
37
- test = mock 'Test'
38
- test.should_receive(:run).exactly(@hooks.length)
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
- model = Class.new Sequel::Model(:models)
45
- model.hooks.should == Sequel::Model.hooks
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
- it "should run hooks around save and create" do
52
- pending 'test execution'
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
- it "should run hooks around save and update" do
56
- pending 'test execution'
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
- it "should run hooks around delete" do
60
- pending 'test execution'
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.after_create" do
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
- before(:each) do
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
- def columns
72
- [:id, :x, :y]
73
- end
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
- ds = @c.dataset
77
- def ds.insert(*args)
78
- super(*args)
79
- 1
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
- it "should be called after creation" do
84
- s = []
192
+ describe "Model#before_save && Model#after_save" do
193
+ setup do
194
+ MODEL_DB.reset
85
195
 
86
- @c.after_create do
87
- s = MODEL_DB.sqls.dup
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
- it "should allow calling save in the hook" do
96
- @c.after_create do
97
- values.delete(:x)
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
- n = @c.create(:id => 1)
103
- MODEL_DB.sqls.should == ["INSERT INTO items (id) VALUES (1)", "SELECT * FROM items WHERE (id = 1) LIMIT 1", "UPDATE items SET id = 2 WHERE (id = 1)"]
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 == ["DELETE FROM items"]
349
+ MODEL_DB.sqls.should == ["DESTROY this stuff"]
349
350
  end
350
351
 
351
- it "should call dataset destroy method if *_destroy hooks exist" do
352
- @c.dataset.stub!(:destroy).and_return(true)
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
- # module DatasetMethods
22
- # def ghi; timestamped_opts; end
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
- @model_a = @model.new
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
- it "should returns true when current instance exists" do
355
- @model_a.exists?.should be_true
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
- it "should return false when the current instance does not exist" do
359
- pending("how would this be false?")
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
@@ -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(:items))
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
@@ -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" do
279
- pending
280
- end
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.1"
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: 2007-12-30 00:00:00 +02:00
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: sequel
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/sequel.rb
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: sequel_model
104
+ rubyforge_project: sequel
106
105
  rubygems_version: 1.0.1
107
106
  signing_key:
108
107
  specification_version: 2