dm-core 0.9.11 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -50
  5. data/Manifest.txt +66 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +6 -7
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/deps.rip +2 -0
  12. data/dm-core.gemspec +11 -15
  13. data/lib/dm-core.rb +105 -110
  14. data/lib/dm-core/adapters.rb +135 -16
  15. data/lib/dm-core/adapters/abstract_adapter.rb +251 -181
  16. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  17. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  18. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  19. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  20. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  21. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  22. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  23. data/lib/dm-core/associations/many_to_many.rb +372 -90
  24. data/lib/dm-core/associations/many_to_one.rb +220 -73
  25. data/lib/dm-core/associations/one_to_many.rb +319 -255
  26. data/lib/dm-core/associations/one_to_one.rb +66 -53
  27. data/lib/dm-core/associations/relationship.rb +561 -156
  28. data/lib/dm-core/collection.rb +1101 -379
  29. data/lib/dm-core/core_ext/kernel.rb +12 -0
  30. data/lib/dm-core/core_ext/symbol.rb +10 -0
  31. data/lib/dm-core/identity_map.rb +4 -34
  32. data/lib/dm-core/migrations.rb +1283 -0
  33. data/lib/dm-core/model.rb +570 -369
  34. data/lib/dm-core/model/descendant_set.rb +81 -0
  35. data/lib/dm-core/model/hook.rb +45 -0
  36. data/lib/dm-core/model/is.rb +32 -0
  37. data/lib/dm-core/model/property.rb +247 -0
  38. data/lib/dm-core/model/relationship.rb +335 -0
  39. data/lib/dm-core/model/scope.rb +90 -0
  40. data/lib/dm-core/property.rb +808 -273
  41. data/lib/dm-core/property_set.rb +141 -98
  42. data/lib/dm-core/query.rb +1037 -483
  43. data/lib/dm-core/query/conditions/comparison.rb +872 -0
  44. data/lib/dm-core/query/conditions/operation.rb +221 -0
  45. data/lib/dm-core/query/direction.rb +43 -0
  46. data/lib/dm-core/query/operator.rb +84 -0
  47. data/lib/dm-core/query/path.rb +138 -0
  48. data/lib/dm-core/query/sort.rb +45 -0
  49. data/lib/dm-core/repository.rb +210 -94
  50. data/lib/dm-core/resource.rb +641 -421
  51. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  52. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  53. data/lib/dm-core/support/chainable.rb +22 -0
  54. data/lib/dm-core/support/deprecate.rb +12 -0
  55. data/lib/dm-core/support/logger.rb +13 -0
  56. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  57. data/lib/dm-core/transaction.rb +333 -92
  58. data/lib/dm-core/type.rb +98 -60
  59. data/lib/dm-core/types/boolean.rb +1 -1
  60. data/lib/dm-core/types/discriminator.rb +34 -20
  61. data/lib/dm-core/types/object.rb +7 -4
  62. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  63. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  64. data/lib/dm-core/types/serial.rb +3 -3
  65. data/lib/dm-core/types/text.rb +3 -4
  66. data/lib/dm-core/version.rb +1 -1
  67. data/script/performance.rb +102 -109
  68. data/script/profile.rb +169 -38
  69. data/spec/lib/adapter_helpers.rb +105 -0
  70. data/spec/lib/collection_helpers.rb +18 -0
  71. data/spec/lib/counter_adapter.rb +34 -0
  72. data/spec/lib/pending_helpers.rb +27 -0
  73. data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
  74. data/spec/public/associations/many_to_many_spec.rb +193 -0
  75. data/spec/public/associations/many_to_one_spec.rb +73 -0
  76. data/spec/public/associations/one_to_many_spec.rb +77 -0
  77. data/spec/public/associations/one_to_one_spec.rb +156 -0
  78. data/spec/public/collection_spec.rb +65 -0
  79. data/spec/public/migrations_spec.rb +359 -0
  80. data/spec/public/model/relationship_spec.rb +924 -0
  81. data/spec/public/model_spec.rb +159 -0
  82. data/spec/public/property_spec.rb +829 -0
  83. data/spec/public/resource_spec.rb +71 -0
  84. data/spec/public/sel_spec.rb +44 -0
  85. data/spec/public/setup_spec.rb +145 -0
  86. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  87. data/spec/public/shared/collection_shared_spec.rb +1670 -0
  88. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  89. data/spec/public/shared/resource_shared_spec.rb +924 -0
  90. data/spec/public/shared/sel_shared_spec.rb +112 -0
  91. data/spec/public/transaction_spec.rb +129 -0
  92. data/spec/public/types/discriminator_spec.rb +130 -0
  93. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  94. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  95. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  96. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  97. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  99. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  100. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  101. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  102. data/spec/semipublic/associations_spec.rb +177 -0
  103. data/spec/semipublic/collection_spec.rb +142 -0
  104. data/spec/semipublic/property_spec.rb +61 -0
  105. data/spec/semipublic/query/conditions_spec.rb +528 -0
  106. data/spec/semipublic/query/path_spec.rb +443 -0
  107. data/spec/semipublic/query_spec.rb +2626 -0
  108. data/spec/semipublic/resource_spec.rb +47 -0
  109. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  110. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  111. data/spec/spec.opts +3 -1
  112. data/spec/spec_helper.rb +80 -57
  113. data/tasks/ci.rb +19 -31
  114. data/tasks/dm.rb +43 -48
  115. data/tasks/doc.rb +8 -11
  116. data/tasks/gemspec.rb +5 -5
  117. data/tasks/hoe.rb +15 -16
  118. data/tasks/install.rb +8 -10
  119. metadata +74 -111
  120. data/lib/dm-core/associations.rb +0 -207
  121. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  122. data/lib/dm-core/auto_migrations.rb +0 -105
  123. data/lib/dm-core/dependency_queue.rb +0 -32
  124. data/lib/dm-core/hook.rb +0 -11
  125. data/lib/dm-core/is.rb +0 -16
  126. data/lib/dm-core/logger.rb +0 -232
  127. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  128. data/lib/dm-core/migrator.rb +0 -29
  129. data/lib/dm-core/scope.rb +0 -58
  130. data/lib/dm-core/support.rb +0 -7
  131. data/lib/dm-core/support/array.rb +0 -13
  132. data/lib/dm-core/support/assertions.rb +0 -8
  133. data/lib/dm-core/support/errors.rb +0 -23
  134. data/lib/dm-core/support/kernel.rb +0 -11
  135. data/lib/dm-core/support/symbol.rb +0 -41
  136. data/lib/dm-core/type_map.rb +0 -80
  137. data/lib/dm-core/types.rb +0 -19
  138. data/script/all +0 -4
  139. data/spec/integration/association_spec.rb +0 -1382
  140. data/spec/integration/association_through_spec.rb +0 -203
  141. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  142. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  143. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  144. data/spec/integration/auto_migrations_spec.rb +0 -413
  145. data/spec/integration/collection_spec.rb +0 -1073
  146. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  147. data/spec/integration/dependency_queue_spec.rb +0 -46
  148. data/spec/integration/model_spec.rb +0 -197
  149. data/spec/integration/mysql_adapter_spec.rb +0 -85
  150. data/spec/integration/postgres_adapter_spec.rb +0 -731
  151. data/spec/integration/property_spec.rb +0 -253
  152. data/spec/integration/query_spec.rb +0 -514
  153. data/spec/integration/repository_spec.rb +0 -61
  154. data/spec/integration/resource_spec.rb +0 -513
  155. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  156. data/spec/integration/sti_spec.rb +0 -273
  157. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  158. data/spec/integration/transaction_spec.rb +0 -75
  159. data/spec/integration/type_spec.rb +0 -275
  160. data/spec/lib/logging_helper.rb +0 -18
  161. data/spec/lib/mock_adapter.rb +0 -27
  162. data/spec/lib/model_loader.rb +0 -100
  163. data/spec/lib/publicize_methods.rb +0 -28
  164. data/spec/models/content.rb +0 -16
  165. data/spec/models/vehicles.rb +0 -34
  166. data/spec/models/zoo.rb +0 -48
  167. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  168. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  169. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  170. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  171. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  172. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  173. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  174. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  175. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  176. data/spec/unit/associations/relationship_spec.rb +0 -71
  177. data/spec/unit/associations_spec.rb +0 -242
  178. data/spec/unit/auto_migrations_spec.rb +0 -111
  179. data/spec/unit/collection_spec.rb +0 -182
  180. data/spec/unit/data_mapper_spec.rb +0 -35
  181. data/spec/unit/identity_map_spec.rb +0 -126
  182. data/spec/unit/is_spec.rb +0 -80
  183. data/spec/unit/migrator_spec.rb +0 -33
  184. data/spec/unit/model_spec.rb +0 -321
  185. data/spec/unit/naming_conventions_spec.rb +0 -36
  186. data/spec/unit/property_set_spec.rb +0 -90
  187. data/spec/unit/property_spec.rb +0 -753
  188. data/spec/unit/query_spec.rb +0 -571
  189. data/spec/unit/repository_spec.rb +0 -93
  190. data/spec/unit/resource_spec.rb +0 -649
  191. data/spec/unit/scope_spec.rb +0 -142
  192. data/spec/unit/transaction_spec.rb +0 -493
  193. data/spec/unit/type_map_spec.rb +0 -114
  194. data/spec/unit/type_spec.rb +0 -119
