dm-core 0.9.2

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 (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