ardm 0.0.1

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.
Files changed (179) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +35 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +21 -0
  5. data/README.md +70 -0
  6. data/Rakefile +4 -0
  7. data/ardm.gemspec +29 -0
  8. data/db/.gitignore +1 -0
  9. data/lib/ardm/active_record/associations.rb +80 -0
  10. data/lib/ardm/active_record/base.rb +49 -0
  11. data/lib/ardm/active_record/dirty.rb +25 -0
  12. data/lib/ardm/active_record/hooks.rb +31 -0
  13. data/lib/ardm/active_record/inheritance.rb +37 -0
  14. data/lib/ardm/active_record/is/state_machine.rb +21 -0
  15. data/lib/ardm/active_record/is.rb +22 -0
  16. data/lib/ardm/active_record/not_found.rb +7 -0
  17. data/lib/ardm/active_record/predicate_builder/array_handler.rb +31 -0
  18. data/lib/ardm/active_record/predicate_builder/rails3.rb +147 -0
  19. data/lib/ardm/active_record/predicate_builder/rails4.rb +139 -0
  20. data/lib/ardm/active_record/predicate_builder/relation_handler.rb +15 -0
  21. data/lib/ardm/active_record/predicate_builder.rb +19 -0
  22. data/lib/ardm/active_record/property.rb +357 -0
  23. data/lib/ardm/active_record/query.rb +108 -0
  24. data/lib/ardm/active_record/record.rb +70 -0
  25. data/lib/ardm/active_record/relation.rb +83 -0
  26. data/lib/ardm/active_record/repository.rb +38 -0
  27. data/lib/ardm/active_record/serialization.rb +164 -0
  28. data/lib/ardm/active_record/storage_names.rb +28 -0
  29. data/lib/ardm/active_record/validations.rb +111 -0
  30. data/lib/ardm/active_record.rb +43 -0
  31. data/lib/ardm/data_mapper/not_found.rb +5 -0
  32. data/lib/ardm/data_mapper/record.rb +41 -0
  33. data/lib/ardm/data_mapper.rb +5 -0
  34. data/lib/ardm/env.rb +5 -0
  35. data/lib/ardm/property/api_key.rb +30 -0
  36. data/lib/ardm/property/bcrypt_hash.rb +31 -0
  37. data/lib/ardm/property/binary.rb +23 -0
  38. data/lib/ardm/property/boolean.rb +29 -0
  39. data/lib/ardm/property/class.rb +19 -0
  40. data/lib/ardm/property/comma_separated_list.rb +28 -0
  41. data/lib/ardm/property/csv.rb +35 -0
  42. data/lib/ardm/property/date.rb +12 -0
  43. data/lib/ardm/property/datetime.rb +12 -0
  44. data/lib/ardm/property/decimal.rb +38 -0
  45. data/lib/ardm/property/discriminator.rb +65 -0
  46. data/lib/ardm/property/enum.rb +51 -0
  47. data/lib/ardm/property/epoch_time.rb +38 -0
  48. data/lib/ardm/property/file_path.rb +25 -0
  49. data/lib/ardm/property/flag.rb +65 -0
  50. data/lib/ardm/property/float.rb +18 -0
  51. data/lib/ardm/property/integer.rb +24 -0
  52. data/lib/ardm/property/invalid_value_error.rb +22 -0
  53. data/lib/ardm/property/ip_address.rb +35 -0
  54. data/lib/ardm/property/json.rb +49 -0
  55. data/lib/ardm/property/lookup.rb +29 -0
  56. data/lib/ardm/property/numeric.rb +40 -0
  57. data/lib/ardm/property/object.rb +36 -0
  58. data/lib/ardm/property/paranoid_boolean.rb +18 -0
  59. data/lib/ardm/property/paranoid_datetime.rb +17 -0
  60. data/lib/ardm/property/regexp.rb +22 -0
  61. data/lib/ardm/property/serial.rb +16 -0
  62. data/lib/ardm/property/slug.rb +29 -0
  63. data/lib/ardm/property/string.rb +40 -0
  64. data/lib/ardm/property/support/dirty_minder.rb +169 -0
  65. data/lib/ardm/property/support/flags.rb +41 -0
  66. data/lib/ardm/property/support/paranoid_base.rb +78 -0
  67. data/lib/ardm/property/text.rb +11 -0
  68. data/lib/ardm/property/time.rb +12 -0
  69. data/lib/ardm/property/uri.rb +27 -0
  70. data/lib/ardm/property/uuid.rb +65 -0
  71. data/lib/ardm/property/validation.rb +208 -0
  72. data/lib/ardm/property/yaml.rb +38 -0
  73. data/lib/ardm/property.rb +891 -0
  74. data/lib/ardm/property_set.rb +152 -0
  75. data/lib/ardm/query/expression.rb +85 -0
  76. data/lib/ardm/query/ext/symbol.rb +37 -0
  77. data/lib/ardm/query/operator.rb +64 -0
  78. data/lib/ardm/record.rb +1 -0
  79. data/lib/ardm/support/assertions.rb +8 -0
  80. data/lib/ardm/support/deprecate.rb +12 -0
  81. data/lib/ardm/support/descendant_set.rb +89 -0
  82. data/lib/ardm/support/equalizer.rb +48 -0
  83. data/lib/ardm/support/ext/array.rb +22 -0
  84. data/lib/ardm/support/ext/blank.rb +25 -0
  85. data/lib/ardm/support/ext/hash.rb +67 -0
  86. data/lib/ardm/support/ext/module.rb +47 -0
  87. data/lib/ardm/support/ext/object.rb +57 -0
  88. data/lib/ardm/support/ext/string.rb +24 -0
  89. data/lib/ardm/support/ext/try_dup.rb +12 -0
  90. data/lib/ardm/support/hook.rb +405 -0
  91. data/lib/ardm/support/lazy_array.rb +451 -0
  92. data/lib/ardm/support/local_object_space.rb +13 -0
  93. data/lib/ardm/support/logger.rb +201 -0
  94. data/lib/ardm/support/mash.rb +176 -0
  95. data/lib/ardm/support/naming_conventions.rb +90 -0
  96. data/lib/ardm/support/ordered_set.rb +380 -0
  97. data/lib/ardm/support/subject.rb +33 -0
  98. data/lib/ardm/support/subject_set.rb +250 -0
  99. data/lib/ardm/version.rb +3 -0
  100. data/lib/ardm.rb +56 -0
  101. data/spec/fixtures/api_user.rb +11 -0
  102. data/spec/fixtures/article.rb +22 -0
  103. data/spec/fixtures/bookmark.rb +14 -0
  104. data/spec/fixtures/invention.rb +5 -0
  105. data/spec/fixtures/network_node.rb +23 -0
  106. data/spec/fixtures/person.rb +17 -0
  107. data/spec/fixtures/software_package.rb +22 -0
  108. data/spec/fixtures/ticket.rb +12 -0
  109. data/spec/fixtures/tshirt.rb +15 -0
  110. data/spec/integration/api_key_spec.rb +25 -0
  111. data/spec/integration/bcrypt_hash_spec.rb +45 -0
  112. data/spec/integration/comma_separated_list_spec.rb +85 -0
  113. data/spec/integration/dirty_minder_spec.rb +197 -0
  114. data/spec/integration/enum_spec.rb +79 -0
  115. data/spec/integration/epoch_time_spec.rb +59 -0
  116. data/spec/integration/file_path_spec.rb +158 -0
  117. data/spec/integration/flag_spec.rb +72 -0
  118. data/spec/integration/ip_address_spec.rb +151 -0
  119. data/spec/integration/json_spec.rb +70 -0
  120. data/spec/integration/slug_spec.rb +65 -0
  121. data/spec/integration/uri_spec.rb +136 -0
  122. data/spec/integration/uuid_spec.rb +102 -0
  123. data/spec/integration/yaml_spec.rb +85 -0
  124. data/spec/public/property/binary_spec.rb +41 -0
  125. data/spec/public/property/boolean_spec.rb +30 -0
  126. data/spec/public/property/class_spec.rb +28 -0
  127. data/spec/public/property/date_spec.rb +22 -0
  128. data/spec/public/property/date_time_spec.rb +22 -0
  129. data/spec/public/property/decimal_spec.rb +23 -0
  130. data/spec/public/property/discriminator_spec.rb +133 -0
  131. data/spec/public/property/float_spec.rb +22 -0
  132. data/spec/public/property/integer_spec.rb +22 -0
  133. data/spec/public/property/object_spec.rb +103 -0
  134. data/spec/public/property/serial_spec.rb +22 -0
  135. data/spec/public/property/string_spec.rb +22 -0
  136. data/spec/public/property/text_spec.rb +23 -0
  137. data/spec/public/property/time_spec.rb +22 -0
  138. data/spec/public/property_spec.rb +316 -0
  139. data/spec/rcov.opts +6 -0
  140. data/spec/schema.rb +86 -0
  141. data/spec/semipublic/property/binary_spec.rb +14 -0
  142. data/spec/semipublic/property/boolean_spec.rb +48 -0
  143. data/spec/semipublic/property/class_spec.rb +36 -0
  144. data/spec/semipublic/property/date_spec.rb +44 -0
  145. data/spec/semipublic/property/date_time_spec.rb +47 -0
  146. data/spec/semipublic/property/decimal_spec.rb +83 -0
  147. data/spec/semipublic/property/discriminator_spec.rb +22 -0
  148. data/spec/semipublic/property/float_spec.rb +83 -0
  149. data/spec/semipublic/property/integer_spec.rb +83 -0
  150. data/spec/semipublic/property/lookup_spec.rb +27 -0
  151. data/spec/semipublic/property/serial_spec.rb +14 -0
  152. data/spec/semipublic/property/string_spec.rb +14 -0
  153. data/spec/semipublic/property/text_spec.rb +30 -0
  154. data/spec/semipublic/property/time_spec.rb +49 -0
  155. data/spec/semipublic/property_spec.rb +51 -0
  156. data/spec/shared/flags_shared_spec.rb +36 -0
  157. data/spec/shared/identity_function_group.rb +5 -0
  158. data/spec/shared/public_property_spec.rb +229 -0
  159. data/spec/shared/semipublic_property_spec.rb +159 -0
  160. data/spec/spec.opts +4 -0
  161. data/spec/spec_helper.rb +58 -0
  162. data/spec/unit/bcrypt_hash_spec.rb +154 -0
  163. data/spec/unit/csv_spec.rb +139 -0
  164. data/spec/unit/dirty_minder_spec.rb +64 -0
  165. data/spec/unit/enum_spec.rb +125 -0
  166. data/spec/unit/epoch_time_spec.rb +72 -0
  167. data/spec/unit/file_path_spec.rb +75 -0
  168. data/spec/unit/flag_spec.rb +114 -0
  169. data/spec/unit/ip_address_spec.rb +109 -0
  170. data/spec/unit/json_spec.rb +127 -0
  171. data/spec/unit/paranoid_boolean_spec.rb +142 -0
  172. data/spec/unit/paranoid_datetime_spec.rb +149 -0
  173. data/spec/unit/regexp_spec.rb +62 -0
  174. data/spec/unit/uri_spec.rb +64 -0
  175. data/spec/unit/yaml_spec.rb +111 -0
  176. data/tasks/spec.rake +40 -0
  177. data/tasks/yard.rake +9 -0
  178. data/tasks/yardstick.rake +19 -0
  179. metadata +350 -0