@@ -1,36 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- describe "DataMapper::NamingConventions" do
4
- describe "Resource" do
5
- it "should coerce a string into the Underscored convention" do
6
- DataMapper::NamingConventions::Resource::Underscored.call('User').should == 'user'
7
- DataMapper::NamingConventions::Resource::Underscored.call('UserAccountSetting').should == 'user_account_setting'
8
- end
9
-
10
- it "should coerce a string into the UnderscoredAndPluralized convention" do
11
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralized.call('User').should == 'users'
12
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralized.call('UserAccountSetting').should == 'user_account_settings'
13
- end
14
-
15
- it "should coerce a string into the UnderscoredAndPluralized convention joining namespace with underscore" do
16
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralized.call('Model::User').should == 'model_users'
17
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralized.call('Model::UserAccountSetting').should == 'model_user_account_settings'
18
- end
19
-
20
- it "should coerce a string into the UnderscoredAndPluralizedWithoutModule convention" do
21
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralizedWithoutModule.call('Model::User').should == 'users'
22
- DataMapper::NamingConventions::Resource::UnderscoredAndPluralizedWithoutModule.call('Model::UserAccountSetting').should == 'user_account_settings'
23
- end
24
-
25
- it "should coerce a string into the Yaml convention" do
26
- DataMapper::NamingConventions::Resource::Yaml.call('UserSetting').should == 'user_settings.yaml'
27
- DataMapper::NamingConventions::Resource::Yaml.call('User').should == 'users.yaml'
28
- end
29
- end
30
-
31
- describe "Field" do
32
- it "should accept a property as input" do
33
- DataMapper::NamingConventions::Field::Underscored.call(Article.blog_id).should == 'blog_id'
34
- end
35
- end
36
- end
@@ -1,90 +0,0 @@
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).dup
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 "#clear should clear out set" do
39
- @properties.clear
40
- @properties.key.should == []
41
- @properties.defaults.should == []
42
- @properties.length.should == 0
43
- end
44
-
45
- it "#[] should find properties by name (Symbol or String)" do
46
- default_properties = [ :id, 'name', :width, 'height' ]
47
- @properties.each_with_index do |property,i|
48
- property.should == @properties[default_properties[i]]
49
- end
50
- end
51
-
52
- it "should provide defaults" do
53
- @properties.defaults.should have(2).entries
54
- @properties.should have(4).entries
55
- end
56
-
57
- it 'should add a property for lazy loading to the :default context if a context is not supplied' do
58
- Boat.properties(:default).lazy_context(:default).length.should == 2 # text & notes
59
- end
60
-
61
- it 'should return a list of contexts that a given field is in' do
62
- props = Boat.properties(:default)
63
- set = props.property_contexts(:a1)
64
- set.include?(:ctx_a).should == true
65
- set.include?(:ctx_c).should == true
66
- set.include?(:ctx_b).should == false
67
- end
68
-
69
- it 'should return a list of expanded fields that should be loaded with a given field' do
70
- props = Boat.properties(:default)
71
- set = props.lazy_load_context(:a2)
72
- expect = [:a1,:a2,:a3,:b1,:b2,:b3]
73
- expect.should == set.sort! {|a,b| a.to_s <=> b.to_s}
74
- end
75
-
76
- describe 'when dup\'ed' do
77
- it 'should duplicate the @entries ivar' do
78
- @properties.dup.entries.should_not equal(@properties.entries)
79
- end
80
-
81
- it 'should reinitialize @properties_for' do
82
- # force @properties_for to hold a property
83
- Icon.properties(:default)[:name].should_not be_nil
84
- @properties = Icon.properties(:default)
85
-
86
- @properties.instance_variable_get("@property_for").should_not be_empty
87
- @properties.dup.instance_variable_get("@property_for").should be_empty
88
- end
89
- end
90
- end
@@ -1,753 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- describe DataMapper::Property do
4
- before :each do
5
- Object.send(:remove_const, :Zoo) if defined?(Zoo)
6
- class ::Zoo
7
- include DataMapper::Resource
8
-
9
- property :id, DataMapper::Types::Serial
10
- end
11
-
12
- Object.send(:remove_const, :Name) if defined?(Name)
13
- class ::Name < DataMapper::Type
14
- primitive String
15
- track :hash
16
-
17
- def self.load(value, property)
18
- value.split(", ").reverse
19
- end
20
-
21
- def self.dump(value, property)
22
- value && value.reverse.join(", ")
23
- end
24
-
25
- def self.typecast(value, property)
26
- value
27
- end
28
- end
29
-
30
- Object.send(:remove_const, :Tomato) if defined?(Tomato)
31
- class ::Tomato
32
- include DataMapper::Resource
33
- end
34
- end
35
-
36
- describe '.new' do
37
- [ Float, BigDecimal ].each do |primitive|
38
- describe "with a #{primitive} primitive" do
39
- it 'should raise an ArgumentError if precision is 0' do
40
- lambda {
41
- Zoo.class_eval <<-RUBY
42
- property :test, #{primitive}, :precision => 0
43
- RUBY
44
- }.should raise_error(ArgumentError)
45
- end
46
-
47
- it "raises an ArgumentError if precision is less than 0" do
48
- lambda {
49
- Zoo.class_eval <<-RUBY
50
- property :test, #{primitive}, :precision => -1
51
- RUBY
52
- }.should raise_error(ArgumentError)
53
- end
54
-
55
- it 'should raise an ArgumentError if scale is less than 0' do
56
- lambda {
57
- Zoo.class_eval <<-RUBY
58
- property :test, #{primitive}, :scale => -1
59
- RUBY
60
- }.should raise_error(ArgumentError)
61
- end
62
-
63
- it 'should raise an ArgumentError if precision is less than scale' do
64
- lambda {
65
- Zoo.class_eval <<-RUBY
66
- property :test, #{primitive}, :precision => 1, :scale => 2
67
- RUBY
68
- }.should raise_error(ArgumentError)
69
- end
70
- end
71
- end
72
- end
73
-
74
- describe '#field' do
75
- before(:each) do
76
- Zoo.class_eval do
77
- property :location, String, :field => "City"
78
-
79
- repository(:mock) do
80
- property :location, String, :field => "MockCity"
81
- end
82
- end
83
- end
84
-
85
- it 'should accept a custom field' do
86
- Zoo.properties[:location].field.should == 'City'
87
- end
88
-
89
- # How is this supposed to work?
90
- it 'should use repository name if passed in' do
91
- pending
92
- Zoo.properties[:location].field(:mock).should == 'MockCity'
93
- end
94
- end
95
-
96
- describe '#get' do
97
- before do
98
- Zoo.class_eval do
99
- property :name, String, :default => "San Diego"
100
- property :address, String
101
- end
102
- @resource = Zoo.new
103
- end
104
-
105
- describe 'when setting the default on initial access' do
106
- it 'should set the ivar to the default' do
107
- @resource.name.should == 'San Diego'
108
- end
109
-
110
- it 'should set the original value to nil' do
111
- @resource.original_values[:name].should == nil
112
- end
113
- end
114
-
115
- it "should not reload the default if you set the property to nil" do
116
- @resource.name = nil
117
- @resource.name.should == nil
118
- end
119
- end
120
-
121
- describe '#get, when tracking via :hash' do
122
- before do
123
- Zoo.class_eval do
124
- property :name, String, :lazy => true, :track => :hash
125
- end
126
- Zoo.auto_migrate!
127
- @resource = Zoo.create(:name => "San Diego")
128
- end
129
-
130
- describe 'when setting the default on initial access' do
131
- it 'should set the ivar to the default' do
132
- @resource.name.should == "San Diego"
133
- end
134
-
135
- it 'should set the original value to nil' do
136
- @resource.name
137
- @resource.original_values[:name].should == "San Diego".hash
138
- end
139
-
140
- it "should know it's dirty if a change was made to the object" do
141
- @resource.name.upcase!
142
- @resource.should be_dirty
143
- end
144
- end
145
- end
146
-
147
- describe '#get, when tracking via :get' do
148
- before do
149
- Zoo.class_eval do
150
- property :name, String
151
- end
152
- Zoo.auto_migrate!
153
- @resource = Zoo.create(:name => "San Diego")
154
- end
155
-
156
- describe 'when setting the default on initial access' do
157
- it 'should set the ivar to the default' do
158
- @resource.name.should == "San Diego"
159
- end
160
-
161
- it 'should set the original value to "San Diego"' do
162
- @resource.name
163
- @resource.original_values[:name].should == "San Diego"
164
- end
165
- end
166
-
167
- it "should know it's dirty if a change was made to the object" do
168
- @resource.name.upcase!
169
- @resource.name
170
- @resource.should be_dirty
171
- @resource.original_values[:name].should == "San Diego"
172
- end
173
- end
174
-
175
- describe 'with Proc defaults' do
176
- it "calls the proc" do
177
- Zoo.class_eval do
178
- property :name, String, :default => proc {|r,p| "San Diego"}
179
- property :address, String
180
- end
181
-
182
- Zoo.new.name.should == "San Diego"
183
- end
184
-
185
- it "provides the resource to the proc" do
186
- Zoo.class_eval do
187
- property :name, String, :default => proc {|r,p| r.address}
188
- property :address, String
189
- end
190
-
191
- zoo = Zoo.new
192
- zoo.address = "San Diego"
193
- zoo.name.should == "San Diego"
194
- end
195
-
196
- it "provides the property to the proc" do
197
- Zoo.class_eval do
198
- property :name, String, :default => proc {|r,p| p.name.to_s}
199
- end
200
-
201
- zoo = Zoo.new
202
- zoo.name.should == "name"
203
- end
204
- end
205
-
206
-
207
- describe '#get!' do
208
- it 'should get the resource' do
209
- Zoo.class_eval do
210
- property :name, String
211
- end
212
-
213
- resource = Zoo.new(:name => "Portland Zoo")
214
- resource.name.should == "Portland Zoo"
215
- end
216
- end
217
-
218
- describe '#set' do
219
- before(:each) do
220
- Zoo.class_eval do
221
- property :name, String
222
- property :age, Integer
223
- property :description, String, :lazy => true
224
- end
225
- Zoo.auto_migrate!
226
- Zoo.create(:name => "San Diego Zoo", :age => 888,
227
- :description => "Great Zoo")
228
- @resource = Zoo.new
229
- end
230
-
231
- it 'should typecast the value' do
232
- @resource.age = "888"
233
- @resource.age.should == 888
234
- end
235
-
236
- it "should lazy load itself first" do
237
- resource = Zoo.first
238
- resource.description = "Still a Great Zoo"
239
- resource.original_values[:description].should == "Great Zoo"
240
- end
241
-
242
- it "should only set original_values once" do
243
- resource = Zoo.first
244
- resource.description = "Still a Great Zoo"
245
- resource.description = "What can I say. This is one great Zoo"
246
- resource.original_values[:description].should == "Great Zoo"
247
- end
248
- end
249
-
250
- describe '#set!' do
251
- before do
252
- Zoo.class_eval do
253
- property :name, String
254
- property :age, Integer
255
- end
256
- end
257
-
258
- it 'should set the resource' do
259
- resource = Zoo.new
260
- resource.name = "Seattle Zoo"
261
- resource.name.should == "Seattle Zoo"
262
- end
263
- end
264
-
265
- # What is this for?
266
- # ---
267
- # it "should evaluate two similar properties as equal" do
268
- # p1 = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
269
- # p2 = DataMapper::Property.new(Zoo, :name, String, { :size => 30 })
270
- # p3 = DataMapper::Property.new(Zoo, :title, String, { :size => 30 })
271
- # p1.eql?(p2).should == true
272
- # p1.hash.should == p2.hash
273
- # p1.eql?(p3).should == false
274
- # p1.hash.should_not == p3.hash
275
- # end
276
-
277
- it "should create a String property" do
278
- Zoo.class_eval do
279
- property :name, String, :size => 30
280
- end
281
-
282
- resource = Zoo.new
283
- resource.name = 100
284
- resource.name.should == "100"
285
- end
286
-
287
- it "should not have key that is lazy" do
288
- Zoo.class_eval do
289
- property :id, String, :lazy => true, :key => true
290
- property :name, String, :lazy => true
291
- end
292
- Zoo.auto_migrate!
293
-
294
- Zoo.create(:id => "100", :name => "San Diego Zoo")
295
- zoo = Zoo.first
296
-
297
- # Do we mean for attribute_loaded? to be public?
298
- zoo.attribute_loaded?(:id).should == true
299
- end
300
-
301
- it "should lazily load other non-loaded, non-lazy fields" do
302
- # This somewhat contorted setup is to successfully test that
303
- # the list of eager properties to be loaded when it's initially
304
- # missing is, in fact, repository-scoped
305
- Zoo.class_eval do
306
- property :id, DataMapper::Types::Serial
307
- property :name, String, :lazy => true
308
- property :address, String, :lazy => true
309
-
310
- repository(:default2) do
311
- property :name, String
312
- property :address, String
313
- end
314
- end
315
-
316
- repository(:default2) do
317
- Zoo.auto_migrate!
318
- Zoo.create(:name => "San Diego Zoo", :address => "San Diego")
319
- end
320
- repository(:default2) do
321
- zoo = Zoo.first(:fields => [:id])
322
-
323
- zoo.attribute_loaded?(:name).should == false
324
- zoo.attribute_loaded?(:address).should == false
325
- zoo.name
326
- zoo.attribute_loaded?(:name).should == true
327
- zoo.attribute_loaded?(:address).should == true
328
- end
329
- end
330
-
331
- it "should use a custom type Name property" do
332
- Zoo.class_eval do
333
- property :name, Name
334
- end
335
-
336
- Zoo.auto_migrate!
337
-
338
- zoo = Zoo.create(:name => %w(Zoo San\ Diego))
339
- Zoo.first.name.should == %w(Zoo San\ Diego)
340
- end
341
-
342
- it "should override type options with property options" do
343
- Zoo.class_eval do
344
- property :name, Name, :track => :get
345
- end
346
-
347
- Zoo.auto_migrate!
348
-
349
- Zoo.create(:name => %w(Awesome Person\ Dude))
350
- zoo = Zoo.first
351
- zoo.name = %w(Awesome Person\ Dude)
352
-
353
- # If we were tracking by hash, this would cause zoo to be dirty,
354
- # as its hash would not match the original. Since we've overridden
355
- # and are tracking by :get, it won't be dirty
356
- zoo.name.stub!(:hash).and_return(1)
357
- zoo.should_not be_dirty
358
- end
359
-
360
- describe "public details" do
361
- before do
362
- Zoo.class_eval do
363
- property :botanical_name, String, :nullable => true, :lazy => true
364
- property :colloquial_name, DataMapper::Types::Text, :default => "Tomato"
365
- end
366
- Zoo.auto_migrate!
367
- end
368
-
369
- it "should determine nullness" do
370
- Zoo.properties[:botanical_name].options[:nullable].should be_true
371
- end
372
-
373
- it "should determine its name" do
374
- Zoo.properties[:botanical_name].name.should == :botanical_name
375
- end
376
-
377
- # lazy? is not exposed to or used by the adapters, so it should be tested indirectly
378
- it "should determine laziness" do
379
- Zoo.create(:botanical_name => "Calystegia sepium")
380
- Zoo.first.attribute_loaded?(:botanical_name).should be_false
381
- end
382
-
383
- it "should automatically set laziness to true on text fields" do
384
- Zoo.create(:colloquial_name => "American hedge bindweed")
385
- Zoo.first.attribute_loaded?(:colloquial_name).should be_false
386
- end
387
-
388
- it "should determine whether it is a key" do
389
- zoo = Zoo.create(:botanical_name => "Calystegia sepium")
390
- id = zoo.id
391
- Zoo.first.id.should == id
392
- end
393
-
394
- it "should determine whether it is serial" do
395
- zoo = Zoo.create(:botanical_name => "Calystegia sepium")
396
- zoo.id.should_not be_nil
397
- end
398
-
399
- it "should determine a default value" do
400
- zoo = Zoo.new
401
- zoo.colloquial_name.should == "Tomato"
402
- end
403
- end
404
-
405
- describe "reader and writer visibility" do
406
- # parameter passed to Property.new # reader | writer visibility
407
- {
408
- {} => [:public, :public],
409
- { :accessor => :public } => [:public, :public],
410
- { :accessor => :protected } => [:protected, :protected],
411
- { :accessor => :private } => [:private, :private],
412
- { :reader => :public } => [:public, :public],
413
- { :reader => :protected } => [:protected, :public],
414
- { :reader => :private } => [:private, :public],
415
- { :writer => :public } => [:public, :public],
416
- { :writer => :protected } => [:public, :protected],
417
- { :writer => :private } => [:public, :private],
418
- { :reader => :public, :writer => :public } => [:public, :public],
419
- { :reader => :public, :writer => :protected } => [:public, :protected],
420
- { :reader => :public, :writer => :private } => [:public, :private],
421
- { :reader => :protected, :writer => :public } => [:protected, :public],
422
- { :reader => :protected, :writer => :protected } => [:protected, :protected],
423
- { :reader => :protected, :writer => :private } => [:protected, :private],
424
- { :reader => :private, :writer => :public } => [:private, :public],
425
- { :reader => :private, :writer => :protected } => [:private, :protected],
426
- { :reader => :private, :writer => :private } => [:private, :private],
427
- }.each do |input, output|
428
- it "#{input.inspect} should make reader #{output[0]} and writer #{output[1]}" do
429
- Tomato.class_eval <<-RUBY
430
- property :botanical_name, String, #{input.inspect}
431
- RUBY
432
- Tomato.send("#{output[0]}_instance_methods").map { |m| m.to_s }.should include("botanical_name")
433
- Tomato.send("#{output[1]}_instance_methods").map { |m| m.to_s }.should include("botanical_name=")
434
- end
435
- end
436
-
437
- [
438
- { :accessor => :junk },
439
- { :reader => :junk },
440
- { :writer => :junk },
441
- { :reader => :public, :writer => :junk },
442
- { :reader => :protected, :writer => :junk },
443
- { :reader => :private, :writer => :junk },
444
- { :reader => :junk, :writer => :public },
445
- { :reader => :junk, :writer => :protected },
446
- { :reader => :junk, :writer => :private },
447
- { :reader => :junk, :writer => :junk },
448
- { :reader => :junk, :writer => :junk },
449
- { :reader => :junk, :writer => :junk },
450
- ].each do |input|
451
- it "#{input.inspect} should raise ArgumentError" do
452
- lambda {
453
- Tomato.class_eval <<-RUBY
454
- property :family, String, #{input.inspect}
455
- RUBY
456
- }.should raise_error(ArgumentError)
457
- end
458
- end
459
- end
460
-
461
- # This is handled by get!
462
- # ---
463
- # it "should return an instance variable name" do
464
- # DataMapper::Property.new(Tomato, :flavor, String, {}).instance_variable_name.should == '@flavor'
465
- # DataMapper::Property.new(Tomato, :ripe, TrueClass, {}).instance_variable_name.should == '@ripe' #not @ripe?
466
- # end
467
-
468
- it "should append ? to TrueClass property reader methods" do
469
- class ::Potato
470
- include DataMapper::Resource
471
- property :id, Integer, :key => true
472
- property :fresh, TrueClass
473
- property :public, TrueClass
474
- end
475
-
476
- Potato.new(:fresh => true).should be_fresh
477
- end
478
-
479
- it "should move unknown options into Property#extra_options" do
480
- Tomato.class_eval do
481
- property :botanical_name, String, :foo => :bar
482
- end
483
- Tomato.properties[:botanical_name].extra_options.should == {:foo => :bar}
484
- end
485
-
486
- it 'should provide #custom?' do
487
- Zoo.class_eval do
488
- property :name, Name, :size => 50
489
- property :state, String, :size => 2
490
- end
491
- Zoo.properties[:name].should be_custom
492
- Zoo.properties[:state].should_not be_custom
493
- end
494
-
495
- it "should set the field to the correct field_naming_convention" do
496
- Zoo.class_eval { property :species, String }
497
- Tomato.class_eval { property :genetic_history, DataMapper::Types::Text }
498
-
499
- Zoo.properties[:species].field.should == "species"
500
- Tomato.properties[:genetic_history].field.should == "genetic_history"
501
- end
502
-
503
- it "should provide the primitive mapping" do
504
- Zoo.class_eval do
505
- property :poverty, String
506
- property :fortune, DataMapper::Types::Text
507
- end
508
-
509
- Zoo.properties[:poverty].primitive.should == String
510
- Zoo.properties[:fortune].primitive.should == String
511
- end
512
-
513
- it "should make it possible to define an integer size" do
514
- Zoo.class_eval { property :cleanliness, String, :size => 100 }
515
- Zoo.properties[:cleanliness].size.should == 100
516
- end
517
-
518
- it "should make it possible to define an integer length (which defines size)" do
519
- Zoo.class_eval { property :cleanliness, String, :length => 100 }
520
- Zoo.properties[:cleanliness].size.should == 100
521
- end
522
-
523
- it "should make it possible to define a range size" do
524
- Zoo.class_eval { property :cleanliness, String, :size => 0..100 }
525
- Zoo.properties[:cleanliness].size.should == 100
526
- end
527
-
528
- it "should make it possible to define a range length (which defines size)" do
529
- Zoo.class_eval { property :cleanliness, String, :length => 0..100 }
530
- Zoo.properties[:cleanliness].size.should == 100
531
- end
532
-
533
- describe '#typecast' do
534
- def self.format(value)
535
- case value
536
- when BigDecimal then "BigDecimal(#{value.to_s('F').inspect})"
537
- when Float, Integer, String then "#{value.class}(#{value.inspect})"
538
- else value.inspect
539
- end
540
- end
541
-
542
- it 'should pass through the value if it is the same type when typecasting' do
543
- Zoo.class_eval do
544
- property :name, String
545
- end
546
- zoo = Zoo.new
547
- value = "San Diego"
548
- def value.to_s() "San Francisco" end
549
- zoo.name = value
550
- zoo.name.should == "San Diego"
551
- end
552
-
553
- it 'should pass through the value nil when typecasting' do
554
- Zoo.class_eval do
555
- property :name, String
556
- end
557
-
558
- zoo = Zoo.new
559
- zoo.name = nil
560
- zoo.name.should == nil
561
- end
562
-
563
- it 'should pass through the value for an Object property' do
564
- value = Object.new
565
- Zoo.class_eval do
566
- property :object, Object
567
- end
568
-
569
- zoo = Zoo.new
570
- zoo.object = value
571
- zoo.object.object_id.should == value.object_id
572
- end
573
-
574
- [ true, 'true', 'TRUE', 1, '1', 't', 'T' ].each do |value|
575
- it "should typecast #{value.inspect} to true for a TrueClass property" do
576
- Zoo.class_eval do
577
- property :boolean, TrueClass
578
- end
579
-
580
- zoo = Zoo.new
581
- zoo.boolean = value
582
- zoo.boolean.should == true
583
- end
584
- end
585
-
586
- [ false, 'false', 'FALSE', 0, '0', 'f', 'F' ].each do |value|
587
- it "should typecast #{value.inspect} to false for a Boolean property" do
588
- Zoo.class_eval do
589
- property :boolean, TrueClass
590
- end
591
-
592
- zoo = Zoo.new
593
- zoo.boolean = value
594
- zoo.boolean.should == false
595
- end
596
- end
597
-
598
- it 'should typecast nil to nil for a Boolean property' do
599
- Zoo.class_eval do
600
- property :boolean, TrueClass
601
- end
602
-
603
- zoo = Zoo.new
604
- zoo.boolean = nil
605
- zoo.boolean.should == nil
606
- end
607
-
608
- it 'should typecast "0" to "0" for a String property' do
609
- Zoo.class_eval do
610
- property :string, String
611
- end
612
-
613
- zoo = Zoo.new
614
- zoo.string = "0"
615
- zoo.string.should == "0"
616
- end
617
-
618
- { '0' => 0.0, '0.0' => 0.0, 0 => 0.0, 0.0 => 0.0, BigDecimal('0.0') => 0.0 }.each do |value,expected|
619
- it "should typecast #{format(value)} to #{format(expected)} for a Float property" do
620
- Zoo.class_eval do
621
- property :float, Float
622
- end
623
-
624
- zoo = Zoo.new
625
- zoo.float = value
626
- zoo.float.should == expected
627
- end
628
- end
629
-
630
- { '-8' => -8, '-8.0' => -8, -8 => -8, -8.0 => -8, BigDecimal('8.0') => 8,
631
- '0' => 0, '0.0' => 0, 0 => 0, 0.0 => 0, BigDecimal('0.0') => 0,
632
- '5' => 5, '5.0' => 5, 5 => 5, 5.0 => 5, BigDecimal('5.0') => 5,
633
- 'none' => nil, 'almost 5' => nil, '-3 change' => -3, '9 items' => 9}.each do |value,expected|
634
- it "should typecast #{format(value)} to #{format(expected)} for an Integer property" do
635
- Zoo.class_eval do
636
- property :int, Integer
637
- end
638
-
639
- zoo = Zoo.new
640
- zoo.int = value
641
- zoo.int.should == expected
642
- end
643
- end
644
-
645
- { '0' => BigDecimal('0'), '0.0' => BigDecimal('0.0'), 0.0 => BigDecimal('0.0'), BigDecimal('0.0') => BigDecimal('0.0') }.each do |value,expected|
646
- it "should typecast #{format(value)} to #{format(expected)} for a BigDecimal property" do
647
- Zoo.class_eval do
648
- property :big_decimal, BigDecimal
649
- end
650
-
651
- zoo = Zoo.new
652
- zoo.big_decimal = value
653
- zoo.big_decimal.should == expected
654
- end
655
- end
656
-
657
- it 'should typecast value for a DateTime property' do
658
- Zoo.class_eval { property :date_time, DateTime }
659
- zoo = Zoo.new
660
- zoo.date_time = '2000-01-01 00:00:00'
661
- zoo.date_time.should == DateTime.new(2000, 1, 1, 0, 0, 0)
662
- end
663
-
664
- it 'should typecast value for a Date property' do
665
- Zoo.class_eval { property :date, Date }
666
- zoo = Zoo.new
667
- zoo.date = '2000-01-01'
668
- zoo.date.should == Date.new(2000, 1, 1)
669
- end
670
-
671
- it 'should typecast value for a Time property' do
672
- Zoo.class_eval { property :time, Time }
673
- zoo = Zoo.new
674
- zoo.time = '2000-01-01 01:01:01.123456'
675
- zoo.time.should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
676
- end
677
-
678
- it 'should typecast Hash for a Time property' do
679
- Zoo.class_eval { property :time, Time }
680
- zoo = Zoo.new
681
- zoo.time = {:year => 2002, "month" => 1, :day => 1, "hour" => 12, :min => 0, :sec => 0}
682
- zoo.time.should == Time.local(2002, 1, 1, 12, 0, 0)
683
- end
684
-
685
- it 'should typecast Hash for a Date property' do
686
- Zoo.class_eval { property :date, Date }
687
- zoo = Zoo.new
688
- zoo.date = {:year => 2002, "month" => 1, :day => 1}
689
- zoo.date.should == Date.new(2002, 1, 1)
690
- end
691
-
692
- it 'should typecast Hash for a DateTime property' do
693
- Zoo.class_eval { property :date_time, DateTime }
694
- zoo = Zoo.new
695
- zoo.date_time = {:year => 2002, :month => 1, :day => 1, "hour" => 12, :min => 0, "sec" => 0}
696
- zoo.date_time.should == DateTime.new(2002, 1, 1, 12, 0, 0)
697
- end
698
-
699
- it 'should use now as defaults for missing parts of a Hash to Time typecast' do
700
- now = Time.now
701
- Zoo.class_eval { property :time, Time }
702
- zoo = Zoo.new
703
- zoo.time = {:month => 1, :day => 1}
704
- zoo.time.should == Time.local(now.year, 1, 1, now.hour, now.min, now.sec)
705
- end
706
-
707
- it 'should use now as defaults for missing parts of a Hash to Date typecast' do
708
- now = Time.now
709
- Zoo.class_eval { property :date, Date }
710
- zoo = Zoo.new
711
- zoo.date = {:month => 1, :day => 1}
712
- zoo.date.should == Date.new(now.year, 1, 1)
713
- end
714
-
715
- it 'should use now as defaults for missing parts of a Hash to DateTime typecast' do
716
- now = Time.now
717
- Zoo.class_eval { property :date_time, DateTime }
718
- zoo = Zoo.new
719
- zoo.date_time = {:month => 1, :day => 1}
720
- zoo.date_time.should == DateTime.new(now.year, 1, 1, now.hour, now.min, now.sec)
721
- end
722
-
723
- it 'should rescue after trying to typecast an invalid Date value from a hash' do
724
- now = Time.now
725
- Zoo.class_eval { property :date, Date }
726
- zoo = Zoo.new
727
- zoo.date = {:year => 2002, :month => 2, :day => 31}
728
- zoo.date.should == Date.new(2002, 3, 3)
729
- end
730
-
731
- it 'should rescue after trying to typecast an invalid DateTime value from a hash' do
732
- now = Time.now
733
- Zoo.class_eval { property :date_time, DateTime }
734
- zoo = Zoo.new
735
- zoo.date_time = {
736
- :year => 2002, :month => 2, :day => 31, :hour => 12, :min => 0, :sec => 0
737
- }
738
- zoo.date_time.should == DateTime.new(2002, 3, 3, 12, 0, 0)
739
- end
740
-
741
- it 'should typecast value for a Class property' do
742
- Zoo.class_eval { property :klass, Class }
743
- zoo = Zoo.new
744
- zoo.klass = "Zoo"
745
- zoo.klass.should == Zoo
746
- end
747
- end
748
-
749
- it 'should return an abbreviated representation of the property when inspected' do
750
- Zoo.class_eval { property :name, String }
751
- Zoo.properties[:name].inspect.should == '#<Property:Zoo:name>'
752
- end
753
- end