ohm-contrib 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
@@ -1,6 +1,6 @@
1
1
  module Ohm
2
2
  module Contrib
3
- VERSION = '0.0.5'
3
+ VERSION = '0.0.6'
4
4
  end
5
5
 
6
6
  autoload :Boundaries, "ohm/contrib/boundaries"
@@ -6,7 +6,7 @@ module Ohm
6
6
  module Types
7
7
  class String < ::String
8
8
  def self.[](value)
9
- value
9
+ new(value)
10
10
  end
11
11
  end
12
12
 
@@ -29,14 +29,14 @@ module Ohm
29
29
  end
30
30
  end
31
31
 
32
- class Decimal
32
+ class Decimal < BigDecimal
33
33
  CANONICAL = /^(\d+)?(\.\d+)?(E[+\-]\d+)?$/
34
34
 
35
35
  def self.[](value)
36
36
  return value if value.to_s.empty?
37
37
 
38
38
  if value.to_s =~ CANONICAL
39
- BigDecimal(value)
39
+ new(value)
40
40
  else
41
41
  value
42
42
  end
@@ -63,26 +63,74 @@ module Ohm
63
63
  end
64
64
  end
65
65
  end
66
+
67
+ module TypeAssertions
68
+
69
+ protected
70
+ def assert_type_decimal(att, error = [att, :not_decimal])
71
+ assert send(att).is_a?(Ohm::Types::Decimal), error
72
+ end
73
+
74
+ def assert_type_time(att, error = [att, :not_time])
75
+ assert send(att).is_a?(Ohm::Types::Time), error
76
+ end
77
+
78
+ def assert_type_date(att, error = [att, :not_date])
79
+ assert send(att).is_a?(Ohm::Types::Date), error
80
+ end
81
+
82
+ def assert_type_integer(att, error = [att, :not_integer])
83
+ assert send(att).is_a?(Ohm::Types::Integer), error
84
+ end
85
+
86
+ def assert_type_float(att, error = [att, :not_float])
87
+ assert send(att).is_a?(Ohm::Types::Float), error
88
+ end
89
+ end
66
90
 
67
91
  module Typecast
68
- include Types
92
+ MissingValidation = Class.new(StandardError)
69
93
 
94
+ include Types
95
+ include TypeAssertions
96
+
70
97
  def self.included(base)
71
- base.extend Macros
98
+ base.extend ClassMethods
72
99
  end
73
100
 
74
- module Macros
75
- def attribute(name, type = String)
101
+ module ClassMethods
102
+ def attribute(name, type = Ohm::Types::String)
76
103
  define_method(name) do
77
104
  type[read_local(name)]
78
105
  end
79
106
 
80
107
  define_method(:"#{name}=") do |value|
81
- write_local(name, value && value.to_s)
108
+ if type.respond_to?(:dump)
109
+ write_local(name, type.dump(value))
110
+ else
111
+ write_local(name, value && value.to_s)
112
+ end
82
113
  end
83
114
 
84
115
  attributes << name unless attributes.include?(name)
116
+ types[name] = type unless types.has_key?(name)
117
+ end
118
+
119
+ def types
120
+ @types ||= {}
121
+ end
122
+ end
123
+
124
+ def valid?
125
+ return unless super
126
+
127
+ self.class.types.each do |field, type|
128
+ value = send(field)
129
+
130
+ unless value.kind_of?(type)
131
+ raise MissingValidation, "#{field} expected to be #{type}, but was #{value.class}"
132
+ end
85
133
  end
86
134
  end
87
135
  end
88
- end
136
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ohm-contrib}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Cyril David"]
12
- s.date = %q{2010-05-15}
12
+ s.date = %q{2010-05-18}
13
13
  s.description = %q{Highly decoupled drop-in functionality for Ohm models}
