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 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