hashme 0.1.2 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/README.md +30 -4
- data/lib/hashme.rb +1 -0
- data/lib/hashme/casted_array.rb +2 -2
- data/lib/hashme/properties.rb +1 -1
- data/lib/hashme/property.rb +10 -33
- data/lib/hashme/property_casting.rb +194 -0
- data/lib/hashme/version.rb +1 -1
- data/spec/hashme/attributes_spec.rb +11 -12
- data/spec/hashme/base_spec.rb +4 -5
- data/spec/hashme/casted_array_spec.rb +20 -17
- data/spec/hashme/properties_spec.rb +21 -21
- data/spec/hashme/property_casting_spec.rb +612 -0
- data/spec/hashme/property_spec.rb +36 -38
- metadata +18 -14
data/spec/hashme/base_spec.rb
CHANGED
@@ -11,10 +11,10 @@ describe Hashme do
|
|
11
11
|
|
12
12
|
describe '.build' do
|
13
13
|
it "should create a Model and give a block to build it" do
|
14
|
-
@model.
|
14
|
+
expect(@model).to receive(:call_in_block)
|
15
15
|
@model.build do |model|
|
16
16
|
@model.call_in_block
|
17
|
-
model.
|
17
|
+
expect(model).to be_kind_of(@model)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -29,16 +29,15 @@ describe Hashme do
|
|
29
29
|
|
30
30
|
it "should accept and set attributes" do
|
31
31
|
@obj = @model.new(:name => "Sam")
|
32
|
-
@obj.name.
|
32
|
+
expect(@obj.name).to eql("Sam")
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should set default values so they are accessible by hash" do
|
36
36
|
@model.property :surname, String, :default => "Nowl"
|
37
37
|
@obj = @model.new
|
38
|
-
@obj.to_hash[:surname].
|
38
|
+
expect(@obj.to_hash[:surname]).to eql('Nowl')
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
41
|
end
|
43
42
|
|
44
43
|
end
|
@@ -14,41 +14,44 @@ describe Hashme::CastedArray do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
describe "#initialize" do
|
17
|
+
let :property do
|
18
|
+
Hashme::Property.new(:name, String)
|
19
|
+
end
|
17
20
|
before :each do
|
18
|
-
@
|
19
|
-
@obj = Hashme::CastedArray.new(owner, @prop, ['test'])
|
21
|
+
@obj = Hashme::CastedArray.new(property, owner, ['test'])
|
20
22
|
end
|
21
23
|
|
22
24
|
it "should prepare array" do
|
23
|
-
@obj.length.
|
25
|
+
expect(@obj.length).to eql(1)
|
24
26
|
end
|
25
27
|
|
26
28
|
it "should set owner and property" do
|
27
|
-
@obj.casted_by.
|
28
|
-
@obj.casted_by_property.
|
29
|
+
expect(@obj.casted_by).to eql(owner)
|
30
|
+
expect(@obj.casted_by_property).to eql(property)
|
29
31
|
end
|
30
32
|
|
31
33
|
it "should instantiate and cast each value" do
|
32
|
-
@obj.first.
|
33
|
-
@obj.first.class.
|
34
|
+
expect(@obj.first).to eql("test")
|
35
|
+
expect(@obj.first.class).to eql(String)
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
39
|
describe "adding to array" do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
subject do
|
41
|
+
Hashme::CastedArray.new(property, owner, [{:name => 'test'}])
|
42
|
+
end
|
43
|
+
let :property do
|
44
|
+
Hashme::Property.new(:item, submodel)
|
42
45
|
end
|
43
46
|
|
44
47
|
it "should cast new items" do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
subject << {:name => 'test2'}
|
49
|
+
expect(subject.last.class).to eql(submodel)
|
50
|
+
expect(subject.first.name).to eql('test')
|
51
|
+
expect(subject.last.name).to eql('test2')
|
49
52
|
|
50
|
-
|
51
|
-
|
53
|
+
expect(subject.last.casted_by).to be(subject)
|
54
|
+
expect(subject.last.casted_by_property).to eql(property)
|
52
55
|
end
|
53
56
|
|
54
57
|
end
|
@@ -23,7 +23,7 @@ describe Hashme::Properties do
|
|
23
23
|
describe "#get_attribute" do
|
24
24
|
it "should provide object in model" do
|
25
25
|
@obj[:key1] = 'value'
|
26
|
-
@obj.get_attribute(:key1).
|
26
|
+
expect(@obj.get_attribute(:key1)).to eql('value')
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -31,41 +31,41 @@ describe Hashme::Properties do
|
|
31
31
|
it "should be posible to set attribute not defined as property" do
|
32
32
|
@obj.set_attribute('key1', 'value1')
|
33
33
|
@obj.set_attribute(:key2, 'value2')
|
34
|
-
@obj[:key1].
|
35
|
-
@obj[:key2].
|
34
|
+
expect(@obj[:key1]).to eql('value1')
|
35
|
+
expect(@obj[:key2]).to eql('value2')
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should set and cast attribute with property" do
|
39
39
|
property = @model.send(:properties)[:name]
|
40
40
|
name = "Fred Flinstone"
|
41
|
-
property.
|
41
|
+
expect(property).to receive(:build).with(@obj, name).and_return(name)
|
42
42
|
@obj.set_attribute(:name, name)
|
43
|
-
@obj[:name].
|
43
|
+
expect(@obj[:name]).to eql(name)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
describe ".properties" do
|
48
48
|
|
49
49
|
it "should be instantiated after property set" do
|
50
|
-
@model.properties.
|
51
|
-
@model.properties.class.
|
50
|
+
expect(@model.properties).to_not be_nil
|
51
|
+
expect(@model.properties.class).to eql(Hash)
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should be empty if no properties" do
|
55
55
|
model = Class.new do
|
56
56
|
include Hashme
|
57
57
|
end
|
58
|
-
model.properties.
|
58
|
+
expect(model.properties).to be_empty
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should be inherited from parent models" do
|
62
62
|
mod = Class.new(@model) do
|
63
63
|
property :surname, String
|
64
64
|
end
|
65
|
-
mod.properties.keys.
|
66
|
-
mod.properties.keys.
|
65
|
+
expect(mod.properties.keys).to include(:name)
|
66
|
+
expect(mod.properties.keys).to include(:surname)
|
67
67
|
# Make sure we don't update the parent!
|
68
|
-
@model.properties.keys.
|
68
|
+
expect(@model.properties.keys).to_not include(:surname)
|
69
69
|
end
|
70
70
|
|
71
71
|
end
|
@@ -73,36 +73,36 @@ describe Hashme::Properties do
|
|
73
73
|
describe ".property" do
|
74
74
|
|
75
75
|
it "should fail if no type is defined" do
|
76
|
-
@model.properties.length.
|
76
|
+
expect(@model.properties.length).to eql(1)
|
77
77
|
expect {
|
78
78
|
@model.property :foobar
|
79
79
|
}.to raise_error(ArgumentError)
|
80
|
-
@model.properties.length.
|
80
|
+
expect(@model.properties.length).to eql(1)
|
81
81
|
end
|
82
82
|
|
83
83
|
it "should create a new property with helper methods" do
|
84
|
-
@model.properties.length.
|
84
|
+
expect(@model.properties.length).to eql(1)
|
85
85
|
@model.property :desc, String
|
86
|
-
@model.properties.length.
|
86
|
+
expect(@model.properties.length).to eql(2)
|
87
87
|
|
88
88
|
prop = @model.properties[:desc]
|
89
|
-
prop.class.
|
89
|
+
expect(prop.class).to eql(Hashme::Property)
|
90
90
|
|
91
|
-
@obj.
|
92
|
-
@obj.
|
91
|
+
expect(@obj).to respond_to(:desc)
|
92
|
+
expect(@obj).to respond_to(:desc=)
|
93
93
|
|
94
94
|
@obj.desc = "test"
|
95
|
-
@obj.desc.
|
95
|
+
expect(@obj.desc).to eql("test")
|
96
96
|
end
|
97
97
|
|
98
98
|
it "should return nil on property with no default" do
|
99
99
|
@model.property :nickname, String
|
100
|
-
@obj.nickname.
|
100
|
+
expect(@obj.nickname).to be_nil
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should create helper method with support for default values" do
|
104
104
|
@model.property :name, String, :default => "Sam"
|
105
|
-
@obj.name.
|
105
|
+
expect(@obj.name).to eql("Sam")
|
106
106
|
end
|
107
107
|
|
108
108
|
end
|
@@ -0,0 +1,612 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Course
|
4
|
+
include Hashme
|
5
|
+
|
6
|
+
property :title, String
|
7
|
+
property :participants, [Object]
|
8
|
+
property :ends_at, Time
|
9
|
+
property :estimate, Float
|
10
|
+
property :hours, Integer
|
11
|
+
property :profit, BigDecimal
|
12
|
+
property :started_on, Date
|
13
|
+
property :updated_at, DateTime
|
14
|
+
property :active, TrueClass
|
15
|
+
property :very_active, TrueClass
|
16
|
+
property :klass, Class
|
17
|
+
property :currency, String, :default => 'EUR'
|
18
|
+
property :symbol, Symbol
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Hashme::PropertyCasting do
|
22
|
+
|
23
|
+
let :property do
|
24
|
+
double(:property)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#cast" do
|
28
|
+
it "should respond" do
|
29
|
+
expect(subject).to respond_to(:cast)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
let :course do
|
34
|
+
Course.new(:title => 'Relaxation')
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "when value is nil" do
|
38
|
+
it "leaves the value unchanged" do
|
39
|
+
course.title = nil
|
40
|
+
expect(course['title']).to be_nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "when value is empty string" do
|
45
|
+
it "leaves the value unchanged" do
|
46
|
+
course.title = ""
|
47
|
+
expect(course['title']).to eql("")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "when type primitive is an Object" do
|
52
|
+
it "it should not cast given value" do
|
53
|
+
course.participants = [{}, 'q', 1]
|
54
|
+
expect(course['participants']).to eql([{}, 'q', 1])
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should cast started_on to Date" do
|
58
|
+
course.started_on = Date.today
|
59
|
+
expect(course['started_on']).to be_an_instance_of(Date)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "when type primitive is a String" do
|
64
|
+
it "keeps string value unchanged" do
|
65
|
+
value = "1.0"
|
66
|
+
course.title = value
|
67
|
+
expect(course['title']).to equal(value)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "it casts to string representation of the value" do
|
71
|
+
course.title = 1.0
|
72
|
+
expect(course['title']).to eql("1.0")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "when type primitive is a Symbol" do
|
77
|
+
it "keeps symbol value unchanged" do
|
78
|
+
value = :a_symbol
|
79
|
+
course.symbol = value
|
80
|
+
expect(course['symbol']).to be(value)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "it casts to symbol representation of the value" do
|
84
|
+
course.symbol = "a_symbol"
|
85
|
+
expect(course['symbol']).to be(:a_symbol)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "turns blank value into nil" do
|
89
|
+
course.symbol = ""
|
90
|
+
expect(course.symbol).to be_nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
describe 'when type primitive is a Float' do
|
96
|
+
it 'returns same value if a float' do
|
97
|
+
value = 24.0
|
98
|
+
course.estimate = value
|
99
|
+
expect(course['estimate']).to equal(value)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns float representation of a zero string integer' do
|
103
|
+
course.estimate = '0'
|
104
|
+
expect(course['estimate']).to eql(0.0)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns float representation of a positive string integer' do
|
108
|
+
course.estimate = '24'
|
109
|
+
expect(course['estimate']).to eql(24.0)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'returns float representation of a negative string integer' do
|
113
|
+
course.estimate = '-24'
|
114
|
+
expect(course['estimate']).to eql(-24.0)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'returns float representation of a zero string float' do
|
118
|
+
course.estimate = '0.0'
|
119
|
+
expect(course['estimate']).to eql(0.0)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns float representation of a positive string float' do
|
123
|
+
course.estimate = '24.35'
|
124
|
+
expect(course['estimate']).to eql(24.35)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'returns float representation of a negative string float' do
|
128
|
+
course.estimate = '-24.35'
|
129
|
+
expect(course['estimate']).to eql(-24.35)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'returns float representation of a zero string float, with no leading digits' do
|
133
|
+
course.estimate = '.0'
|
134
|
+
expect(course['estimate']).to eql(0.0)
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'returns float representation of a positive string float, with no leading digits' do
|
138
|
+
course.estimate = '.41'
|
139
|
+
expect(course['estimate']).to eql(0.41)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'returns float representation of a zero integer' do
|
143
|
+
course.estimate = 0
|
144
|
+
expect(course['estimate']).to eql(0.0)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'returns float representation of a positive integer' do
|
148
|
+
course.estimate = 24
|
149
|
+
expect(course['estimate']).to eql(24.0)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'returns float representation of a negative integer' do
|
153
|
+
course.estimate = -24
|
154
|
+
expect(course['estimate']).to eql(-24.0)
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'returns float representation of a zero decimal' do
|
158
|
+
course.estimate = BigDecimal('0.0')
|
159
|
+
expect(course['estimate']).to eql(0.0)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'returns float representation of a positive decimal' do
|
163
|
+
course.estimate = BigDecimal('24.35')
|
164
|
+
expect(course['estimate']).to eql(24.35)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'returns float representation of a negative decimal' do
|
168
|
+
course.estimate = BigDecimal('-24.35')
|
169
|
+
expect(course['estimate']).to eql(-24.35)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'return float of a number with commas instead of points for decimals' do
|
173
|
+
course.estimate = '23,35'
|
174
|
+
expect(course['estimate']).to eql(23.35)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should handle numbers with commas and points" do
|
178
|
+
course.estimate = '1,234.00'
|
179
|
+
expect(course.estimate).to eql(1234.00)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should handle a mis-match of commas and points and maintain the last one" do
|
183
|
+
course.estimate = "1,232.434.123,323"
|
184
|
+
expect(course.estimate).to eql(1232434123.323)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should handle numbers with whitespace" do
|
188
|
+
course.estimate = " 24.35 "
|
189
|
+
expect(course.estimate).to eql(24.35)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should handle numbers with unit strings" do
|
193
|
+
course.estimate = "23.21 points"
|
194
|
+
expect(course['estimate']).to eql(23.21)
|
195
|
+
end
|
196
|
+
|
197
|
+
[ '', 'string', ' foo ' ].each do |value|
|
198
|
+
it "should typecast string without a number to nil (#{value.inspect})" do
|
199
|
+
course.estimate = value
|
200
|
+
expect(course['estimate']).to be_nil
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
[ '00.0', '0.', '-.0' ].each do |value|
|
205
|
+
it "should typecast strings with strange numbers to zero (#{value.inspect})" do
|
206
|
+
course.estimate = value
|
207
|
+
expect(course['estimate']).to eql(0.0)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
[ Object.new, true ].each do |value|
|
212
|
+
it "should not typecast non-numeric value that won't respond to #to_f (#{value.inspect})" do
|
213
|
+
course.estimate = value
|
214
|
+
expect(course['estimate']).to equal(nil)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
describe 'when type primitive is a Integer' do
|
221
|
+
it 'returns same value if an integer' do
|
222
|
+
value = 24
|
223
|
+
course.hours = value
|
224
|
+
expect(course['hours']).to equal(value)
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'returns integer representation of a zero string integer' do
|
228
|
+
course.hours = '0'
|
229
|
+
expect(course['hours']).to eql(0)
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'returns integer representation of a positive string integer' do
|
233
|
+
course.hours = '24'
|
234
|
+
expect(course['hours']).to eql(24)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'returns integer representation of a negative string integer' do
|
238
|
+
course.hours = '-24'
|
239
|
+
expect(course['hours']).to eql(-24)
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'returns integer representation of a zero string float' do
|
243
|
+
course.hours = '0.0'
|
244
|
+
expect(course['hours']).to eql(0)
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'returns integer representation of a positive string float' do
|
248
|
+
course.hours = '24.35'
|
249
|
+
expect(course['hours']).to eql(24)
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'returns integer representation of a negative string float' do
|
253
|
+
course.hours = '-24.35'
|
254
|
+
expect(course['hours']).to eql(-24)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'returns integer representation of a zero string float, with no leading digits' do
|
258
|
+
course.hours = '.0'
|
259
|
+
expect(course['hours']).to eql(0)
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'returns integer representation of a positive string float, with no leading digits' do
|
263
|
+
course.hours = '.41'
|
264
|
+
expect(course['hours']).to eql(0)
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'returns integer representation of a zero float' do
|
268
|
+
course.hours = 0.0
|
269
|
+
expect(course['hours']).to eql(0)
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'returns integer representation of a positive float' do
|
273
|
+
course.hours = 24.35
|
274
|
+
expect(course['hours']).to eql(24)
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'returns integer representation of a negative float' do
|
278
|
+
course.hours = -24.35
|
279
|
+
expect(course['hours']).to eql(-24)
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'returns integer representation of a zero decimal' do
|
283
|
+
course.hours = '0.0'
|
284
|
+
expect(course['hours']).to eql(0)
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'returns integer representation of a positive decimal' do
|
288
|
+
course.hours = '24.35'
|
289
|
+
expect(course['hours']).to eql(24)
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'returns integer representation of a negative decimal' do
|
293
|
+
course.hours = '-24.35'
|
294
|
+
expect(course['hours']).to eql(-24)
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should handle numbers with whitespace" do
|
298
|
+
course.hours = " 24 "
|
299
|
+
expect(course['hours']).to eql(24)
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should handle numbers with string units" do
|
303
|
+
course.hours = "23 hours"
|
304
|
+
expect(course['hours']).to eql(23)
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should typecast an empty string to nil" do
|
308
|
+
course.hours = ""
|
309
|
+
expect(course['hours']).to be_nil
|
310
|
+
end
|
311
|
+
|
312
|
+
[ '', 'string', ' foo ' ].each do |value|
|
313
|
+
it "should typecast string without a number to nil (#{value.inspect})" do
|
314
|
+
course.hours = value
|
315
|
+
expect(course['hours']).to be_nil
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
[ '00.0', '0.', '-.0' ].each do |value|
|
320
|
+
it "should typecast strings with strange numbers to zero (#{value.inspect})" do
|
321
|
+
course.hours = value
|
322
|
+
expect(course['hours']).to eql(0)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
[ Object.new, true ].each do |value|
|
327
|
+
it "should not typecast non-numeric value that won't respond to #to_i (#{value.inspect})" do
|
328
|
+
course.hours = value
|
329
|
+
expect(course['hours']).to equal(nil)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
describe 'when type primitive is a BigDecimal' do
|
336
|
+
it 'returns same value if a decimal' do
|
337
|
+
value = BigDecimal('24.0')
|
338
|
+
course.profit = value
|
339
|
+
expect(course['profit']).to equal(value)
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'returns decimal representation of a zero string integer' do
|
343
|
+
course.profit = '0'
|
344
|
+
expect(course['profit']).to eql(BigDecimal('0.0'))
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'returns decimal representation of a positive string integer' do
|
348
|
+
course.profit = '24'
|
349
|
+
expect(course['profit']).to eql(BigDecimal('24.0'))
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'returns decimal representation of a negative string integer' do
|
353
|
+
course.profit = '-24'
|
354
|
+
expect(course['profit']).to eql(BigDecimal('-24.0'))
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'returns decimal representation of a zero string float' do
|
358
|
+
course.profit = '0.0'
|
359
|
+
expect(course['profit']).to eql(BigDecimal('0.0'))
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'returns decimal representation of a positive string float' do
|
363
|
+
course.profit = '24.35'
|
364
|
+
expect(course['profit']).to eql(BigDecimal('24.35'))
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'returns decimal representation of a negative string float' do
|
368
|
+
course.profit = '-24.35'
|
369
|
+
expect(course['profit']).to eql(BigDecimal('-24.35'))
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'returns decimal representation of a zero string float, with no leading digits' do
|
373
|
+
course.profit = '.0'
|
374
|
+
expect(course['profit']).to eql(BigDecimal('0.0'))
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'returns decimal representation of a positive string float, with no leading digits' do
|
378
|
+
course.profit = '.41'
|
379
|
+
expect(course['profit']).to eql(BigDecimal('0.41'))
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'returns decimal representation of a zero integer' do
|
383
|
+
course.profit = 0
|
384
|
+
expect(course['profit']).to eql(BigDecimal('0.0'))
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'returns decimal representation of a positive integer' do
|
388
|
+
course.profit = 24
|
389
|
+
expect(course['profit']).to eql(BigDecimal('24.0'))
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'returns decimal representation of a negative integer' do
|
393
|
+
course.profit = -24
|
394
|
+
expect(course['profit']).to eql(BigDecimal('-24.0'))
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'returns decimal representation of a zero float' do
|
398
|
+
course.profit = 0.0
|
399
|
+
expect(course['profit']).to eql(BigDecimal('0.0'))
|
400
|
+
end
|
401
|
+
|
402
|
+
it 'returns decimal representation of a positive float' do
|
403
|
+
course.profit = 24.35
|
404
|
+
expect(course['profit']).to eql(BigDecimal('24.35'))
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'returns decimal representation of a negative float' do
|
408
|
+
course.profit = -24.35
|
409
|
+
expect(course['profit']).to eql(BigDecimal('-24.35'))
|
410
|
+
end
|
411
|
+
|
412
|
+
it "should handle numbers with whitespace" do
|
413
|
+
course.profit = " 24.35 "
|
414
|
+
expect(course['profit']).to eql(BigDecimal('24.35'))
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should handle numbers with strings" do
|
418
|
+
course.profit = "22.23 euros"
|
419
|
+
expect(course['profit']).to eql(BigDecimal('22.23'))
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should typecast an empty string to nil" do
|
423
|
+
course.profit = ""
|
424
|
+
expect(course['profit']).to be_nil
|
425
|
+
end
|
426
|
+
|
427
|
+
[ '', 'string', ' foo ' ].each do |value|
|
428
|
+
it "should typecast string without a number to nil (#{value.inspect})" do
|
429
|
+
course.profit = value
|
430
|
+
expect(course['profit']).to be_nil
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
[ '00.0', '0.', '-.0' ].each do |value|
|
435
|
+
it "should typecast strings with strange numbers to zero (#{value.inspect})" do
|
436
|
+
course.profit = value
|
437
|
+
expect(course['profit']).to eql(0.0)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
[ Object.new, true ].each do |value|
|
442
|
+
it "should typecast non-numeric value that won't respond to to_d (#{value.inspect}) as nil" do
|
443
|
+
course.profit = value
|
444
|
+
expect(course['profit']).to equal(nil)
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
end
|
449
|
+
|
450
|
+
describe 'when type primitive is a DateTime' do
|
451
|
+
describe 'and value given as a hash with keys like :year, :month, etc' do
|
452
|
+
it 'builds a DateTime instance from hash values' do
|
453
|
+
course.updated_at = {
|
454
|
+
:year => '2006',
|
455
|
+
:month => '11',
|
456
|
+
:day => '23',
|
457
|
+
:hour => '12',
|
458
|
+
:min => '0',
|
459
|
+
:sec => '0'
|
460
|
+
}
|
461
|
+
result = course['updated_at']
|
462
|
+
|
463
|
+
expect(result).to be_kind_of(DateTime)
|
464
|
+
expect(result.year).to eql(2006)
|
465
|
+
expect(result.month).to eql(11)
|
466
|
+
expect(result.day).to eql(23)
|
467
|
+
expect(result.hour).to eql(12)
|
468
|
+
expect(result.min).to eql(0)
|
469
|
+
expect(result.sec).to eql(0)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
describe 'and value is a string' do
|
474
|
+
it 'parses the string' do
|
475
|
+
course.updated_at = 'Dec, 2006'
|
476
|
+
expect(course['updated_at'].month).to eql(12)
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
it 'does not typecast non-datetime values' do
|
481
|
+
course.updated_at = 'not-datetime'
|
482
|
+
expect(course['updated_at']).to be_nil
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe 'when type primitive is a Date' do
|
487
|
+
describe 'and value given as a hash with keys like :year, :month, etc' do
|
488
|
+
it 'builds a Date instance from hash values' do
|
489
|
+
course.started_on = {
|
490
|
+
:year => '2007',
|
491
|
+
:month => '3',
|
492
|
+
:day => '25'
|
493
|
+
}
|
494
|
+
result = course['started_on']
|
495
|
+
|
496
|
+
expect(result).to be_kind_of(Date)
|
497
|
+
expect(result.year).to eql(2007)
|
498
|
+
expect(result.month).to eql(3)
|
499
|
+
expect(result.day).to eql(25)
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
describe 'and value is a string' do
|
504
|
+
it 'parses the string' do
|
505
|
+
course.started_on = 'Dec 20th, 2006'
|
506
|
+
expect(course.started_on.month).to eql(12)
|
507
|
+
expect(course.started_on.day).to eql(20)
|
508
|
+
expect(course.started_on.year).to eql(2006)
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'does not typecast non-date values' do
|
513
|
+
course.started_on = 'not-date'
|
514
|
+
expect(course['started_on']).to be_nil
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
describe 'when type primitive is a Time' do
|
519
|
+
describe 'and value given as a hash with keys like :year, :month, etc' do
|
520
|
+
it 'builds a Time instance from hash values' do
|
521
|
+
course.ends_at = {
|
522
|
+
:year => '2006',
|
523
|
+
:month => '11',
|
524
|
+
:day => '23',
|
525
|
+
:hour => '12',
|
526
|
+
:min => '0',
|
527
|
+
:sec => '0'
|
528
|
+
}
|
529
|
+
result = course['ends_at']
|
530
|
+
|
531
|
+
expect(result).to be_kind_of(Time)
|
532
|
+
expect(result.year).to eql(2006)
|
533
|
+
expect(result.month).to eql(11)
|
534
|
+
expect(result.day).to eql(23)
|
535
|
+
expect(result.hour).to eql(12)
|
536
|
+
expect(result.min).to eql(0)
|
537
|
+
expect(result.sec).to eql(0)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
describe 'and value is a string' do
|
542
|
+
it 'parses the string' do
|
543
|
+
t = Time.new(2011, 4, 1, 18, 50, 32, "+02:00")
|
544
|
+
course.ends_at = t.strftime('%Y/%m/%d %H:%M:%S %z')
|
545
|
+
expect(course['ends_at'].year).to eql(t.year)
|
546
|
+
expect(course['ends_at'].month).to eql(t.month)
|
547
|
+
expect(course['ends_at'].day).to eql(t.day)
|
548
|
+
expect(course['ends_at'].hour).to eql(t.hour)
|
549
|
+
expect(course['ends_at'].min).to eql(t.min)
|
550
|
+
expect(course['ends_at'].sec).to eql(t.sec)
|
551
|
+
end
|
552
|
+
it 'parses the string without offset as UTC' do
|
553
|
+
t = Time.now.utc
|
554
|
+
course.ends_at = t.strftime("%Y-%m-%d %H:%M:%S")
|
555
|
+
expect(course.ends_at.utc?).to be_truthy
|
556
|
+
expect(course['ends_at'].year).to eql(t.year)
|
557
|
+
expect(course['ends_at'].month).to eql(t.month)
|
558
|
+
expect(course['ends_at'].day).to eql(t.day)
|
559
|
+
expect(course['ends_at'].hour).to eql(t.hour)
|
560
|
+
expect(course['ends_at'].min).to eql(t.min)
|
561
|
+
expect(course['ends_at'].sec).to eql(t.sec)
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
it 'does not typecast non-time values' do
|
566
|
+
course.ends_at = 'not-time'
|
567
|
+
expect(course['ends_at']).to be_nil
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
describe 'when type primitive is a Class' do
|
572
|
+
it 'returns same value if a class' do
|
573
|
+
value = Course
|
574
|
+
course.klass = value
|
575
|
+
expect(course['klass']).to equal(value)
|
576
|
+
end
|
577
|
+
|
578
|
+
it 'returns the class if found' do
|
579
|
+
course.klass = 'Course'
|
580
|
+
expect(course['klass']).to eql(Course)
|
581
|
+
end
|
582
|
+
|
583
|
+
it 'does not typecast non-class values' do
|
584
|
+
course.klass = 'NoClass'
|
585
|
+
expect(course['klass']).to be_nil
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
describe 'when type primitive is a Boolean' do
|
590
|
+
|
591
|
+
[ true, 'true', 'TRUE', '1', 1, 't', 'T' ].each do |value|
|
592
|
+
it "returns true when value is #{value.inspect}" do
|
593
|
+
course.active = value
|
594
|
+
expect(course['active']).to be_truthy
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
[ false, 'false', 'FALSE', '0', 0, 'f', 'F' ].each do |value|
|
599
|
+
it "returns false when value is #{value.inspect}" do
|
600
|
+
course.active = value
|
601
|
+
expect(course['active']).to be_falsey
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
[ 'string', 2, 1.0, BigDecimal('1.0'), DateTime.now, Time.now, Date.today, Class, Object.new, ].each do |value|
|
606
|
+
it "does not typecast value #{value.inspect}" do
|
607
|
+
course.active = value
|
608
|
+
expect(course['active']).to be_nil
|
609
|
+
end
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|