@@ -0,0 +1,316 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+ require 'addressable/uri'
4
+
5
+ # instance methods
6
+ describe Ardm::Property do
7
+
8
+ # define the model prior to supported_by
9
+ before do
10
+ class ::Track < Ardm::Record
11
+ property :id, Serial
12
+ property :artist, String, :lazy => false, :index => :artist_album
13
+ property :title, String, :field => 'name', :index => true
14
+ property :album, String, :index => :artist_album
15
+ property :musicbrainz_hash, String, :unique => true, :unique_index => true
16
+ end
17
+
18
+ class ::Image < Ardm::Record
19
+ property :md5hash, String, :key => true, :length => 32
20
+ property :title, String, :required => true, :unique => true
21
+ property :description, Text, :length => 1..1024, :lazy => [ :detail ]
22
+ property :width, Integer, :lazy => [:dimensions]
23
+ property :height, Integer, :lazy => [:dimensions]
24
+ property :format, String, :default => 'jpeg'
25
+ property :taken_at, Time, :default => proc { Time.now }
26
+
27
+ validates_presence_of :format
28
+ end
29
+ end
30
+
31
+ describe '#field' do
32
+ it 'returns @field value if it is present' do
33
+ Track.properties[:title].field.should eql('name')
34
+ end
35
+ end
36
+
37
+ describe '#default_for' do
38
+ it 'returns default value for non-callables' do
39
+ Image.properties[:format].default_for(Image.new).should == 'jpeg'
40
+ end
41
+
42
+ it 'returns result of a call for callable values' do
43
+ Image.properties[:taken_at].default_for(Image.new).year.should == Time.now.year
44
+ end
45
+
46
+ it "sets the default when the record is created" do
47
+ img = Image.create!(title: 'My Picture')
48
+ img.format.should == 'jpeg'
49
+ end
50
+ end
51
+
52
+ describe '#eql?' do
53
+ it 'is true for properties with the same model and name' do
54
+ Track.properties[:title].should eql(Track.properties[:title])
55
+ end
56
+
57
+
58
+ it 'is false for properties of different models' do
59
+ Track.properties[:title].should_not eql(Image.properties[:title])
60
+ end
61
+
62
+ it 'is false for properties with different names' do
63
+ Track.properties[:title].should_not eql(Track.properties[:id])
64
+ end
65
+ end
66
+
67
+ describe '#get!' do
68
+ before do
69
+ @image = Image.new
70
+
71
+ # now some dark Ruby magic
72
+ @image.instance_variable_set(:@description, 'Is set by magic')
73
+ end
74
+
75
+ it 'gets instance variable value from the resource directly' do
76
+ pending "support for this in ActiveRecord is questionable" do
77
+ # if you know a better way to test direct instance variable access,
78
+ # go ahead and make changes to this example
79
+ Image.properties[:description].get!(@image).should == 'Is set by magic'
80
+ end
81
+ end
82
+ end
83
+
84
+ describe '#index' do
85
+ it 'returns true when property has an index' do
86
+ Track.properties[:title].index.should be(true)
87
+ end
88
+
89
+ it 'returns index name when property has a named index' do
90
+ Track.properties[:album].index.should eql(:artist_album)
91
+ end
92
+
93
+ it 'returns false when property has no index' do
94
+ Track.properties[:musicbrainz_hash].index.should be(false)
95
+ end
96
+ end
97
+
98
+ describe '#initialize' do
99
+ describe 'when tracking strategy is explicitly given' do
100
+ it 'uses tracking strategy from options'
101
+ end
102
+ end
103
+
104
+ describe '#inspect' do
105
+ before do
106
+ @str = Track.properties[:title].inspect
107
+ end
108
+
109
+ it 'features model name' do
110
+ @str.should =~ /@model=Track/
111
+ end
112
+
113
+ it 'features property name' do
114
+ @str.should =~ /@name=:title/
115
+ end
116
+ end
117
+
118
+ describe '#key?' do
119
+ describe 'returns true when property is a ' do
120
+ it 'serial key' do
121
+ Track.properties[:id].key?.should be(true)
122
+ end
123
+ it 'natural key' do
124
+ Image.properties[:md5hash].key?.should be(true)
125
+ end
126
+ end
127
+
128
+ it 'returns true when property is a part of composite key'
129
+
130
+ it 'returns false when property does not relate to a key' do
131
+ Track.properties[:title].key?.should be(false)
132
+ end
133
+ end
134
+
135
+ describe '#lazy?' do
136
+ it 'returns true when property is lazy loaded' do
137
+ Image.properties[:description].lazy?.should be(true)
138
+ end
139
+
140
+ it 'returns false when property is not lazy loaded' do
141
+ Track.properties[:artist].lazy?.should be(false)
142
+ end
143
+ end
144
+
145
+ describe '#length' do
146
+ it 'returns upper bound for Range values' do
147
+ Image.properties[:description].length.should eql(1024)
148
+ end
149
+
150
+ it 'returns value as is for integer values' do
151
+ Image.properties[:md5hash].length.should eql(32)
152
+ end
153
+ end
154
+
155
+ describe '#min' do
156
+ describe 'when :min and :max options not provided to constructor' do
157
+ before do
158
+ @property = Image.property(:integer_with_nil_min, Integer)
159
+ end
160
+
161
+ it 'should be nil' do
162
+ @property.min.should be_nil
163
+ end
164
+ end
165
+
166
+ describe 'when :min option not provided to constructor, but :max is provided' do
167
+ before do
168
+ @property = Image.property(:integer_with_default_min, Integer, :max => 1)
169
+ end
170
+
171
+ it 'should be the default value' do
172
+ @property.min.should == 0
173
+ end
174
+ end
175
+
176
+ describe 'when :min and :max options provided to constructor' do
177
+ before do
178
+ @min = 1
179
+ @property = Image.property(:integer_with_explicit_min, Integer, :min => @min, :max => 2)
180
+ end
181
+
182
+ it 'should be the expected value' do
183
+ @property.min.should == @min
184
+ end
185
+ end
186
+ end
187
+
188
+ describe '#max' do
189
+ describe 'when :min and :max options not provided to constructor' do
190
+ before do
191
+ @property = Image.property(:integer_with_nil_max, Integer)
192
+ end
193
+
194
+ it 'should be nil' do
195
+ @property.max.should be_nil
196
+ end
197
+ end
198
+
199
+ describe 'when :max option not provided to constructor, but :min is provided' do
200
+ before do
201
+ @property = Image.property(:integer_with_default_max, Integer, :min => 1)
202
+ end
203
+
204
+ it 'should be the default value' do
205
+ @property.max.should == 2**31-1
206
+ end
207
+ end
208
+
209
+ describe 'when :min and :max options provided to constructor' do
210
+ before do
211
+ @max = 2
212
+ @property = Image.property(:integer_with_explicit_max, Integer, :min => 1, :max => @max)
213
+ end
214
+
215
+ it 'should be the expected value' do
216
+ @property.max.should == @max
217
+ end
218
+ end
219
+ end
220
+
221
+ describe '#allow_nil?' do
222
+ it 'returns true when property can accept nil as its value' do
223
+ Track.properties[:artist].allow_nil?.should be(true)
224
+ end
225
+
226
+ it 'returns false when property nil value is prohibited for this property' do
227
+ Image.properties[:title].allow_nil?.should be(false)
228
+ end
229
+ end
230
+
231
+ describe '#serial?' do
232
+ it 'returns true when property is serial (auto incrementing)' do
233
+ Track.properties[:id].serial?.should be(true)
234
+ end
235
+
236
+ it 'returns false when property is NOT serial (auto incrementing)' do
237
+ Image.properties[:md5hash].serial?.should be(false)
238
+ end
239
+ end
240
+
241
+ describe '#set' do
242
+ before do
243
+ # keep in mind we must run these examples with a
244
+ # saved model instance
245
+ @image = Image.create(
246
+ :md5hash => '5268f0f3f452844c79843e820f998869',
247
+ :title => 'Rome at the sunset',
248
+ :description => 'Just wow'
249
+ )
250
+
251
+ @property = Image.properties[:title]
252
+ end
253
+
254
+ it 'triggers lazy loading for given resource'
255
+
256
+ it 'type casts given value' do
257
+ @property.set(@image, Addressable::URI.parse('http://test.example/'))
258
+ # get a string that has been typecasted using #to_str
259
+ @image.title.should == 'http://test.example/'
260
+ end
261
+
262
+ it 'sets new property value' do
263
+ @property.set(@image, 'Updated value')
264
+ @image.title.should == 'Updated value'
265
+ end
266
+ end
267
+
268
+ describe '#set!' do
269
+ before do
270
+ @image = Image.new(:md5hash => '5268f0f3f452844c79843e820f998869',
271
+ :title => 'Rome at the sunset',
272
+ :description => 'Just wow')
273
+
274
+ @property = Image.properties[:title]
275
+ end
276
+
277
+ it 'directly sets instance variable on given resource' do
278
+ @property.set!(@image, 'Set with dark Ruby magic')
279
+ @image.title.should == 'Set with dark Ruby magic'
280
+ end
281
+ end
282
+
283
+ describe '#unique?' do
284
+ it 'is true for fields that explicitly given uniq index' do
285
+ Track.properties[:musicbrainz_hash].unique?.should be(true)
286
+ end
287
+
288
+ it 'is true for serial fields' do
289
+ pending do
290
+ Track.properties[:title].unique?.should be(true)
291
+ end
292
+ end
293
+
294
+ it 'is true for keys' do
295
+ Image.properties[:md5hash].unique?.should be(true)
296
+ end
297
+ end
298
+
299
+ describe '#unique_index' do
300
+ it 'returns true when property has unique index' do
301
+ Track.properties[:musicbrainz_hash].unique_index.should be(true)
302
+ end
303
+
304
+ it 'returns false when property has no unique index' do
305
+ Track.properties[:title].unique_index.should be(false)
306
+ end
307
+
308
+ it 'returns true when property is unique' do
309
+ Image.properties[:title].unique_index.should be(true)
310
+ end
311
+
312
+ it 'returns :key when property is a key' do
313
+ Track.properties[:id].unique_index.should == :key
314
+ end
315
+ end
316
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1,6 @@
1
+ --exclude "spec,^/"
2
+ --sort coverage
3
+ --callsites
4
+ --xrefs
5
+ --profile
6
+ --text-summary
data/spec/schema.rb ADDED
@@ -0,0 +1,86 @@
1
+ ::ActiveRecord::Schema.define do
2
+
3
+ create_table :api_users, :force => true do |t|
4
+ t.string :name
5
+ t.string :api_key
6
+ end
7
+
8
+ create_table :articles, :force => true do |t|
9
+ t.string :title
10
+ t.text :body
11
+ t.timestamps
12
+ t.datetime :published_at
13
+ t.boolean :deleted
14
+ t.datetime :deleted_at
15
+ t.string :slug
16
+ end
17
+
18
+ create_table :bookmarks, :force => true do |t|
19
+ t.string :title
20
+ t.boolean :shared
21
+ t.string :uri
22
+ t.text :tags
23
+ end
24
+
25
+ create_table :images, :force => true, :id => false do |t|
26
+ t.string :md5hash, :length => 32
27
+ t.index :md5hash, :unique => true
28
+ t.string :title
29
+ t.text :description, :length => 1024
30
+ t.integer :width
31
+ t.integer :height
32
+ t.string :format
33
+ t.time :taken_at
34
+ end
35
+
36
+ create_table :network_nodes, :force => true do |t|
37
+ t.string :ip_address
38
+ t.integer :cidr_subnet_bits
39
+ t.string :node_uuid
40
+ end
41
+
42
+ create_table :people, :force => true do |t|
43
+ t.string :name
44
+ t.text :positions
45
+ t.text :inventions
46
+ t.time :birthday
47
+ t.text :interests
48
+ t.string :password
49
+ end
50
+
51
+ create_table :software_packages, :force => true do |t|
52
+ t.integer :node_number
53
+ t.string :source_path
54
+ t.string :destination_path
55
+ t.string :product
56
+ t.string :version
57
+ t.datetime :released_at
58
+ t.boolean :security_update
59
+ t.datetime :installed_at
60
+ t.string :installed_by
61
+ end
62
+
63
+ create_table :tickets, :force => true do |t|
64
+ t.string :title
65
+ t.text :body
66
+ t.integer :status
67
+ end
68
+
69
+ create_table :tracks, :force => true do |t|
70
+ t.string :artist
71
+ t.string :name
72
+ t.string :album
73
+ t.string :musicbrainz_hash
74
+ t.index [:artist, :album]
75
+ t.index :name
76
+ t.index :musicbrainz_hash, :unique => true
77
+ end
78
+
79
+ create_table :tshirts, :force => true do |t|
80
+ t.string :writing
81
+ t.boolean :has_picture
82
+ t.text :picture
83
+ t.text :color
84
+ t.text :size
85
+ end
86
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Binary do
4
+ let(:name) { :title }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { 'value' }
8
+ let(:other_value) { 'return value' }
9
+ let(:invalid_value) { 1 }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Boolean do
4
+ let(:name) { :active }
5
+ let(:type) { described_class }
6
+ let(:options) { {:set => [true, false]} }
7
+ let(:value) { true }
8
+ let(:other_value) { false }
9
+ let(:invalid_value) { 1 }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#valid?' do
16
+ [ true, false ].each do |value|
17
+ it "returns true when value is #{value.inspect}" do
18
+ property.valid?(value).should be(true)
19
+ end
20
+ end
21
+
22
+ [ 'true', 'TRUE', '1', 1, 't', 'T', 'false', 'FALSE', '0', 0, 'f', 'F' ].each do |value|
23
+ it "returns false for #{value.inspect}" do
24
+ property.valid?(value).should be(false)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#typecast' do
30
+ [ true, 'true', 'TRUE', '1', 1, 't', 'T' ].each do |value|
31
+ it "returns true when value is #{value.inspect}" do
32
+ property.typecast(value).should be(true)
33
+ end
34
+ end
35
+
36
+ [ false, 'false', 'FALSE', '0', 0, 'f', 'F' ].each do |value|
37
+ it "returns false when value is #{value.inspect}" do
38
+ property.typecast(value).should be(false)
39
+ end
40
+ end
41
+
42
+ [ 'string', 2, 1.0, BigDecimal('1.0'), DateTime.now, Time.now, Date.today, Class, Object.new, ].each do |value|
43
+ it "does not typecast value #{value.inspect}" do
44
+ property.typecast(value).should equal(value)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Class do
4
+ before do
5
+ Object.send(:remove_const, :Foo) if defined?(Foo)
6
+ Object.send(:remove_const, :Bar) if defined?(Bar)
7
+
8
+ class ::Foo; end
9
+ class ::Bar; end
10
+ end
11
+
12
+ let(:name) { :type }
13
+ let(:type) { described_class }
14
+ let(:options) { {} }
15
+ let(:value) { Foo }
16
+ let(:other_value) { Bar }
17
+ let(:invalid_value) { 1 }
18
+ let(:model) { Blog::Article }
19
+ let(:property) { type.new(model, name, options) }
20
+
21
+ it_should_behave_like 'A semipublic Property'
22
+
23
+ describe '#typecast' do
24
+ it 'returns same value if a class' do
25
+ property.typecast(model).should equal(model)
26
+ end
27
+
28
+ it 'returns the class if found' do
29
+ property.typecast(model.name).should eql(model)
30
+ end
31
+
32
+ it 'does not typecast non-class values' do
33
+ property.typecast('NoClass').should eql('NoClass')
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Date do
4
+ let(:name) { :created_on }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { Date.today }
8
+ let(:other_value) { Date.today + 1 }
9
+ let(:invalid_value) { 1 }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#typecast' do
16
+ describe 'and value given as a hash with keys like :year, :month, etc' do
17
+ it 'builds a Date instance from hash values' do
18
+ result = property.typecast(
19
+ :year => '2007',
20
+ :month => '3',
21
+ :day => '25'
22
+ )
23
+
24
+ result.should be_kind_of(Date)
25
+ result.year.should eql(2007)
26
+ result.month.should eql(3)
27
+ result.day.should eql(25)
28
+ end
29
+ end
30
+
31
+ describe 'and value is a string' do
32
+ it 'parses the string' do
33
+ result = property.typecast('Dec 20th, 2006')
34
+ result.month.should == 12
35
+ result.day.should == 20
36
+ result.year.should == 2006
37
+ end
38
+ end
39
+
40
+ it 'does not typecast non-date values' do
41
+ property.typecast('not-date').should eql('not-date')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::DateTime do
4
+ let(:name) { :created_at }
5
+ let(:type) { described_class }
6
+ let(:options) { {} }
7
+ let(:value) { DateTime.now }
8
+ let(:other_value) { DateTime.now + 15 }
9
+ let(:invalid_value) { 1 }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#typecast' do
16
+ describe 'and value given as a hash with keys like :year, :month, etc' do
17
+ it 'builds a DateTime instance from hash values' do
18
+ result = property.typecast(
19
+ :year => '2006',
20
+ :month => '11',
21
+ :day => '23',
22
+ :hour => '12',
23
+ :min => '0',
24
+ :sec => '0'
25
+ )
26
+
27
+ result.should be_kind_of(DateTime)
28
+ result.year.should eql(2006)
29
+ result.month.should eql(11)
30
+ result.day.should eql(23)
31
+ result.hour.should eql(12)
32
+ result.min.should eql(0)
33
+ result.sec.should eql(0)
34
+ end
35
+ end
36
+
37
+ describe 'and value is a string' do
38
+ it 'parses the string' do
39
+ property.typecast('Dec, 2006').month.should == 12
40
+ end
41
+ end
42
+
43
+ it 'does not typecast non-datetime values' do
44
+ property.typecast('not-datetime').should eql('not-datetime')
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ardm::Property::Decimal do
4
+ let(:name) { :rate }
5
+ let(:type) { described_class }
6
+ let(:options) { { :precision => 5, :scale => 2 } }
7
+ let(:value) { BigDecimal('1.0') }
8
+ let(:other_value) { BigDecimal('2.0') }
9
+ let(:invalid_value) { true }
10
+ let(:model) { Blog::Article }
11
+ let(:property) { type.new(model, name, options) }
12
+
13
+ it_should_behave_like 'A semipublic Property'
14
+
15
+ describe '#typecast' do
16
+ it 'returns same value if a decimal' do
17
+ @value = BigDecimal('24.0')
18
+ property.typecast(@value).should equal(@value)
19
+ end
20
+
21
+ it 'returns decimal representation of a zero string integer' do
22
+ property.typecast('0').should eql(BigDecimal('0.0'))
23
+ end
24
+
25
+ it 'returns decimal representation of a positive string integer' do
26
+ property.typecast('24').should eql(BigDecimal('24.0'))
27
+ end
28
+
29
+ it 'returns decimal representation of a negative string integer' do
30
+ property.typecast('-24').should eql(BigDecimal('-24.0'))
31
+ end
32
+
33
+ it 'returns decimal representation of a zero string float' do
34
+ property.typecast('0.0').should eql(BigDecimal('0.0'))
35
+ end
36
+
37
+ it 'returns decimal representation of a positive string float' do
38
+ property.typecast('24.35').should eql(BigDecimal('24.35'))
39
+ end
40
+
41
+ it 'returns decimal representation of a negative string float' do
42
+ property.typecast('-24.35').should eql(BigDecimal('-24.35'))
43
+ end
44
+
45
+ it 'returns decimal representation of a zero string float, with no leading digits' do
46
+ property.typecast('.0').should eql(BigDecimal('0.0'))
47
+ end
48
+
49
+ it 'returns decimal representation of a positive string float, with no leading digits' do
50
+ property.typecast('.41').should eql(BigDecimal('0.41'))
51
+ end
52
+
53
+ it 'returns decimal representation of a zero integer' do
54
+ property.typecast(0).should eql(BigDecimal('0.0'))
55
+ end
56
+
57
+ it 'returns decimal representation of a positive integer' do
58
+ property.typecast(24).should eql(BigDecimal('24.0'))
59
+ end
60
+
61
+ it 'returns decimal representation of a negative integer' do
62
+ property.typecast(-24).should eql(BigDecimal('-24.0'))
63
+ end
64
+
65
+ it 'returns decimal representation of a zero float' do
66
+ property.typecast(0.0).should eql(BigDecimal('0.0'))
67
+ end
68
+
69
+ it 'returns decimal representation of a positive float' do
70
+ property.typecast(24.35).should eql(BigDecimal('24.35'))
71
+ end
72
+
73
+ it 'returns decimal representation of a negative float' do
74
+ property.typecast(-24.35).should eql(BigDecimal('-24.35'))
75
+ end
76
+
77
+ [ Object.new, true, '0.', '-.0', 'string' ].each do |value|
78
+ it "does not typecast non-numeric value #{value.inspect}" do
79
+ property.typecast(value).should equal(value)
80
+ end
81
+ end
82
+ end
83
+ end