ohm-contrib 0.0.5 → 0.0.6
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/VERSION +1 -1
- data/lib/ohm/contrib.rb +1 -1
- data/lib/ohm/contrib/typecast.rb +57 -9
- data/ohm-contrib.gemspec +2 -2
- data/test/test_ohm_typecast.rb +201 -10
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/lib/ohm/contrib.rb
CHANGED
data/lib/ohm/contrib/typecast.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
92
|
+
MissingValidation = Class.new(StandardError)
|
69
93
|
|
94
|
+
include Types
|
95
|
+
include TypeAssertions
|
96
|
+
|
70
97
|
def self.included(base)
|
71
|
-
base.extend
|
98
|
+
base.extend ClassMethods
|
72
99
|
end
|
73
100
|
|
74
|
-
module
|
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
|
-
|
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
|
data/ohm-contrib.gemspec
CHANGED
@@ -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.
|
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-
|
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 = [
|
data/test/test_ohm_typecast.rb
CHANGED
@@ -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
|
-
|
46
|
-
|
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
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
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
|
-
-
|
9
|
-
version: 0.0.
|
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-
|
17
|
+
date: 2010-05-18 00:00:00 +08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|