dm-core 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/CHANGELOG +144 -0
  2. data/FAQ +74 -0
  3. data/MIT-LICENSE +22 -0
  4. data/QUICKLINKS +12 -0
  5. data/README +143 -0
  6. data/lib/dm-core.rb +213 -0
  7. data/lib/dm-core/adapters.rb +4 -0
  8. data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
  9. data/lib/dm-core/adapters/data_objects_adapter.rb +701 -0
  10. data/lib/dm-core/adapters/mysql_adapter.rb +132 -0
  11. data/lib/dm-core/adapters/postgres_adapter.rb +179 -0
  12. data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  13. data/lib/dm-core/associations.rb +172 -0
  14. data/lib/dm-core/associations/many_to_many.rb +138 -0
  15. data/lib/dm-core/associations/many_to_one.rb +101 -0
  16. data/lib/dm-core/associations/one_to_many.rb +275 -0
  17. data/lib/dm-core/associations/one_to_one.rb +61 -0
  18. data/lib/dm-core/associations/relationship.rb +116 -0
  19. data/lib/dm-core/associations/relationship_chain.rb +74 -0
  20. data/lib/dm-core/auto_migrations.rb +64 -0
  21. data/lib/dm-core/collection.rb +604 -0
  22. data/lib/dm-core/hook.rb +11 -0
  23. data/lib/dm-core/identity_map.rb +45 -0
  24. data/lib/dm-core/is.rb +16 -0
  25. data/lib/dm-core/logger.rb +233 -0
  26. data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  27. data/lib/dm-core/migrator.rb +29 -0
  28. data/lib/dm-core/model.rb +399 -0
  29. data/lib/dm-core/naming_conventions.rb +52 -0
  30. data/lib/dm-core/property.rb +611 -0
  31. data/lib/dm-core/property_set.rb +158 -0
  32. data/lib/dm-core/query.rb +590 -0
  33. data/lib/dm-core/repository.rb +159 -0
  34. data/lib/dm-core/resource.rb +618 -0
  35. data/lib/dm-core/scope.rb +35 -0
  36. data/lib/dm-core/support.rb +7 -0
  37. data/lib/dm-core/support/array.rb +13 -0
  38. data/lib/dm-core/support/assertions.rb +8 -0
  39. data/lib/dm-core/support/errors.rb +23 -0
  40. data/lib/dm-core/support/kernel.rb +7 -0
  41. data/lib/dm-core/support/symbol.rb +41 -0
  42. data/lib/dm-core/transaction.rb +267 -0
  43. data/lib/dm-core/type.rb +160 -0
  44. data/lib/dm-core/type_map.rb +80 -0
  45. data/lib/dm-core/types.rb +19 -0
  46. data/lib/dm-core/types/boolean.rb +7 -0
  47. data/lib/dm-core/types/discriminator.rb +32 -0
  48. data/lib/dm-core/types/object.rb +20 -0
  49. data/lib/dm-core/types/paranoid_boolean.rb +23 -0
  50. data/lib/dm-core/types/paranoid_datetime.rb +22 -0
  51. data/lib/dm-core/types/serial.rb +9 -0
  52. data/lib/dm-core/types/text.rb +10 -0
  53. data/spec/integration/association_spec.rb +1215 -0
  54. data/spec/integration/association_through_spec.rb +150 -0
  55. data/spec/integration/associations/many_to_many_spec.rb +171 -0
  56. data/spec/integration/associations/many_to_one_spec.rb +123 -0
  57. data/spec/integration/associations/one_to_many_spec.rb +66 -0
  58. data/spec/integration/auto_migrations_spec.rb +398 -0
  59. data/spec/integration/collection_spec.rb +1015 -0
  60. data/spec/integration/data_objects_adapter_spec.rb +32 -0
  61. data/spec/integration/model_spec.rb +68 -0
  62. data/spec/integration/mysql_adapter_spec.rb +85 -0
  63. data/spec/integration/postgres_adapter_spec.rb +732 -0
  64. data/spec/integration/property_spec.rb +224 -0
  65. data/spec/integration/query_spec.rb +376 -0
  66. data/spec/integration/repository_spec.rb +57 -0
  67. data/spec/integration/resource_spec.rb +324 -0
  68. data/spec/integration/sqlite3_adapter_spec.rb +352 -0
  69. data/spec/integration/sti_spec.rb +185 -0
  70. data/spec/integration/transaction_spec.rb +75 -0
  71. data/spec/integration/type_spec.rb +149 -0
  72. data/spec/lib/mock_adapter.rb +27 -0
  73. data/spec/spec_helper.rb +112 -0
  74. data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
  75. data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
  76. data/spec/unit/adapters/data_objects_adapter_spec.rb +627 -0
  77. data/spec/unit/adapters/postgres_adapter_spec.rb +125 -0
  78. data/spec/unit/associations/many_to_many_spec.rb +14 -0
  79. data/spec/unit/associations/many_to_one_spec.rb +138 -0
  80. data/spec/unit/associations/one_to_many_spec.rb +385 -0
  81. data/spec/unit/associations/one_to_one_spec.rb +7 -0
  82. data/spec/unit/associations/relationship_spec.rb +67 -0
  83. data/spec/unit/associations_spec.rb +205 -0
  84. data/spec/unit/auto_migrations_spec.rb +110 -0
  85. data/spec/unit/collection_spec.rb +174 -0
  86. data/spec/unit/data_mapper_spec.rb +21 -0
  87. data/spec/unit/identity_map_spec.rb +126 -0
  88. data/spec/unit/is_spec.rb +80 -0
  89. data/spec/unit/migrator_spec.rb +33 -0
  90. data/spec/unit/model_spec.rb +339 -0
  91. data/spec/unit/naming_conventions_spec.rb +28 -0
  92. data/spec/unit/property_set_spec.rb +96 -0
  93. data/spec/unit/property_spec.rb +447 -0
  94. data/spec/unit/query_spec.rb +485 -0
  95. data/spec/unit/repository_spec.rb +93 -0
  96. data/spec/unit/resource_spec.rb +557 -0
  97. data/spec/unit/scope_spec.rb +131 -0
  98. data/spec/unit/transaction_spec.rb +493 -0
  99. data/spec/unit/type_map_spec.rb +114 -0
  100. data/spec/unit/type_spec.rb +119 -0
  101. metadata +187 -0
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe "DataMapper::NamingConventions" do
4
+ it "should coerce a string into the Underscored convention" do
5
+ DataMapper::NamingConventions::Underscored.call('User').should == 'user'
6
+ DataMapper::NamingConventions::Underscored.call('UserAccountSetting').should == 'user_account_setting'
7
+ end
8
+
9
+ it "should coerce a string into the UnderscoredAndPluralized convention" do
10
+ DataMapper::NamingConventions::UnderscoredAndPluralized.call('User').should == 'users'
11
+ DataMapper::NamingConventions::UnderscoredAndPluralized.call('UserAccountSetting').should == 'user_account_settings'
12
+ end
13
+
14
+ it "should coerce a string into the UnderscoredAndPluralized convention joining namespace with underscore" do
15
+ DataMapper::NamingConventions::UnderscoredAndPluralized.call('Model::User').should == 'model_users'
16
+ DataMapper::NamingConventions::UnderscoredAndPluralized.call('Model::UserAccountSetting').should == 'model_user_account_settings'
17
+ end
18
+
19
+ it "should coerce a string into the UnderscoredAndPluralizedWithoutModule convention" do
20
+ DataMapper::NamingConventions::UnderscoredAndPluralizedWithoutModule.call('Model::User').should == 'users'
21
+ DataMapper::NamingConventions::UnderscoredAndPluralizedWithoutModule.call('Model::UserAccountSetting').should == 'user_account_settings'
22
+ end
23
+
24
+ it "should coerce a string into the Yaml convention" do
25
+ DataMapper::NamingConventions::Yaml.call('UserSetting').should == 'user_settings.yaml'
26
+ DataMapper::NamingConventions::Yaml.call('User').should == 'users.yaml'
27
+ end
28
+ end
@@ -0,0 +1,96 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ class Icon
4
+ include DataMapper::Resource
5
+
6
+ property :id, Serial
7
+ property :name, String
8
+ property :width, Integer, :lazy => true
9
+ property :height, Integer, :lazy => true
10
+ end
11
+
12
+ class Boat
13
+ include DataMapper::Resource
14
+ property :name, String #not lazy
15
+ property :text, DataMapper::Types::Text #Lazy by default
16
+ property :notes, String, :lazy => true
17
+ property :a1, String, :lazy => [:ctx_a,:ctx_c]
18
+ property :a2, String, :lazy => [:ctx_a,:ctx_b]
19
+ property :a3, String, :lazy => [:ctx_a]
20
+ property :b1, String, :lazy => [:ctx_b]
21
+ property :b2, String, :lazy => [:ctx_b]
22
+ property :b3, String, :lazy => [:ctx_b]
23
+ end
24
+
25
+ describe DataMapper::PropertySet do
26
+ before :each do
27
+ @properties = Icon.properties(:default)
28
+ end
29
+
30
+ it "#slice should find properties" do
31
+ @properties.slice(:name, 'width').should have(2).entries
32
+ end
33
+
34
+ it "#select should find properties" do
35
+ @properties.select { |property| property.primitive == Integer }.should have(3).entries
36
+ end
37
+
38
+ it "#[] should find properties by name (Symbol or String)" do
39
+ default_properties = [ :id, 'name', :width, 'height' ]
40
+ @properties.each_with_index do |property,i|
41
+ property.should == @properties[default_properties[i]]
42
+ end
43
+ end
44
+
45
+ it "should provide defaults" do
46
+ @properties.defaults.should have(2).entries
47
+ @properties.should have(4).entries
48
+ end
49
+
50
+ it 'should add a property for lazy loading to the :default context if a context is not supplied' do
51
+ Boat.properties(:default).lazy_context(:default).length.should == 2 # text & notes
52
+ end
53
+
54
+ it 'should return a list of contexts that a given field is in' do
55
+ props = Boat.properties(:default)
56
+ set = props.property_contexts(:a1)
57
+ set.include?(:ctx_a).should == true
58
+ set.include?(:ctx_c).should == true
59
+ set.include?(:ctx_b).should == false
60
+ end
61
+
62
+ it 'should return a list of expanded fields that should be loaded with a given field' do
63
+ props = Boat.properties(:default)
64
+ set = props.lazy_load_context(:a2)
65
+ expect = [:a1,:a2,:a3,:b1,:b2,:b3]
66
+ expect.should == set.sort! {|a,b| a.to_s <=> b.to_s}
67
+ end
68
+
69
+ describe 'when dup\'ed' do
70
+ it 'should duplicate the @entries ivar' do
71
+ @properties.dup.entries.should_not equal(@properties.entries)
72
+ end
73
+
74
+ it 'should reinitialize @properties_for' do
75
+ # force @properties_for to hold a property
76
+ Icon.properties(:default)[:name].should_not be_nil
77
+ @properties = Icon.properties(:default)
78
+
79
+ @properties.instance_variable_get("@property_for").should_not be_empty
80
+ @properties.dup.instance_variable_get("@property_for").should be_empty
81
+ end
82
+
83
+ it 'should be able to retarget a new model' do
84
+ copy = Icon.properties.dup(Boat)
85
+ copy.should have(4).entries
86
+
87
+ copy.each do |property|
88
+ property.model.should == Boat
89
+ end
90
+
91
+ copy << DataMapper::Property.new(Icon, :z_index, Integer, {})
92
+ copy.should have(5).entries
93
+ Icon.properties.should have(4).entries
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,447 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Property do
4
+ before :all do
5
+ class Zoo
6
+ include DataMapper::Resource
7
+ end
8
+
9
+ class Name < DataMapper::Type
10
+ primitive String
11
+ size 100
12
+ end
13
+
14
+ class Tomato
15
+ include DataMapper::Resource
16
+ end
17
+ end
18
+
19
+ before do
20
+ @property = DataMapper::Property.new(Zoo, :name, String, :default => 'San Diego')
21
+ end
22
+
23
+ it 'should provide .new' do
24
+ DataMapper::Property.should respond_to(:new)
25
+ end
26
+
27
+ describe '.new' do
28
+ [ Float, BigDecimal ].each do |primitive|
29
+ describe "with a #{primitive} primitive" do
30
+ it 'should raise an ArgumentError if precision is equal to or less than 0' do
31
+ lambda{
32
+ DataMapper::Property.new(Zoo, :test, primitive, :precision => 0)
33
+ }.should raise_error(ArgumentError)
34
+
35
+ lambda{
36
+ DataMapper::Property.new(Zoo, :test, primitive, :precision => -1)
37
+ }.should raise_error(ArgumentError)
38
+ end
39
+
40
+ it 'should raise an ArgumentError if scale is less than 0' do
41
+ lambda{
42
+ DataMapper::Property.new(Zoo, :test, primitive, :scale => -1)
43
+ }.should raise_error(ArgumentError)
44
+ end
45
+
46
+ it 'should raise an ArgumentError if precision is less than scale' do
47
+ lambda{
48
+ DataMapper::Property.new(Zoo, :test, primitive, :precision => 1, :scale => 2)
49
+ }.should raise_error(ArgumentError)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ it 'should provide #get' do
56
+ @property.should respond_to(:get)
57
+ end
58
+
59
+ describe '#get' do
60
+ before do
61
+ @original_values = {}
62
+ @resource = mock('resource', :kind_of? => true, :new_record? => true, :original_values => @original_values)
63
+ end
64
+
65
+ describe 'when setting the default on initial access' do
66
+ before do
67
+ # make sure there was no original value
68
+ @original_values.should_not have_key(:name)
69
+
70
+ # force the default to be set
71
+ @resource.should_receive(:instance_variable_get).with('@name').twice.and_return(nil)
72
+ @resource.should_receive(:attribute_loaded?).with(:name).and_return(false)
73
+ end
74
+
75
+ it 'should set the ivar to the default' do
76
+ @resource.should_receive(:instance_variable_set).with('@name', 'San Diego')
77
+
78
+ @property.get(@resource).should == 'San Diego'
79
+ end
80
+
81
+ it 'should set the original value to nil' do
82
+ @property.get(@resource).should == 'San Diego'
83
+
84
+ @original_values.should == { :name => nil }
85
+ end
86
+ end
87
+ end
88
+
89
+ it 'should provide #get!' do
90
+ @property.should respond_to(:get!)
91
+ end
92
+
93
+ describe '#get!' do
94
+ it 'should get the resource instance variable' do
95
+ resource = mock('resource', :kind_of? => true)
96
+ resource.should_receive(:instance_variable_get).with('@name').and_return('Portland Zoo')
97
+ @property.get!(resource).should == 'Portland Zoo'
98
+ end
99
+ end
100
+
101
+ it 'should provide #set' do
102
+ @property.should respond_to(:set)
103
+ end
104
+
105
+ describe '#set' do
106
+ before do
107
+ @original_values = {}
108
+ @resource = mock('resource', :kind_of? => true, :original_values => @original_values)
109
+ end
110
+
111
+ it 'should typecast the value' do
112
+ @property.should_receive(:typecast).with(888)
113
+ @property.set(@resource, 888)
114
+ end
115
+ end
116
+
117
+ it 'should provide #set!' do
118
+ @property.should respond_to(:set!)
119
+ end
120
+
121
+ describe '#set!' do
122
+ it 'should set the resource instance variable' do
123
+ resource = mock('resource', :kind_of? => true)
124
+ resource.should_receive(:instance_variable_set).with('@name', 'Seattle Zoo').and_return(resource)
125
+ @property.set!(resource, 'Seattle Zoo').object_id.should == resource.object_id
126
+ end
127
+ end
128
+
129
+ it "should evaluate two similar properties as equal" do
130
+ p1 = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
131
+ p2 = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
132
+ p3 = DataMapper::Property.new(Zoo, :title, String, { :size => 30 })
133
+ p1.eql?(p2).should == true
134
+ p1.hash.should == p2.hash
135
+ p1.eql?(p3).should == false
136
+ p1.hash.should_not == p3.hash
137
+ end
138
+
139
+ it "should create a String property" do
140
+ property = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
141
+
142
+ property.primitive.should == String
143
+ end
144
+
145
+ it "should not have key that is lazy" do
146
+ property = DataMapper::Property.new(Zoo, :id, DataMapper::Types::Text, { :key => true })
147
+ property.lazy?.should == false
148
+ end
149
+
150
+ it "should use a custom type Name property" do
151
+ class Name < DataMapper::Type
152
+ primitive String
153
+ end
154
+
155
+ property = DataMapper::Property.new(Zoo, :name, Name, {})
156
+
157
+ property.primitive.should == String
158
+ property.type.should == Name
159
+ property.primitive.should == property.type.primitive
160
+ end
161
+
162
+ it "should override type options with property options" do
163
+ property = DataMapper::Property.new(Zoo, :name, Name, { :size => 50 })
164
+ options = property.instance_variable_get(:@options)
165
+
166
+ options[:size].should == 50
167
+ end
168
+
169
+ it "should determine nullness" do
170
+ DataMapper::Property.new(Tomato,:botanical_name,String,{:nullable => true}).options[:nullable].should == true
171
+ end
172
+
173
+ it "should determine its name" do
174
+ DataMapper::Property.new(Tomato,:botanical_name,String,{}).name.should == :botanical_name
175
+ end
176
+
177
+ it "should determine laziness" do
178
+ DataMapper::Property.new(Tomato,:botanical_name,String,{:lazy => true}).lazy?.should == true
179
+ DataMapper::Property.new(Tomato,:seedless,TrueClass,{}).lazy?.should == false
180
+ end
181
+
182
+ it "should automatically set laziness to true on text fields?" do
183
+ DataMapper::Property.new(Tomato,:botanical_name,DataMapper::Types::Text,{}).lazy?.should == true
184
+ end
185
+
186
+ it "should determine whether it is a key" do
187
+ DataMapper::Property.new(Tomato,:id,Integer,{:key => true}).key?.should == true
188
+ DataMapper::Property.new(Tomato,:botanical_name,String,{}).key?.should == false
189
+ end
190
+
191
+ it "should determine whether it is serial" do
192
+ DataMapper::Property.new(Tomato,:id,Integer,{:serial => true}).serial?.should == true
193
+ DataMapper::Property.new(Tomato,:botanical_name,String,{}).serial?.should == false
194
+ end
195
+
196
+ it "should determine a default value" do
197
+ resource = mock('resource')
198
+ property = DataMapper::Property.new(Tomato, :botanical_name, String, :default => 'Tomato')
199
+ property.default_for(resource).should == 'Tomato'
200
+ end
201
+
202
+ it "should determine visibility of readers and writers" do
203
+ name = DataMapper::Property.new(Tomato,:botanical_name,String,{})
204
+ name.reader_visibility.should == :public
205
+ name.writer_visibility.should == :public
206
+
207
+ seeds = DataMapper::Property.new(Tomato,:seeds,TrueClass,{:accessor=>:private})
208
+ seeds.reader_visibility.should == :private
209
+ seeds.writer_visibility.should == :private
210
+
211
+ family = DataMapper::Property.new(Tomato,:family,String,{:reader => :public, :writer => :private })
212
+ family.reader_visibility.should == :public
213
+ family.writer_visibility.should == :private
214
+ end
215
+
216
+ it "should return an instance variable name" do
217
+ DataMapper::Property.new(Tomato, :flavor, String, {}).instance_variable_name.should == '@flavor'
218
+ DataMapper::Property.new(Tomato, :ripe, TrueClass, {}).instance_variable_name.should == '@ripe' #not @ripe?
219
+ end
220
+
221
+ it "should append ? to TrueClass property reader methods" do
222
+ class Potato
223
+ include DataMapper::Resource
224
+ property :id, Integer, :key => true
225
+ property :fresh, TrueClass
226
+ property :public, TrueClass
227
+ end
228
+
229
+ Potato.new().should respond_to(:fresh)
230
+ Potato.new().should respond_to(:fresh?)
231
+
232
+ Potato.new(:fresh => true).should be_fresh
233
+
234
+ Potato.new().should respond_to(:public)
235
+ Potato.new().should respond_to(:public?)
236
+ end
237
+
238
+ it "should raise an ArgumentError when created with an invalid option" do
239
+ lambda{
240
+ DataMapper::Property.new(Tomato,:botanical_name,String,{:foo=>:bar})
241
+ }.should raise_error(ArgumentError)
242
+ end
243
+
244
+ it 'should return the attribute value from a given instance' do
245
+ class Tomato
246
+ include DataMapper::Resource
247
+ property :id, Integer, :key => true
248
+ end
249
+
250
+ tomato = Tomato.new(:id => 1)
251
+ tomato.model.properties(:default)[:id].get(tomato).should == 1
252
+ end
253
+
254
+ it 'should set the attribute value in a given instance' do
255
+ tomato = Tomato.new
256
+ tomato.model.properties(:default)[:id].set(tomato, 2)
257
+ tomato.id.should == 2
258
+ end
259
+
260
+ it 'should provide #custom?' do
261
+ DataMapper::Property.new(Zoo, :name, Name, { :size => 50 }).should be_custom
262
+ DataMapper::Property.new(Zoo, :state, String, { :size => 2 }).should_not be_custom
263
+ end
264
+
265
+ it "should set the field to the correct field_naming_convention" do
266
+ DataMapper::Property.new(Zoo, :species, String, {}).field.should == 'species'
267
+ DataMapper::Property.new(Tomato, :genetic_history, DataMapper::Types::Text, {}).field.should == "genetic_history"
268
+ end
269
+
270
+ it "should provide the primitive mapping" do
271
+ DataMapper::Property.new(Zoo, :poverty, String, {}).primitive.should == String
272
+ DataMapper::Property.new(Zoo, :fortune, DataMapper::Types::Text, {}).primitive.should == String
273
+ end
274
+
275
+ it "should provide a size/length" do
276
+ DataMapper::Property.new(Zoo, :cleanliness, String, { :size => 100 }).size.should == 100
277
+ DataMapper::Property.new(Zoo, :cleanliness, String, { :length => 200 }).size.should == 200
278
+ DataMapper::Property.new(Zoo, :cleanliness, String, { :size => (0..100) }).size.should == 100
279
+ DataMapper::Property.new(Zoo, :cleanliness, String, { :length => (0..200) }).size.should == 200
280
+ end
281
+
282
+ it 'should provide #typecast' do
283
+ DataMapper::Property.new(Zoo, :name, String).should respond_to(:typecast)
284
+ end
285
+
286
+ describe '#typecast' do
287
+ def self.format(value)
288
+ case value
289
+ when BigDecimal then "BigDecimal(#{value.to_s('F').inspect})"
290
+ when Float, Integer, String then "#{value.class}(#{value.inspect})"
291
+ else value.inspect
292
+ end
293
+ end
294
+
295
+ it 'should pass through the value if it is the same type when typecasting' do
296
+ value = 'San Diego'
297
+ property = DataMapper::Property.new(Zoo, :name, String)
298
+ property.typecast(value).object_id.should == value.object_id
299
+ end
300
+
301
+ it 'should pass through the value nil when typecasting' do
302
+ property = DataMapper::Property.new(Zoo, :string, String)
303
+ property.typecast(nil).should == nil
304
+ end
305
+
306
+ it 'should pass through the value for an Object property' do
307
+ value = 'a ruby object'
308
+ property = DataMapper::Property.new(Zoo, :object, Object)
309
+ property.typecast(value).object_id.should == value.object_id
310
+ end
311
+
312
+ [ true, 'true', 'TRUE', 1, '1', 't', 'T' ].each do |value|
313
+ it "should typecast #{value.inspect} to true for a TrueClass property" do
314
+ property = DataMapper::Property.new(Zoo, :true_class, TrueClass)
315
+ property.typecast(value).should == true
316
+ end
317
+ end
318
+
319
+ [ false, 'false', 'FALSE', 0, '0', 'f', 'F' ].each do |value|
320
+ it "should typecast #{value.inspect} to false for a Boolean property" do
321
+ property = DataMapper::Property.new(Zoo, :true_class, TrueClass)
322
+ property.typecast(value).should == false
323
+ end
324
+ end
325
+
326
+ it 'should typecast nil to nil for a Boolean property' do
327
+ property = DataMapper::Property.new(Zoo, :true_class, TrueClass)
328
+ property.typecast(nil).should == nil
329
+ end
330
+
331
+ it 'should typecast "0" to "0" for a String property' do
332
+ property = DataMapper::Property.new(Zoo, :string, String)
333
+ property.typecast(0).should == '0'
334
+ end
335
+
336
+ { '0' => 0.0, '0.0' => 0.0, 0 => 0.0, 0.0 => 0.0, BigDecimal('0.0') => 0.0 }.each do |value,expected|
337
+ it "should typecast #{format(value)} to #{format(expected)} for a Float property" do
338
+ property = DataMapper::Property.new(Zoo, :float, Float)
339
+ property.typecast(value).should == expected
340
+ end
341
+ end
342
+
343
+ { '0' => 0, '0.0' => 0, 0 => 0, 0.0 => 0, BigDecimal('0.0') => 0 }.each do |value,expected|
344
+ it "should typecast #{format(value)} to #{format(expected)} for an Integer property" do
345
+ property = DataMapper::Property.new(Zoo, :integer, Integer)
346
+ property.typecast(value).should == expected
347
+ end
348
+ end
349
+
350
+ { '0' => BigDecimal('0'), '0.0' => BigDecimal('0.0'), 0.0 => BigDecimal('0.0'), BigDecimal('0.0') => BigDecimal('0.0') }.each do |value,expected|
351
+ it "should typecast #{format(value)} to #{format(expected)} for a BigDecimal property" do
352
+ property = DataMapper::Property.new(Zoo, :big_decimal, BigDecimal)
353
+ property.typecast(value).should == expected
354
+ end
355
+ end
356
+
357
+ it 'should typecast value for a DateTime property' do
358
+ property = DataMapper::Property.new(Zoo, :date_time, DateTime)
359
+ property.typecast('2000-01-01 00:00:00').should == DateTime.new(2000, 1, 1, 0, 0, 0)
360
+ end
361
+
362
+ it 'should typecast value for a Date property' do
363
+ property = DataMapper::Property.new(Zoo, :date, Date)
364
+ property.typecast('2000-01-01').should == Date.new(2000, 1, 1)
365
+ end
366
+
367
+ it 'should typecast value for a Time property' do
368
+ property = DataMapper::Property.new(Zoo, :time, Time)
369
+ property.typecast('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
370
+ end
371
+
372
+ it 'should typecast Hash for a Time property' do
373
+ property = DataMapper::Property.new(Zoo, :time, Time)
374
+ property.typecast(
375
+ :year => 2002, "month" => 1, :day => 1, "hour" => 12, :min => 0, :sec => 0
376
+ ).should == Time.local(2002, 1, 1, 12, 0, 0)
377
+ end
378
+
379
+ it 'should typecast Hash for a Date property' do
380
+ property = DataMapper::Property.new(Zoo, :date, Date)
381
+ property.typecast(:year => 2002, "month" => 1, :day => 1).should == Date.new(2002, 1, 1)
382
+ end
383
+
384
+ it 'should typecast Hash for a DateTime property' do
385
+ property = DataMapper::Property.new(Zoo, :date_time, DateTime)
386
+ property.typecast(
387
+ :year => 2002, :month => 1, :day => 1, "hour" => 12, :min => 0, "sec" => 0
388
+ ).should == DateTime.new(2002, 1, 1, 12, 0, 0)
389
+ end
390
+
391
+ it 'should use now as defaults for missing parts of a Hash to Time typecast' do
392
+ now = Time.now
393
+ property = DataMapper::Property.new(Zoo, :time, Time)
394
+ property.typecast(
395
+ :month => 1, :day => 1
396
+ ).should == Time.local(now.year, 1, 1, now.hour, now.min, now.sec)
397
+ end
398
+
399
+ it 'should use now as defaults for missing parts of a Hash to Date typecast' do
400
+ now = Time.now
401
+ property = DataMapper::Property.new(Zoo, :date, Date)
402
+ property.typecast(
403
+ :month => 1, :day => 1
404
+ ).should == Date.new(now.year, 1, 1)
405
+ end
406
+
407
+ it 'should use now as defaults for missing parts of a Hash to DateTime typecast' do
408
+ now = Time.now
409
+ property = DataMapper::Property.new(Zoo, :date_time, DateTime)
410
+ property.typecast(
411
+ :month => 1, :day => 1
412
+ ).should == DateTime.new(now.year, 1, 1, now.hour, now.min, now.sec)
413
+ end
414
+
415
+ it 'should rescue after trying to typecast an invalid Date value from a hash' do
416
+ property = DataMapper::Property.new(Zoo, :date, Date)
417
+ property.typecast(:year => 2002, :month => 2, :day => 31).should == Date.new(2002, 3, 3)
418
+ end
419
+
420
+ it 'should rescue after trying to typecast an invalid DateTime value from a hash' do
421
+ property = DataMapper::Property.new(Zoo, :date_time, DateTime)
422
+ property.typecast(
423
+ :year => 2002, :month => 2, :day => 31, :hour => 12, :min => 0, :sec => 0
424
+ ).should == DateTime.new(2002, 3, 3, 12, 0, 0)
425
+ end
426
+
427
+ it 'should typecast value for a Class property' do
428
+ property = DataMapper::Property.new(Zoo, :class, Class)
429
+ property.typecast('Zoo').should == Zoo
430
+ end
431
+ end
432
+
433
+ it 'should provide #inspect' do
434
+ DataMapper::Property.new(Zoo, :name, String).should respond_to(:inspect)
435
+ end
436
+
437
+ it "should use the Repository of its @model" do
438
+ p = DataMapper::Property.new(Zoo, :name, String)
439
+ repo = mock("repository")
440
+ Zoo.should_receive(:repository).and_return(repo)
441
+ p.repository.should == repo
442
+ end
443
+
444
+ it 'should return an abbreviated representation of the property when inspected' do
445
+ DataMapper::Property.new(Zoo, :name, String).inspect.should == '#<Property:Zoo:name>'
446
+ end
447
+ end