sequel_model 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,12 @@
1
- === 0.3.1
1
+ === 0.3.2 (2008-01-24)
2
+
3
+ * Added Model#update_with_params method with support for virtual attributes and auto-filtering of unrelated parameters, and changed Model.create_with_params to support virtual attributes (#128).
4
+
5
+ * Cleaned up gem spec (#132).
6
+
7
+ * Removed validations code. Now relying on validations in assistance gem.
8
+
9
+ === 0.3.1 (2008-01-21)
2
10
 
3
11
  * Changed Model.dataset to use inflector to pluralize the class name into the table name. Works in similar fashion to table names in AR or DM.
4
12
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "sequel_model"
12
- VERS = "0.3.1"
12
+ VERS = "0.3.2"
13
13
  CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
14
14
  RDOC_OPTS = [
15
15
  "--quiet",
@@ -57,15 +57,14 @@ spec = Gem::Specification.new do |s|
57
57
  s.required_ruby_version = ">= 1.8.4"
58
58
 
59
59
  case RUBY_PLATFORM
60
- when /mswin/
61
- s.platform = Gem::Platform::CURRENT
62
60
  when /java/
63
61
  s.platform = "jruby"
64
62
  else
65
63
  s.platform = Gem::Platform::RUBY
66
64
  end
67
65
 
68
- s.add_dependency("sequel_core", '>= 0.5')
66
+ s.add_dependency("assistance", '>= 0.1.2')
67
+ s.add_dependency("sequel_core", '>= 1.0')
69
68
 
70
69
  s.files = %w(COPYING README Rakefile) + Dir.glob("{doc,spec,lib}/**/*")
71
70
 
@@ -96,6 +95,9 @@ end
96
95
 
97
96
  task :tag do
98
97
  cwd = FileUtils.pwd
98
+ sh %{rm -rf doc/*}
99
+ sh %{rm -rf pkg/*}
100
+ sh %{rm -rf coverage/*}
99
101
  sh %{cd ../.. && svn copy #{cwd} tags/#{NAME}-#{VERS} && svn commit -m "#{NAME}-#{VERS} tag." tags}
100
102
  end
101
103
 
@@ -135,9 +135,22 @@ module Sequel
135
135
  end
136
136
  end
137
137
 
138
+ # Updates the instance with the supplied values with support for virtual
139
+ # attributes, ignoring any values for which no setter method is available.
140
+ def update_with_params(values)
141
+ c = columns
142
+ values.each do |k, v| m = :"#{k}="
143
+ send(m, v) if c.include?(k) || respond_to?(m)
144
+ end
145
+ save_changes
146
+ end
147
+ alias_method :update_with, :update_with_params
148
+
138
149
  class << self
139
150
  def create_with_params(params)
140
- create(params.reject {|k, v| !columns.include?(k.to_sym)})
151
+ record = new
152
+ record.update_with_params(params)
153
+ record
141
154
  end
142
155
  alias_method :create_with, :create_with_params
143
156
  end
@@ -1,248 +1,8 @@
1
- gem 'assistance', '>= 0.1.1' # because we need Array#extract_options!
1
+ gem 'assistance', '>= 0.1.2' # because we need Validations
2
2
 
3
3
  module Sequel
4
- # The Validatable module provides validation capabilities as a mixin. When
5
- # included into a class, it enhances the class with class and instance
6
- # methods for defining validations and validating class instances.
7
- #
8
- # The Validatable emulates the validation capabilities of ActiveRecord, and
9
- # provides methods for validating acceptance, confirmation, presence, format,
10
- # length and numericality of attributes.
11
- #
12
- # To use validations, you need to include the Validatable module in your
13
- # class:
14
- #
15
- # class MyClass
16
- # include Sequel::Validatable
17
- # validates_length_of :password, :minimum => 6
18
- # end
19
- module Validatable
20
- # Includes the Validatable class methods into the including class.
21
- def self.included(c)
22
- c.extend ClassMethods
23
- end
24
-
25
- # Returns the validation errors associated with the object.
26
- def errors
27
- @errors ||= Errors.new
28
- end
29
-
30
- # Validates the object.
31
- def validate
32
- errors.clear
33
- self.class.validate(self)
34
- end
35
-
36
- # Validates the object and returns true if no errors are reported.
37
- def valid?
38
- validate
39
- errors.empty?
40
- end
41
-
42
- # Validatable::Errors represents validation errors.
43
- class Errors
44
- # Initializes a new instance of validation errors.
45
- def initialize
46
- @errors = Hash.new {|h, k| h[k] = []}
47
- end
48
-
49
- # Returns true if no errors are stored.
50
- def empty?
51
- @errors.empty?
52
- end
53
-
54
- # Clears all errors.
55
- def clear
56
- @errors.clear
57
- end
58
-
59
- # Returns the errors for the given attribute.
60
- def on(att)
61
- @errors[att]
62
- end
63
- alias_method :[], :on
64
-
65
- # Adds an error for the given attribute.
66
- def add(att, msg)
67
- @errors[att] << msg
68
- end
69
-
70
- # Returns an array of fully-formatted error messages.
71
- def full_messages
72
- @errors.inject([]) do |m, kv| att, errors = *kv
73
- errors.each {|e| m << "#{att} #{e}"}
74
- m
75
- end
76
- end
77
- end
78
-
79
- # The Generator class is used to generate validation definitions using
80
- # the validates {} idiom.
81
- class Generator
82
- # Initializes a new generator.
83
- def initialize(receiver ,&block)
84
- @receiver = receiver
85
- instance_eval(&block)
86
- end
87
-
88
- # Delegates method calls to the receiver by calling receiver.validates_xxx.
89
- def method_missing(m, *args)
90
- @receiver.send(:"validates_#{m}", *args)
91
- end
92
- end
93
-
94
- # Validatable class methods.
95
- module ClassMethods
96
- # Defines validations by converting a longhand block into a series of
97
- # shorthand definitions. For example:
98
- #
99
- # class MyClass
100
- # include Sequel::Validatable
101
- # validates do
102
- # length_of :name, :minimum => 6
103
- # length_of :password, :minimum => 8
104
- # end
105
- # end
106
- #
107
- # is equivalent to:
108
- # class MyClass
109
- # include Sequel::Validatable
110
- # validates_length_of :name, :minimum => 6
111
- # validates_length_of :password, :minimum => 8
112
- # end
113
- def validates(&block)
114
- Generator.new(self, &block)
115
- end
116
-
117
- # Returns the validations hash for the class.
118
- def validations
119
- @validations ||= Hash.new {|h, k| h[k] = []}
120
- end
121
-
122
- # Returns true if validations are defined.
123
- def has_validations?
124
- !validations.empty?
125
- end
126
-
127
- # Validates the given instance.
128
- def validate(o)
129
- validations.each do |att, procs|
130
- v = o.send(att)
131
- procs.each {|p| p[o, att, v]}
132
- end
133
- end
134
-
135
- # Adds a validation for each of the given attributes using the supplied
136
- # block. The block must accept three arguments: instance, attribute and
137
- # value, e.g.:
138
- #
139
- # validates_each :name, :password do |object, attribute, value|
140
- # object.errors[attribute] << 'is not nice' unless value.nice?
141
- # end
142
- def validates_each(*atts, &block)
143
- atts.each {|a| validations[a] << block}
144
- end
145
-
146
- # Validates acceptance of an attribute.
147
- def validates_acceptance_of(*atts)
148
- opts = {
149
- :message => 'is not accepted',
150
- :allow_nil => true,
151
- :accept => '1'
152
- }.merge!(atts.extract_options!)
153
-
154
- validates_each(*atts) do |o, a, v|
155
- next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
156
- o.errors[a] << opts[:message] unless v == opts[:accept]
157
- end
158
- end
159
-
160
- # Validates confirmation of an attribute.
161
- def validates_confirmation_of(*atts)
162
- opts = {
163
- :message => 'is not confirmed',
164
- }.merge!(atts.extract_options!)
165
-
166
- validates_each(*atts) do |o, a, v|
167
- next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
168
- c = o.send(:"#{a}_confirmation")
169
- o.errors[a] << opts[:message] unless v == c
170
- end
171
- end
172
-
173
- # Validates the format of an attribute.
174
- def validates_format_of(*atts)
175
- opts = {
176
- :message => 'is invalid',
177
- }.merge!(atts.extract_options!)
178
-
179
- unless opts[:with].is_a?(Regexp)
180
- raise Sequel::Error, "A regular expression must be supplied as the :with option of the options hash"
181
- end
182
-
183
- validates_each(*atts) do |o, a, v|
184
- next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
185
- o.errors[a] << opts[:message] unless v.to_s =~ opts[:with]
186
- end
187
- end
188
-
189
- # Validates the length of an attribute.
190
- def validates_length_of(*atts)
191
- opts = {
192
- :too_long => 'is too long',
193
- :too_short => 'is too short',
194
- :wrong_length => 'is the wrong length'
195
- }.merge!(atts.extract_options!)
196
-
197
- validates_each(*atts) do |o, a, v|
198
- next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
199
- if m = opts[:maximum]
200
- o.errors[a] << (opts[:message] || opts[:too_long]) unless v && v.size <= m
201
- end
202
- if m = opts[:minimum]
203
- o.errors[a] << (opts[:message] || opts[:too_short]) unless v && v.size >= m
204
- end
205
- if i = opts[:is]
206
- o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && v.size == i
207
- end
208
- if w = opts[:within]
209
- o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && w.include?(v.size)
210
- end
211
- end
212
- end
213
-
214
- NUMBER_RE = /^\d*\.{0,1}\d+$/
215
- INTEGER_RE = /\A[+-]?\d+\Z/
216
-
217
- # Validates whether an attribute is a number.
218
- def validates_numericality_of(*atts)
219
- opts = {
220
- :message => 'is not a number',
221
- }.merge!(atts.extract_options!)
222
-
223
- re = opts[:only_integer] ? INTEGER_RE : NUMBER_RE
224
-
225
- validates_each(*atts) do |o, a, v|
226
- next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
227
- o.errors[a] << opts[:message] unless v.to_s =~ re
228
- end
229
- end
230
-
231
- # Validates the presence of an attribute.
232
- def validates_presence_of(*atts)
233
- opts = {
234
- :message => 'is not present',
235
- }.merge!(atts.extract_options!)
236
-
237
- validates_each(*atts) do |o, a, v|
238
- o.errors[a] << opts[:message] unless v && !v.blank?
239
- end
240
- end
241
- end
242
- end
243
-
244
4
  class Model
245
- include Validatable
5
+ include Validation
246
6
 
247
7
  alias_method :save!, :save
248
8
  def save(*args)
@@ -282,6 +282,43 @@ describe "Model#pk_hash" do
282
282
  end
283
283
  end
284
284
 
285
+ describe Sequel::Model, "update_with_params" do
286
+
287
+ before(:each) do
288
+ MODEL_DB.reset
289
+
290
+ @c = Class.new(Sequel::Model(:items)) do
291
+ def self.columns; [:x, :y]; end
292
+ end
293
+ @o1 = @c.new
294
+ @o2 = @c.new(:id => 5)
295
+ end
296
+
297
+ it "should filter the given params using the model columns" do
298
+ @o1.update_with_params(:x => 1, :z => 2)
299
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
300
+
301
+ MODEL_DB.reset
302
+ @o2.update_with_params(:y => 1, :abc => 2)
303
+ MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
304
+ end
305
+
306
+ it "should be aliased by create_with" do
307
+ @o1.update_with(:x => 1, :z => 2)
308
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
309
+
310
+ MODEL_DB.reset
311
+ @o2.update_with(:y => 1, :abc => 2)
312
+ MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
313
+ end
314
+
315
+ it "should support virtual attributes" do
316
+ @c.class_def(:blah=) {|v| self.x = v}
317
+ @o1.update_with(:blah => 333)
318
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (333)"
319
+ end
320
+ end
321
+
285
322
  describe Sequel::Model, "create_with_params" do
286
323
 
287
324
  before(:each) do
@@ -310,6 +347,11 @@ describe Sequel::Model, "create_with_params" do
310
347
  MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (1)"
311
348
  end
312
349
 
350
+ it "should support virtual attributes" do
351
+ @c.class_def(:blah=) {|v| self.x = v}
352
+ o = @c.create_with(:blah => 333)
353
+ MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (333)"
354
+ end
313
355
  end
314
356
 
315
357
  describe Sequel::Model, "#destroy" do
@@ -1,295 +1,5 @@
1
1
  require File.join(File.dirname(__FILE__), "spec_helper")
2
2
 
3
- describe "Sequel::Validatable::Errors" do
4
- setup do
5
- @errors = Sequel::Validatable::Errors.new
6
- class Sequel::Validatable::Errors
7
- attr_accessor :errors
8
- end
9
- end
10
-
11
- specify "should be clearable using #clear" do
12
- @errors.errors = {1 => 2, 3 => 4}
13
- @errors.clear
14
- @errors.errors.should == {}
15
- end
16
-
17
- specify "should be empty if no errors are added" do
18
- @errors.should be_empty
19
- @errors[:blah] << "blah"
20
- @errors.should_not be_empty
21
- end
22
-
23
- specify "should return errors for a specific attribute using #on or #[]" do
24
- @errors[:blah].should == []
25
- @errors.on(:blah).should == []
26
-
27
- @errors[:blah] << 'blah'
28
- @errors[:blah].should == ['blah']
29
- @errors.on(:blah).should == ['blah']
30
-
31
- @errors[:bleu].should == []
32
- @errors.on(:bleu).should == []
33
- end
34
-
35
- specify "should accept errors using #[] << or #add" do
36
- @errors[:blah] << 'blah'
37
- @errors[:blah].should == ['blah']
38
-
39
- @errors.add :blah, 'zzzz'
40
- @errors[:blah].should == ['blah', 'zzzz']
41
- end
42
-
43
- specify "should return full messages using #full_messages" do
44
- @errors.full_messages.should == []
45
-
46
- @errors[:blow] << 'blieuh'
47
- @errors[:blow] << 'blich'
48
- @errors[:blay] << 'bliu'
49
- msgs = @errors.full_messages
50
- msgs.size.should == 3
51
- msgs.should include('blow blieuh', 'blow blich', 'blay bliu')
52
- end
53
- end
54
-
55
- describe Sequel::Validatable do
56
- setup do
57
- @c = Class.new do
58
- include Sequel::Validatable
59
-
60
- def self.validates_coolness_of(attr)
61
- validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
62
- end
63
- end
64
-
65
- @d = Class.new do
66
- attr_accessor :errors
67
- def initialize; @errors = Sequel::Validatable::Errors.new; end
68
- end
69
- end
70
-
71
- specify "should respond to validates, validations, has_validations?" do
72
- @c.should respond_to(:validations)
73
- @c.should respond_to(:has_validations?)
74
- end
75
-
76
- specify "should acccept validation definitions using validates_each" do
77
- @c.validates_each(:xx, :yy) {|o, a, v| o.errors[a] << 'too low' if v < 50}
78
-
79
- @c.validations[:xx].size.should == 1
80
- @c.validations[:yy].size.should == 1
81
-
82
- o = @d.new
83
- @c.validations[:xx].first.call(o, :aa, 40)
84
- @c.validations[:yy].first.call(o, :bb, 60)
85
-
86
- o.errors.full_messages.should == ['aa too low']
87
- end
88
-
89
- specify "should return true/false for has_validations?" do
90
- @c.has_validations?.should == false
91
- @c.validates_each(:xx) {1}
92
- @c.has_validations?.should == true
93
- end
94
-
95
- specify "should provide a validates method that takes block with validation definitions" do
96
- @c.validates do
97
- coolness_of :blah
98
- end
99
- @c.validations[:blah].should_not be_empty
100
-
101
- o = @d.new
102
- @c.validations[:blah].first.call(o, :ttt, 40)
103
- o.errors.full_messages.should == ['ttt is not cool']
104
- o.errors.clear
105
- @c.validations[:blah].first.call(o, :ttt, :cool)
106
- o.errors.should be_empty
107
- end
108
- end
109
-
110
- describe "A Validatable instance" do
111
- setup do
112
- @c = Class.new do
113
- attr_accessor :score
114
-
115
- include Sequel::Validatable
116
-
117
- validates_each :score do |o, a, v|
118
- o.errors[a] << 'too low' if v < 87
119
- end
120
- end
121
-
122
- @o = @c.new
123
- end
124
-
125
- specify "should supply a #valid? method that returns true if validations pass" do
126
- @o.score = 50
127
- @o.should_not be_valid
128
- @o.score = 100
129
- @o.should be_valid
130
- end
131
-
132
- specify "should provide an errors object" do
133
- @o.score = 100
134
- @o.should be_valid
135
- @o.errors.should be_empty
136
-
137
- @o.score = 86
138
- @o.should_not be_valid
139
- @o.errors[:score].should == ['too low']
140
- @o.errors[:blah].should be_empty
141
- end
142
- end
143
-
144
- describe Sequel::Validatable::Generator do
145
- setup do
146
- $testit = nil
147
-
148
- @c = Class.new do
149
- include Sequel::Validatable
150
-
151
- def self.validates_blah
152
- $testit = 1324
153
- end
154
- end
155
- end
156
-
157
- specify "should instance_eval the block, sending everything to its receiver" do
158
- Sequel::Validatable::Generator.new(@c) do
159
- blah
160
- end
161
- $testit.should == 1324
162
- end
163
- end
164
-
165
- describe "Sequel validations" do
166
- setup do
167
- @c = Class.new do
168
- attr_accessor :value
169
- include Sequel::Validatable
170
- end
171
- @m = @c.new
172
- end
173
-
174
- specify "should validate acceptance_of" do
175
- @c.validates_acceptance_of :value
176
- @m.should be_valid
177
- @m.value = '1'
178
- @m.should be_valid
179
- end
180
-
181
- specify "should validate acceptance_of with accept" do
182
- @c.validates_acceptance_of :value, :accept => 'true'
183
- @m.value = '1'
184
- @m.should_not be_valid
185
- @m.value = 'true'
186
- @m.should be_valid
187
- end
188
-
189
- specify "should validate acceptance_of with allow_nil => false" do
190
- @c.validates_acceptance_of :value, :allow_nil => false
191
- @m.should_not be_valid
192
- end
193
-
194
- specify "should validate confirmation_of" do
195
- @c.send(:attr_accessor, :value_confirmation)
196
- @c.validates_confirmation_of :value
197
-
198
- @m.value = 'blah'
199
- @m.should_not be_valid
200
-
201
- @m.value_confirmation = 'blah'
202
- @m.should be_valid
203
- end
204
-
205
- specify "should validate format_of" do
206
- @c.validates_format_of :value, :with => /.+_.+/
207
- @m.value = 'abc_'
208
- @m.should_not be_valid
209
- @m.value = 'abc_def'
210
- @m.should be_valid
211
- end
212
-
213
- specify "should raise for validate_format_of without regexp" do
214
- proc {@c.validates_format_of :value}.should raise_error(Sequel::Error)
215
- proc {@c.validates_format_of :value, :with => :blah}.should raise_error(Sequel::Error)
216
- end
217
-
218
- specify "should validate length_of with maximum" do
219
- @c.validates_length_of :value, :maximum => 5
220
- @m.should_not be_valid
221
- @m.value = '12345'
222
- @m.should be_valid
223
- @m.value = '123456'
224
- @m.should_not be_valid
225
- end
226
-
227
- specify "should validate length_of with minimum" do
228
- @c.validates_length_of :value, :minimum => 5
229
- @m.should_not be_valid
230
- @m.value = '12345'
231
- @m.should be_valid
232
- @m.value = '1234'
233
- @m.should_not be_valid
234
- end
235
-
236
- specify "should validate length_of with within" do
237
- @c.validates_length_of :value, :within => 2..5
238
- @m.should_not be_valid
239
- @m.value = '12345'
240
- @m.should be_valid
241
- @m.value = '1'
242
- @m.should_not be_valid
243
- @m.value = '123456'
244
- @m.should_not be_valid
245
- end
246
-
247
- specify "should validate length_of with is" do
248
- @c.validates_length_of :value, :is => 3
249
- @m.should_not be_valid
250
- @m.value = '123'
251
- @m.should be_valid
252
- @m.value = '12'
253
- @m.should_not be_valid
254
- @m.value = '1234'
255
- @m.should_not be_valid
256
- end
257
-
258
- specify "should validate length_of with allow_nil" do
259
- @c.validates_length_of :value, :is => 3, :allow_nil => true
260
- @m.should be_valid
261
- end
262
-
263
- specify "should validate numericality_of" do
264
- @c.validates_numericality_of :value
265
- @m.value = 'blah'
266
- @m.should_not be_valid
267
- @m.value = '123'
268
- @m.should be_valid
269
- @m.value = '123.1231'
270
- @m.should be_valid
271
- end
272
-
273
- specify "should validate numericality_of with only_integer" do
274
- @c.validates_numericality_of :value, :only_integer => true
275
- @m.value = 'blah'
276
- @m.should_not be_valid
277
- @m.value = '123'
278
- @m.should be_valid
279
- @m.value = '123.1231'
280
- @m.should_not be_valid
281
- end
282
-
283
- specify "should validate presence_of" do
284
- @c.validates_presence_of :value
285
- @m.should_not be_valid
286
- @m.value = ''
287
- @m.should_not be_valid
288
- @m.value = 1234
289
- @m.should be_valid
290
- end
291
- end
292
-
293
3
  describe Sequel::Model, "Validations" do
294
4
 
295
5
  before(:all) do
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.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -9,9 +9,18 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-01-21 00:00:00 +02:00
12
+ date: 2008-01-24 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: assistance
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.1.2
23
+ version:
15
24
  - !ruby/object:Gem::Dependency
16
25
  name: sequel_core
17
26
  version_requirement:
@@ -19,7 +28,7 @@ dependencies:
19
28
  requirements:
20
29
  - - ">="
21
30
  - !ruby/object:Gem::Version
22
- version: "0.5"
31
+ version: "1.0"
23
32
  version:
24
33
  description: Lightweight ORM for Ruby
25
34
  email: ciconia@gmail.com