14
14
  s.email = %q{cyx.ucron@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -16,6 +16,42 @@ class TestOhmTypecast < Test::Unit::TestCase
16
16
 
17
17
  assert_equal 0.1, sum
18
18
  end
19
+
20
+ context "given a non-decimal value FooBar" do
21
+ should "preseve the value FooBar" do
22
+ product = Product.new(:price => "FooBar")
23
+ assert_equal "FooBar", product.price
24
+ end
25
+
26
+ should "raise a MissingValidation error during validation" do
27
+ product = Product.new(:price => "FooBar")
28
+
29
+ assert_raise Ohm::Typecast::MissingValidation do
30
+ product.valid?
31
+ end
32
+ end
33
+ end
34
+
35
+ context "given a non-decimal value FooBar but with assert_type_decimal" do
36
+ class Post < Ohm::Model
37
+ include Ohm::Typecast
38
+
39
+ attribute :price, Decimal
40
+
41
+ def validate
42
+ super
43
+
44
+ assert_type_decimal :price
45
+ end
46
+ end
47
+
48
+ should "be invalid and have an error on the field" do
49
+ post = Post.new(:price => "FooBar")
50
+
51
+ assert ! post.valid?
52
+ assert_equal [[:price, :not_decimal]], post.errors
53
+ end
54
+ end
19
55
  end
20
56
 
21
57
  context "time typecasting" do
@@ -30,7 +66,7 @@ class TestOhmTypecast < Test::Unit::TestCase
30
66
  product = Product.create(:start_of_sale => @time)
31
67
  product = Product[product.id]
32
68
 
33
- assert_equal @time, product.start_of_sale
69
+ assert_equal @time.to_s, product.start_of_sale.to_s
34
70
  end
35
71
 
36
72
  test "the retrieved value is a Time object" do
@@ -42,10 +78,9 @@ class TestOhmTypecast < Test::Unit::TestCase
42
78
  end
43
79
 
44
80
  test "an invalid string" do
45
- product = Product.create(:start_of_sale => "invalid time")
46
- product = Product[product.id]
47
-
48
- assert_equal "invalid time", product.start_of_sale
81
+ assert_raise Ohm::Typecast::MissingValidation do
82
+ product = Product.create(:start_of_sale => "invalid time")
83
+ end
49
84
  end
50
85
 
51
86
  test "when nil" do
@@ -59,6 +94,26 @@ class TestOhmTypecast < Test::Unit::TestCase
59
94
  end
60
95
  end
61
96
 
97
+ context "time typecasting with assert_type_time" do
98
+ class Post < Ohm::Model
99
+ include Ohm::Typecast
100
+
101
+ attribute :start_of_sale, Time
102
+
103
+ def validate
104
+ super
105
+
106
+ assert_type_time :start_of_sale
107
+ end
108
+ end
109
+
110
+ should "be valid given invalid time value" do
111
+ post = Post.new(:start_of_sale => "FooBar")
112
+ assert ! post.valid?
113
+ assert_equal [[:start_of_sale, :not_time]], post.errors
114
+ end
115
+ end
116
+
62
117
  context "date typecasting" do
63
118
  class Product < Ohm::Model
64
119
  include Ohm::Typecast
@@ -82,10 +137,10 @@ class TestOhmTypecast < Test::Unit::TestCase
82
137
  assert_kind_of Date, product.date_bought
83
138
  end
84
139
 
85
- test "assigning a string which is not a valid date before persisting" do
86
- product = Product.create(:date_bought => "Bla Bla")
87
-
88
- assert_equal "Bla Bla", product.date_bought
140
+ test "assigning a string which is not a valid date" do
141
+ assert_raise Ohm::Typecast::MissingValidation do
142
+ product = Product.create(:date_bought => "Bla Bla")
143
+ end
89
144
  end
90
145
 
91
146
  test "when nil" do
@@ -97,6 +152,25 @@ class TestOhmTypecast < Test::Unit::TestCase
97
152
  end
98
153
  end
99
154
 
155
+ context "date typecasting with assert_type_date" do
156
+ class Post < Ohm::Model
157
+ include Ohm::Typecast
158
+
159
+ attribute :created, Date
160
+
161
+ def validate
162
+ assert_type_date :created
163
+ end
164
+ end
165
+
166
+ should "have an invalid created field on save" do
167
+ post = Post.new(:created => "FooBar")
168
+ assert ! post.valid?
169
+ assert_equal [[:created, :not_date]], post.errors
170
+ assert_equal "FooBar", post.created
171
+ end
172
+ end
173
+
100
174
  context "integer typecasting" do
101
175
  class Product < Ohm::Model
102
176
  include Ohm::Typecast
@@ -125,6 +199,25 @@ class TestOhmTypecast < Test::Unit::TestCase
125
199
  end
126
200
  end
127
201
 
202
+ context "integer typecasting with assert_type_integer validation" do
203
+ class Post < Ohm::Model
204
+ include Ohm::Typecast
205
+
206
+ attribute :counter, Integer
207
+
208
+ def validate
209
+ assert_type_integer :counter
210
+ end
211
+ end
212
+
213
+ should "have an error on counter given a non-integer value" do
214
+ post = Post.new(:counter => "FooBar")
215
+ assert ! post.valid?
216
+ assert_equal [[:counter, :not_integer]], post.errors
217
+ assert_equal "FooBar", post.counter
218
+ end
219
+ end
220
+
128
221
  context "float typecasting" do
129
222
  class Product < Ohm::Model
130
223
  include Ohm::Typecast
@@ -157,6 +250,26 @@ class TestOhmTypecast < Test::Unit::TestCase
157
250
  end
158
251
  end
159
252
 
253
+ context "float typecasting with assert_type_float validation" do
254
+ class Post < Ohm::Model
255
+ include Ohm::Typecast
256
+
257
+ attribute :quotient, Float
258
+
259
+ def validate
260
+ assert_type_float :quotient
261
+ end
262
+ end
263
+
264
+ should "have an error on quotient given a non-float value" do
265
+ post = Post.new(:quotient => "FooBar")
266
+ assert ! post.valid?
267
+ assert_equal [[:quotient, :not_float]], post.errors
268
+ assert_equal "FooBar", post.quotient
269
+ end
270
+ end
271
+
272
+
160
273
  context "trying to validate numericality of a decimal" do
161
274
  class Item < Ohm::Model
162
275
  include Ohm::Typecast
@@ -177,4 +290,82 @@ class TestOhmTypecast < Test::Unit::TestCase
177
290
  assert_equal [[:price, :not_numeric]], @item.errors
178
291
  end
179
292
  end
180
- end
293
+
294
+ context "specifying a custom DataType without a #dump method" do
295
+ class ::FooBar < Struct.new(:value)
296
+ def self.[](str)
297
+ new(str)
298
+ end
299
+ end
300
+
301
+ class Item < Ohm::Model
302
+ include Ohm::Typecast
303
+
304
+ attribute :foo, FooBar
305
+ end
306
+
307
+ should "use it as expected" do
308
+ item = Item.new(:foo => "bar")
309
+ assert_equal FooBar.new("bar"), item.foo
310
+ end
311
+ end
312
+
313
+ context "specifying a customer DataType but with a #dump method" do
314
+ class ::CSV < Array
315
+ def self.dump(arr)
316
+ arr.join(',')
317
+ end
318
+
319
+ def self.[](str)
320
+ new(str.split(','))
321
+ end
322
+
323
+ def to_s
324
+ join(',')
325
+ end
326
+ end
327
+
328
+ class Item < Ohm::Model
329
+ include Ohm::Typecast
330
+
331
+ attribute :csv, CSV
332
+ end
333
+
334
+
335
+ should "dump the appropriate value" do
336
+ item = Item.new(:csv => [ 'first', 'second', 'third'])
337
+
338
+ assert_equal 'first,second,third', item.send(:read_local, :csv)
339
+ end
340
+
341
+ should "be able to retrieve it back properly" do
342
+ item = Item.create(:csv => [ 'first', 'second', 'third'])
343
+ item = Item[item.id]
344
+
345
+ assert_equal ['first', 'second', 'third'], item.csv
346
+ end
347
+
348
+ should "also be able to read/write with raw CSV" do
349
+ item = Item.create(:csv => CSV.new(['first', 'second', 'third']))
350
+ item = Item[item.id]
351
+
352
+ assert_equal ['first', 'second', 'third'], item.csv
353
+ end
354
+ end
355
+
356
+ context "defaut Strings" do
357
+ class Post < Ohm::Model
358
+ include Ohm::Typecast
359
+
360
+ attribute :field1
361
+ attribute :field2
362
+ attribute :field3
363
+ end
364
+
365
+ should "not throw a validation missing exception during save" do
366
+ assert_nothing_raised Ohm::Typecast::MissingValidation do
367
+ Post.create :field1 => "field1", :field2 => "field2", :field3 => "fld3"
368
+ end
369
+ end
370
+ end
371
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 5
9
- version: 0.0.5
8
+ - 6
9
+ version: 0.0.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - Cyril David
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-15 00:00:00 +08:00
17
+ date: 2010-05-18 00:00:00 +08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency