ghost_dm-core 1.3.0.beta

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 (254) hide show
  1. data/.autotest +29 -0
  2. data/.document +5 -0
  3. data/.gitignore +35 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +65 -0
  6. data/LICENSE +20 -0
  7. data/README.md +269 -0
  8. data/Rakefile +4 -0
  9. data/dm-core.gemspec +24 -0
  10. data/lib/dm-core.rb +292 -0
  11. data/lib/dm-core/adapters.rb +222 -0
  12. data/lib/dm-core/adapters/abstract_adapter.rb +237 -0
  13. data/lib/dm-core/adapters/in_memory_adapter.rb +113 -0
  14. data/lib/dm-core/associations/many_to_many.rb +499 -0
  15. data/lib/dm-core/associations/many_to_one.rb +290 -0
  16. data/lib/dm-core/associations/one_to_many.rb +348 -0
  17. data/lib/dm-core/associations/one_to_one.rb +86 -0
  18. data/lib/dm-core/associations/relationship.rb +663 -0
  19. data/lib/dm-core/backwards.rb +13 -0
  20. data/lib/dm-core/collection.rb +1515 -0
  21. data/lib/dm-core/core_ext/kernel.rb +23 -0
  22. data/lib/dm-core/core_ext/pathname.rb +6 -0
  23. data/lib/dm-core/core_ext/symbol.rb +10 -0
  24. data/lib/dm-core/identity_map.rb +7 -0
  25. data/lib/dm-core/model.rb +874 -0
  26. data/lib/dm-core/model/hook.rb +103 -0
  27. data/lib/dm-core/model/is.rb +32 -0
  28. data/lib/dm-core/model/property.rb +249 -0
  29. data/lib/dm-core/model/relationship.rb +378 -0
  30. data/lib/dm-core/model/scope.rb +89 -0
  31. data/lib/dm-core/property.rb +866 -0
  32. data/lib/dm-core/property/binary.rb +21 -0
  33. data/lib/dm-core/property/boolean.rb +20 -0
  34. data/lib/dm-core/property/class.rb +17 -0
  35. data/lib/dm-core/property/date.rb +10 -0
  36. data/lib/dm-core/property/date_time.rb +10 -0
  37. data/lib/dm-core/property/decimal.rb +36 -0
  38. data/lib/dm-core/property/discriminator.rb +44 -0
  39. data/lib/dm-core/property/float.rb +16 -0
  40. data/lib/dm-core/property/integer.rb +22 -0
  41. data/lib/dm-core/property/invalid_value_error.rb +22 -0
  42. data/lib/dm-core/property/lookup.rb +27 -0
  43. data/lib/dm-core/property/numeric.rb +38 -0
  44. data/lib/dm-core/property/object.rb +34 -0
  45. data/lib/dm-core/property/serial.rb +14 -0
  46. data/lib/dm-core/property/string.rb +38 -0
  47. data/lib/dm-core/property/text.rb +9 -0
  48. data/lib/dm-core/property/time.rb +10 -0
  49. data/lib/dm-core/property_set.rb +177 -0
  50. data/lib/dm-core/query.rb +1366 -0
  51. data/lib/dm-core/query/conditions/comparison.rb +911 -0
  52. data/lib/dm-core/query/conditions/operation.rb +721 -0
  53. data/lib/dm-core/query/direction.rb +36 -0
  54. data/lib/dm-core/query/operator.rb +35 -0
  55. data/lib/dm-core/query/path.rb +114 -0
  56. data/lib/dm-core/query/sort.rb +39 -0
  57. data/lib/dm-core/relationship_set.rb +72 -0
  58. data/lib/dm-core/repository.rb +226 -0
  59. data/lib/dm-core/resource.rb +1214 -0
  60. data/lib/dm-core/resource/persistence_state.rb +75 -0
  61. data/lib/dm-core/resource/persistence_state/clean.rb +40 -0
  62. data/lib/dm-core/resource/persistence_state/deleted.rb +30 -0
  63. data/lib/dm-core/resource/persistence_state/dirty.rb +96 -0
  64. data/lib/dm-core/resource/persistence_state/immutable.rb +34 -0
  65. data/lib/dm-core/resource/persistence_state/persisted.rb +29 -0
  66. data/lib/dm-core/resource/persistence_state/transient.rb +80 -0
  67. data/lib/dm-core/spec/lib/adapter_helpers.rb +64 -0
  68. data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
  69. data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
  70. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  71. data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
  72. data/lib/dm-core/spec/setup.rb +174 -0
  73. data/lib/dm-core/spec/shared/adapter_spec.rb +341 -0
  74. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  75. data/lib/dm-core/spec/shared/resource_spec.rb +1232 -0
  76. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  77. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +176 -0
  78. data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
  79. data/lib/dm-core/support/assertions.rb +8 -0
  80. data/lib/dm-core/support/chainable.rb +18 -0
  81. data/lib/dm-core/support/deprecate.rb +12 -0
  82. data/lib/dm-core/support/descendant_set.rb +89 -0
  83. data/lib/dm-core/support/equalizer.rb +48 -0
  84. data/lib/dm-core/support/ext/array.rb +22 -0
  85. data/lib/dm-core/support/ext/blank.rb +25 -0
  86. data/lib/dm-core/support/ext/hash.rb +67 -0
  87. data/lib/dm-core/support/ext/module.rb +47 -0
  88. data/lib/dm-core/support/ext/object.rb +57 -0
  89. data/lib/dm-core/support/ext/string.rb +24 -0
  90. data/lib/dm-core/support/ext/try_dup.rb +12 -0
  91. data/lib/dm-core/support/hook.rb +405 -0
  92. data/lib/dm-core/support/inflections.rb +60 -0
  93. data/lib/dm-core/support/inflector/inflections.rb +211 -0
  94. data/lib/dm-core/support/inflector/methods.rb +151 -0
  95. data/lib/dm-core/support/lazy_array.rb +451 -0
  96. data/lib/dm-core/support/local_object_space.rb +13 -0
  97. data/lib/dm-core/support/logger.rb +201 -0
  98. data/lib/dm-core/support/mash.rb +176 -0
  99. data/lib/dm-core/support/naming_conventions.rb +90 -0
  100. data/lib/dm-core/support/ordered_set.rb +380 -0
  101. data/lib/dm-core/support/subject.rb +33 -0
  102. data/lib/dm-core/support/subject_set.rb +250 -0
  103. data/lib/dm-core/version.rb +3 -0
  104. data/script/performance.rb +275 -0
  105. data/script/profile.rb +218 -0
  106. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  107. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +68 -0
  108. data/spec/public/associations/many_to_many_spec.rb +197 -0
  109. data/spec/public/associations/many_to_one_spec.rb +83 -0
  110. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  111. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  112. data/spec/public/associations/one_to_many_spec.rb +81 -0
  113. data/spec/public/associations/one_to_one_spec.rb +176 -0
  114. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  115. data/spec/public/collection_spec.rb +69 -0
  116. data/spec/public/finalize_spec.rb +76 -0
  117. data/spec/public/model/hook_spec.rb +246 -0
  118. data/spec/public/model/property_spec.rb +88 -0
  119. data/spec/public/model/relationship_spec.rb +1040 -0
  120. data/spec/public/model_spec.rb +462 -0
  121. data/spec/public/property/binary_spec.rb +41 -0
  122. data/spec/public/property/boolean_spec.rb +22 -0
  123. data/spec/public/property/class_spec.rb +28 -0
  124. data/spec/public/property/date_spec.rb +22 -0
  125. data/spec/public/property/date_time_spec.rb +22 -0
  126. data/spec/public/property/decimal_spec.rb +23 -0
  127. data/spec/public/property/discriminator_spec.rb +135 -0
  128. data/spec/public/property/float_spec.rb +22 -0
  129. data/spec/public/property/integer_spec.rb +22 -0
  130. data/spec/public/property/object_spec.rb +107 -0
  131. data/spec/public/property/serial_spec.rb +22 -0
  132. data/spec/public/property/string_spec.rb +22 -0
  133. data/spec/public/property/text_spec.rb +63 -0
  134. data/spec/public/property/time_spec.rb +22 -0
  135. data/spec/public/property_spec.rb +341 -0
  136. data/spec/public/resource_spec.rb +288 -0
  137. data/spec/public/sel_spec.rb +53 -0
  138. data/spec/public/setup_spec.rb +145 -0
  139. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  140. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  141. data/spec/public/shared/collection_shared_spec.rb +1667 -0
  142. data/spec/public/shared/finder_shared_spec.rb +1629 -0
  143. data/spec/rcov.opts +6 -0
  144. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  145. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
  146. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  147. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  148. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  149. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  150. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  151. data/spec/semipublic/associations_spec.rb +177 -0
  152. data/spec/semipublic/collection_spec.rb +110 -0
  153. data/spec/semipublic/model_spec.rb +96 -0
  154. data/spec/semipublic/property/binary_spec.rb +13 -0
  155. data/spec/semipublic/property/boolean_spec.rb +47 -0
  156. data/spec/semipublic/property/class_spec.rb +33 -0
  157. data/spec/semipublic/property/date_spec.rb +43 -0
  158. data/spec/semipublic/property/date_time_spec.rb +46 -0
  159. data/spec/semipublic/property/decimal_spec.rb +83 -0
  160. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  161. data/spec/semipublic/property/float_spec.rb +82 -0
  162. data/spec/semipublic/property/integer_spec.rb +82 -0
  163. data/spec/semipublic/property/lookup_spec.rb +29 -0
  164. data/spec/semipublic/property/serial_spec.rb +13 -0
  165. data/spec/semipublic/property/string_spec.rb +13 -0
  166. data/spec/semipublic/property/text_spec.rb +31 -0
  167. data/spec/semipublic/property/time_spec.rb +50 -0
  168. data/spec/semipublic/property_spec.rb +114 -0
  169. data/spec/semipublic/query/conditions/comparison_spec.rb +1501 -0
  170. data/spec/semipublic/query/conditions/operation_spec.rb +1294 -0
  171. data/spec/semipublic/query/path_spec.rb +471 -0
  172. data/spec/semipublic/query_spec.rb +3682 -0
  173. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  174. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  175. data/spec/semipublic/resource/state/dirty_spec.rb +162 -0
  176. data/spec/semipublic/resource/state/immutable_spec.rb +105 -0
  177. data/spec/semipublic/resource/state/transient_spec.rb +162 -0
  178. data/spec/semipublic/resource/state_spec.rb +230 -0
  179. data/spec/semipublic/resource_spec.rb +23 -0
  180. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  181. data/spec/semipublic/shared/resource_shared_spec.rb +199 -0
  182. data/spec/semipublic/shared/resource_state_shared_spec.rb +79 -0
  183. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  184. data/spec/spec.opts +5 -0
  185. data/spec/spec_helper.rb +38 -0
  186. data/spec/support/core_ext/hash.rb +10 -0
  187. data/spec/support/core_ext/inheritable_attributes.rb +46 -0
  188. data/spec/support/properties/huge_integer.rb +17 -0
  189. data/spec/unit/array_spec.rb +23 -0
  190. data/spec/unit/blank_spec.rb +73 -0
  191. data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
  192. data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
  193. data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
  194. data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
  195. data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
  196. data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
  197. data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
  198. data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
  199. data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
  200. data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
  201. data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
  202. data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
  203. data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
  204. data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
  205. data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
  206. data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
  207. data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
  208. data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
  209. data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
  210. data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
  211. data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
  212. data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
  213. data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
  214. data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
  215. data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
  216. data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
  217. data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
  218. data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
  219. data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
  220. data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
  221. data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
  222. data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
  223. data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
  224. data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
  225. data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
  226. data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
  227. data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
  228. data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
  229. data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
  230. data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
  231. data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
  232. data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
  233. data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
  234. data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
  235. data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
  236. data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
  237. data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
  238. data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
  239. data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
  240. data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
  241. data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
  242. data/spec/unit/hash_spec.rb +28 -0
  243. data/spec/unit/hook_spec.rb +1235 -0
  244. data/spec/unit/inflections_spec.rb +16 -0
  245. data/spec/unit/lazy_array_spec.rb +1949 -0
  246. data/spec/unit/mash_spec.rb +312 -0
  247. data/spec/unit/module_spec.rb +71 -0
  248. data/spec/unit/object_spec.rb +38 -0
  249. data/spec/unit/try_dup_spec.rb +46 -0
  250. data/tasks/ci.rake +1 -0
  251. data/tasks/spec.rake +38 -0
  252. data/tasks/yard.rake +9 -0
  253. data/tasks/yardstick.rake +19 -0
  254. metadata +365 -0
@@ -0,0 +1,1629 @@
1
+ share_examples_for 'Finder Interface' do
2
+ before :all do
3
+ %w[ @article_model @article @other @articles ].each do |ivar|
4
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
5
+ raise "+#{ivar}+ should not be nil in before block" unless instance_variable_get(ivar)
6
+ end
7
+ end
8
+
9
+ before :all do
10
+ @no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
11
+ defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
12
+
13
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
14
+
15
+ @many_to_many = @articles.kind_of?(DataMapper::Associations::ManyToMany::Collection)
16
+
17
+ @skip = @no_join && @many_to_many
18
+ end
19
+
20
+ before do
21
+ pending if @skip
22
+ end
23
+
24
+ it 'should be Enumerable' do
25
+ @articles.should be_kind_of(Enumerable)
26
+ end
27
+
28
+ [ :[], :slice ].each do |method|
29
+ it { @articles.should respond_to(method) }
30
+
31
+ describe "##{method}" do
32
+ before :all do
33
+ 1.upto(10) { |number| @articles.create(:content => "Article #{number}") }
34
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
35
+ end
36
+
37
+ describe 'with a positive offset' do
38
+ before :all do
39
+ unless @skip
40
+ @return = @resource = @articles.send(method, 0)
41
+ end
42
+ end
43
+
44
+ it 'should return a Resource' do
45
+ @return.should be_kind_of(DataMapper::Resource)
46
+ end
47
+
48
+ it 'should return expected Resource' do
49
+ @return.should == @copy.entries.send(method, 0)
50
+ end
51
+ end
52
+
53
+ describe 'with a positive offset and length' do
54
+ before :all do
55
+ @return = @resources = @articles.send(method, 5, 5)
56
+ end
57
+
58
+ it 'should return a Collection' do
59
+ @return.should be_kind_of(DataMapper::Collection)
60
+ end
61
+
62
+ it 'should return the expected Resource' do
63
+ @return.should == @copy.entries.send(method, 5, 5)
64
+ end
65
+
66
+ it 'should scope the Collection' do
67
+ @resources.reload.should == @copy.entries.send(method, 5, 5)
68
+ end
69
+ end
70
+
71
+ describe 'with a positive range' do
72
+ before :all do
73
+ @return = @resources = @articles.send(method, 5..10)
74
+ end
75
+
76
+ it 'should return a Collection' do
77
+ @return.should be_kind_of(DataMapper::Collection)
78
+ end
79
+
80
+ it 'should return the expected Resources' do
81
+ @return.should == @copy.entries.send(method, 5..10)
82
+ end
83
+
84
+ it 'should scope the Collection' do
85
+ @resources.reload.should == @copy.entries.send(method, 5..10)
86
+ end
87
+ end
88
+
89
+ describe 'with a negative offset' do
90
+ before :all do
91
+ unless @skip
92
+ @return = @resource = @articles.send(method, -1)
93
+ end
94
+ end
95
+
96
+ it 'should return a Resource' do
97
+ @return.should be_kind_of(DataMapper::Resource)
98
+ end
99
+
100
+ it 'should return expected Resource' do
101
+ @return.should == @copy.entries.send(method, -1)
102
+ end
103
+ end
104
+
105
+ describe 'with a negative offset and length' do
106
+ before :all do
107
+ @return = @resources = @articles.send(method, -5, 5)
108
+ end
109
+
110
+ it 'should return a Collection' do
111
+ @return.should be_kind_of(DataMapper::Collection)
112
+ end
113
+
114
+ it 'should return the expected Resources' do
115
+ @return.should == @copy.entries.send(method, -5, 5)
116
+ end
117
+
118
+ it 'should scope the Collection' do
119
+ @resources.reload.should == @copy.entries.send(method, -5, 5)
120
+ end
121
+ end
122
+
123
+ describe 'with a negative range' do
124
+ before :all do
125
+ @return = @resources = @articles.send(method, -5..-2)
126
+ end
127
+
128
+ it 'should return a Collection' do
129
+ @return.should be_kind_of(DataMapper::Collection)
130
+ end
131
+
132
+ it 'should return the expected Resources' do
133
+ @return.to_a.should == @copy.entries.send(method, -5..-2)
134
+ end
135
+
136
+ it 'should scope the Collection' do
137
+ @resources.reload.should == @copy.entries.send(method, -5..-2)
138
+ end
139
+ end
140
+
141
+ describe 'with an empty exclusive range' do
142
+ before :all do
143
+ @return = @resources = @articles.send(method, 0...0)
144
+ end
145
+
146
+ it 'should return a Collection' do
147
+ @return.should be_kind_of(DataMapper::Collection)
148
+ end
149
+
150
+ it 'should return the expected value' do
151
+ @return.to_a.should == @copy.entries.send(method, 0...0)
152
+ end
153
+
154
+ it 'should be empty' do
155
+ @return.should be_empty
156
+ end
157
+ end
158
+
159
+ describe 'with an offset not within the Collection' do
160
+ before :all do
161
+ unless @skip
162
+ @return = @articles.send(method, 99)
163
+ end
164
+ end
165
+
166
+ it 'should return nil' do
167
+ @return.should be_nil
168
+ end
169
+ end
170
+
171
+ describe 'with an offset and length not within the Collection' do
172
+ before :all do
173
+ @return = @articles.send(method, 99, 1)
174
+ end
175
+
176
+ it 'should return a Collection' do
177
+ @return.should be_kind_of(DataMapper::Collection)
178
+ end
179
+
180
+ it 'should be empty' do
181
+ @return.should be_empty
182
+ end
183
+ end
184
+
185
+ describe 'with a range not within the Collection' do
186
+ before :all do
187
+ @return = @articles.send(method, 99..100)
188
+ end
189
+
190
+ it 'should return a Collection' do
191
+ @return.should be_kind_of(DataMapper::Collection)
192
+ end
193
+
194
+ it 'should be empty' do
195
+ @return.should be_empty
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ it { @articles.should respond_to(:all) }
202
+
203
+ describe '#all' do
204
+ describe 'with no arguments' do
205
+ before :all do
206
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
207
+
208
+ @return = @collection = @articles.all
209
+ end
210
+
211
+ it 'should return a Collection' do
212
+ @return.should be_kind_of(DataMapper::Collection)
213
+ end
214
+
215
+ it 'should return a new instance' do
216
+ @return.should_not equal(@articles)
217
+ end
218
+
219
+ it 'should be expected Resources' do
220
+ @collection.should == @articles.entries
221
+ end
222
+
223
+ it 'should not have a Query the same as the original' do
224
+ @return.query.should_not equal(@articles.query)
225
+ end
226
+
227
+ it 'should have a Query equal to the original' do
228
+ @return.query.should eql(@articles.query)
229
+ end
230
+
231
+ it 'should scope the Collection' do
232
+ @collection.reload.should == @copy.entries
233
+ end
234
+ end
235
+
236
+ describe 'with a query' do
237
+ before :all do
238
+ @new = @articles.create(:content => 'New Article')
239
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
240
+
241
+ @return = @articles.all(:content => [ 'New Article' ])
242
+ end
243
+
244
+ it 'should return a Collection' do
245
+ @return.should be_kind_of(DataMapper::Collection)
246
+ end
247
+
248
+ it 'should return a new instance' do
249
+ @return.should_not equal(@articles)
250
+ end
251
+
252
+ it 'should be expected Resources' do
253
+ @return.should == [ @new ]
254
+ end
255
+
256
+ it 'should have a different query than original Collection' do
257
+ @return.query.should_not equal(@articles.query)
258
+ end
259
+
260
+ it 'should scope the Collection' do
261
+ @return.reload.should == @copy.entries.select { |resource| resource.content == 'New Article' }
262
+ end
263
+ end
264
+
265
+ describe 'with a query using raw conditions' do
266
+ before do
267
+ pending unless defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
268
+ end
269
+
270
+ before :all do
271
+ @new = @articles.create(:subtitle => 'New Article')
272
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
273
+
274
+ @return = @articles.all(:conditions => [ 'subtitle = ?', 'New Article' ])
275
+ end
276
+
277
+ it 'should return a Collection' do
278
+ @return.should be_kind_of(DataMapper::Collection)
279
+ end
280
+
281
+ it 'should return a new instance' do
282
+ @return.should_not equal(@articles)
283
+ end
284
+
285
+ it 'should be expected Resources' do
286
+ @return.should == [ @new ]
287
+ end
288
+
289
+ it 'should have a different query than original Collection' do
290
+ @return.query.should_not == @articles.query
291
+ end
292
+
293
+ it 'should scope the Collection' do
294
+ @return.reload.should == @copy.entries.select { |resource| resource.subtitle == 'New Article' }.first(1)
295
+ end
296
+ end
297
+
298
+ describe 'with a query that is out of range' do
299
+ it 'should raise an exception' do
300
+ lambda {
301
+ @articles.all(:limit => 10).all(:offset => 10)
302
+ }.should raise_error(RangeError, 'offset 10 and limit 0 are outside allowed range')
303
+ end
304
+ end
305
+
306
+ describe 'with a query using a m:1 relationship' do
307
+ describe 'with a Hash' do
308
+ before :all do
309
+ @return = @articles.all(:original => @original.attributes)
310
+ end
311
+
312
+ it 'should return a Collection' do
313
+ @return.should be_kind_of(DataMapper::Collection)
314
+ end
315
+
316
+ it 'should be expected Resources' do
317
+ @return.should == [ @article ]
318
+ end
319
+
320
+ it 'should have a valid query' do
321
+ @return.query.should be_valid
322
+ end
323
+ end
324
+
325
+ describe 'with a resource' do
326
+ before :all do
327
+ @return = @articles.all(:original => @original)
328
+ end
329
+
330
+ it 'should return a Collection' do
331
+ @return.should be_kind_of(DataMapper::Collection)
332
+ end
333
+
334
+ it 'should be expected Resources' do
335
+ @return.should == [ @article ]
336
+ end
337
+
338
+ it 'should have a valid query' do
339
+ @return.query.should be_valid
340
+ end
341
+ end
342
+
343
+ describe 'with a collection' do
344
+ before :all do
345
+ @collection = @article_model.all(
346
+ Hash[ @article_model.key.zip(@original.key) ]
347
+ )
348
+
349
+ @return = @articles.all(:original => @collection)
350
+ end
351
+
352
+ it 'should return a Collection' do
353
+ @return.should be_kind_of(DataMapper::Collection)
354
+ end
355
+
356
+ it 'should be expected Resources' do
357
+ @return.should == [ @article ]
358
+ end
359
+
360
+ it 'should have a valid query' do
361
+ @return.query.should be_valid
362
+ end
363
+
364
+ end
365
+
366
+ describe 'with an empty Array' do
367
+ before :all do
368
+ @return = @articles.all(:original => [])
369
+ end
370
+
371
+ it 'should return a Collection' do
372
+ @return.should be_kind_of(DataMapper::Collection)
373
+ end
374
+
375
+ it 'should be an empty Collection' do
376
+ @return.should be_empty
377
+ end
378
+
379
+ it 'should not have a valid query' do
380
+ @return.query.should_not be_valid
381
+ end
382
+ end
383
+
384
+ describe 'with a nil value' do
385
+ before :all do
386
+ @return = @articles.all(:original => nil)
387
+ end
388
+
389
+ it 'should return a Collection' do
390
+ @return.should be_kind_of(DataMapper::Collection)
391
+ end
392
+
393
+ if respond_to?(:model?) && model?
394
+ it 'should be expected Resources' do
395
+ @return.should == [ @original, @other ]
396
+ end
397
+ else
398
+ it 'should be an empty Collection' do
399
+ @return.should be_empty
400
+ end
401
+ end
402
+
403
+ it 'should have a valid query' do
404
+ @return.query.should be_valid
405
+ end
406
+
407
+ it 'should be equivalent to negated collection query' do
408
+ pending_if 'Update RDBMS to match ruby behavior', @do_adapter && @articles.kind_of?(DataMapper::Model) do
409
+ # NOTE: the second query will not match any articles where original_id
410
+ # is nil, while the in-memory/yaml adapters will. RDBMS will explicitly
411
+ # filter out NULL matches because we are matching on a non-NULL value,
412
+ # which is not consistent with how DM/Ruby matching behaves.
413
+ @return.should == @articles.all(:original.not => @article_model.all)
414
+ end
415
+ end
416
+ end
417
+
418
+ describe 'with a negated nil value' do
419
+ before :all do
420
+ @return = @articles.all(:original.not => nil)
421
+ end
422
+
423
+ it 'should return a Collection' do
424
+ @return.should be_kind_of(DataMapper::Collection)
425
+ end
426
+
427
+ it 'should be expected Resources' do
428
+ @return.should == [ @article ]
429
+ end
430
+
431
+ it 'should have a valid query' do
432
+ @return.query.should be_valid
433
+ end
434
+
435
+ it 'should be equivalent to collection query' do
436
+ @return.should == @articles.all(:original => @article_model.all)
437
+ end
438
+ end
439
+ end
440
+
441
+ describe 'with a query using a 1:1 relationship' do
442
+ before :all do
443
+ @new = @articles.create(:content => 'New Article', :original => @article)
444
+ end
445
+
446
+ describe 'with a Hash' do
447
+ before :all do
448
+ @return = @articles.all(:previous => @new.attributes)
449
+ end
450
+
451
+ it 'should return a Collection' do
452
+ @return.should be_kind_of(DataMapper::Collection)
453
+ end
454
+
455
+ it 'should be expected Resources' do
456
+ @return.should == [ @article ]
457
+ end
458
+
459
+ it 'should have a valid query' do
460
+ @return.query.should be_valid
461
+ end
462
+ end
463
+
464
+ describe 'with a resource' do
465
+ before :all do
466
+ @return = @articles.all(:previous => @new)
467
+ end
468
+
469
+ it 'should return a Collection' do
470
+ @return.should be_kind_of(DataMapper::Collection)
471
+ end
472
+
473
+ it 'should be expected Resources' do
474
+ @return.should == [ @article ]
475
+ end
476
+
477
+ it 'should have a valid query' do
478
+ @return.query.should be_valid
479
+ end
480
+ end
481
+
482
+ describe 'with a collection' do
483
+ before :all do
484
+ @collection = @article_model.all(
485
+ Hash[ @article_model.key.zip(@new.key) ]
486
+ )
487
+
488
+ @return = @articles.all(:previous => @collection)
489
+ end
490
+
491
+ it 'should return a Collection' do
492
+ @return.should be_kind_of(DataMapper::Collection)
493
+ end
494
+
495
+ it 'should be expected Resources' do
496
+ @return.should == [ @article ]
497
+ end
498
+
499
+ it 'should have a valid query' do
500
+ @return.query.should be_valid
501
+ end
502
+ end
503
+
504
+ describe 'with an empty Array' do
505
+ before :all do
506
+ @return = @articles.all(:previous => [])
507
+ end
508
+
509
+ it 'should return a Collection' do
510
+ @return.should be_kind_of(DataMapper::Collection)
511
+ end
512
+
513
+ it 'should be an empty Collection' do
514
+ @return.should be_empty
515
+ end
516
+
517
+ it 'should not have a valid query' do
518
+ @return.query.should_not be_valid
519
+ end
520
+ end
521
+
522
+ describe 'with a nil value' do
523
+ before :all do
524
+ @return = @articles.all(:previous => nil)
525
+ end
526
+
527
+ it 'should return a Collection' do
528
+ @return.should be_kind_of(DataMapper::Collection)
529
+ end
530
+
531
+ if respond_to?(:model?) && model?
532
+ it 'should be expected Resources' do
533
+ @return.should == [ @other, @new ]
534
+ end
535
+ else
536
+ it 'should be expected Resources' do
537
+ @return.should == [ @new ]
538
+ end
539
+ end
540
+
541
+ it 'should have a valid query' do
542
+ @return.query.should be_valid
543
+ end
544
+
545
+ it 'should be equivalent to negated collection query' do
546
+ @return.should == @articles.all(:previous.not => @article_model.all(:original.not => nil))
547
+ end
548
+ end
549
+
550
+ describe 'with a negated nil value' do
551
+ before :all do
552
+ @return = @articles.all(:previous.not => nil)
553
+ end
554
+
555
+ it 'should return a Collection' do
556
+ @return.should be_kind_of(DataMapper::Collection)
557
+ end
558
+
559
+ if respond_to?(:model?) && model?
560
+ it 'should be expected Resources' do
561
+ @return.should == [ @original, @article ]
562
+ end
563
+ else
564
+ it 'should be expected Resources' do
565
+ @return.should == [ @article ]
566
+ end
567
+ end
568
+
569
+ it 'should have a valid query' do
570
+ @return.query.should be_valid
571
+ end
572
+
573
+ it 'should be equivalent to collection query' do
574
+ @return.should == @articles.all(:previous => @article_model.all)
575
+ end
576
+ end
577
+ end
578
+
579
+ describe 'with a query using a 1:m relationship' do
580
+ before :all do
581
+ @new = @articles.create(:content => 'New Article', :original => @article)
582
+ end
583
+
584
+ describe 'with a Hash' do
585
+ before :all do
586
+ @return = @articles.all(:revisions => @new.attributes)
587
+ end
588
+
589
+ it 'should return a Collection' do
590
+ @return.should be_kind_of(DataMapper::Collection)
591
+ end
592
+
593
+ it 'should be expected Resources' do
594
+ @return.should == [ @article ]
595
+ end
596
+
597
+ it 'should have a valid query' do
598
+ @return.query.should be_valid
599
+ end
600
+ end
601
+
602
+ describe 'with a resource' do
603
+ before :all do
604
+ @return = @articles.all(:revisions => @new)
605
+ end
606
+
607
+ it 'should return a Collection' do
608
+ @return.should be_kind_of(DataMapper::Collection)
609
+ end
610
+
611
+ it 'should be expected Resources' do
612
+ @return.should == [ @article ]
613
+ end
614
+
615
+ it 'should have a valid query' do
616
+ @return.query.should be_valid
617
+ end
618
+ end
619
+
620
+ describe 'with a collection' do
621
+ before :all do
622
+ @collection = @article_model.all(
623
+ Hash[ @article_model.key.zip(@new.key) ]
624
+ )
625
+
626
+ @return = @articles.all(:revisions => @collection)
627
+ end
628
+
629
+ it 'should return a Collection' do
630
+ @return.should be_kind_of(DataMapper::Collection)
631
+ end
632
+
633
+ it 'should be expected Resources' do
634
+ @return.should == [ @article ]
635
+ end
636
+
637
+ it 'should have a valid query' do
638
+ @return.query.should be_valid
639
+ end
640
+ end
641
+
642
+ describe 'with an empty Array' do
643
+ before :all do
644
+ @return = @articles.all(:revisions => [])
645
+ end
646
+
647
+ it 'should return a Collection' do
648
+ @return.should be_kind_of(DataMapper::Collection)
649
+ end
650
+
651
+ it 'should be an empty Collection' do
652
+ @return.should be_empty
653
+ end
654
+
655
+ it 'should not have a valid query' do
656
+ @return.query.should_not be_valid
657
+ end
658
+ end
659
+
660
+ describe 'with a nil value' do
661
+ before :all do
662
+ @return = @articles.all(:revisions => nil)
663
+ end
664
+
665
+ it 'should return a Collection' do
666
+ @return.should be_kind_of(DataMapper::Collection)
667
+ end
668
+
669
+ if respond_to?(:model?) && model?
670
+ it 'should be expected Resources' do
671
+ @return.should == [ @other, @new ]
672
+ end
673
+ else
674
+ it 'should be expected Resources' do
675
+ @return.should == [ @new ]
676
+ end
677
+ end
678
+
679
+ it 'should have a valid query' do
680
+ @return.query.should be_valid
681
+ end
682
+
683
+ it 'should be equivalent to negated collection query' do
684
+ @return.should == @articles.all(:revisions.not => @article_model.all(:original.not => nil))
685
+ end
686
+ end
687
+
688
+ describe 'with a negated nil value' do
689
+ before :all do
690
+ @return = @articles.all(:revisions.not => nil)
691
+ end
692
+
693
+ it 'should return a Collection' do
694
+ @return.should be_kind_of(DataMapper::Collection)
695
+ end
696
+
697
+ if respond_to?(:model?) && model?
698
+ it 'should be expected Resources' do
699
+ @return.should == [ @original, @article ]
700
+ end
701
+ else
702
+ it 'should be expected Resources' do
703
+ @return.should == [ @article ]
704
+ end
705
+ end
706
+
707
+ it 'should have a valid query' do
708
+ @return.query.should be_valid
709
+ end
710
+
711
+ it 'should be equivalent to collection query' do
712
+ @return.should == @articles.all(:revisions => @article_model.all)
713
+ end
714
+ end
715
+ end
716
+
717
+ describe 'with a query using a m:m relationship' do
718
+ before :all do
719
+ @publication = @article.publications.create(:name => 'DataMapper Now')
720
+ end
721
+
722
+ describe 'with a Hash' do
723
+ before :all do
724
+ @return = @articles.all(:publications => @publication.attributes)
725
+ end
726
+
727
+ it 'should return a Collection' do
728
+ @return.should be_kind_of(DataMapper::Collection)
729
+ end
730
+
731
+ it 'should be expected Resources' do
732
+ pending 'TODO' do
733
+ @return.should == [ @article ]
734
+ end
735
+ end
736
+
737
+ it 'should have a valid query' do
738
+ @return.query.should be_valid
739
+ end
740
+ end
741
+
742
+ describe 'with a resource' do
743
+ before :all do
744
+ @return = @articles.all(:publications => @publication)
745
+ end
746
+
747
+ it 'should return a Collection' do
748
+ @return.should be_kind_of(DataMapper::Collection)
749
+ end
750
+
751
+ it 'should be expected Resources' do
752
+ pending 'TODO' do
753
+ @return.should == [ @article ]
754
+ end
755
+ end
756
+
757
+ it 'should have a valid query' do
758
+ @return.query.should be_valid
759
+ end
760
+ end
761
+
762
+ describe 'with a collection' do
763
+ before :all do
764
+ @collection = @publication_model.all(
765
+ Hash[ @publication_model.key.zip(@publication.key) ]
766
+ )
767
+
768
+ @return = @articles.all(:publications => @collection)
769
+ end
770
+
771
+ it 'should return a Collection' do
772
+ @return.should be_kind_of(DataMapper::Collection)
773
+ end
774
+
775
+ it 'should be expected Resources' do
776
+ pending 'TODO' do
777
+ @return.should == [ @article ]
778
+ end
779
+ end
780
+
781
+ it 'should have a valid query' do
782
+ @return.query.should be_valid
783
+ end
784
+ end
785
+
786
+ describe 'with an empty Array' do
787
+ before :all do
788
+ @return = @articles.all(:publications => [])
789
+ end
790
+
791
+ it 'should return a Collection' do
792
+ @return.should be_kind_of(DataMapper::Collection)
793
+ end
794
+
795
+ it 'should be an empty Collection' do
796
+ @return.should be_empty
797
+ end
798
+
799
+ it 'should not have a valid query' do
800
+ @return.query.should_not be_valid
801
+ end
802
+ end
803
+
804
+ describe 'with a nil value' do
805
+ before :all do
806
+ @return = @articles.all(:publications => nil)
807
+ end
808
+
809
+ it 'should return a Collection' do
810
+ @return.should be_kind_of(DataMapper::Collection)
811
+ end
812
+
813
+ it 'should be empty' do
814
+ pending 'TODO' do
815
+ @return.should be_empty
816
+ end
817
+ end
818
+
819
+ it 'should have a valid query' do
820
+ @return.query.should be_valid
821
+ end
822
+
823
+ it 'should be equivalent to negated collection query' do
824
+ @return.should == @articles.all(:publications.not => @publication_model.all)
825
+ end
826
+ end
827
+
828
+ describe 'with a negated nil value' do
829
+ before :all do
830
+ @return = @articles.all(:publications.not => nil)
831
+ end
832
+
833
+ it 'should return a Collection' do
834
+ @return.should be_kind_of(DataMapper::Collection)
835
+ end
836
+
837
+ it 'should be expected Resources' do
838
+ pending 'TODO' do
839
+ @return.should == [ @article ]
840
+ end
841
+ end
842
+
843
+ it 'should have a valid query' do
844
+ @return.query.should be_valid
845
+ end
846
+
847
+ it 'should be equivalent to collection query' do
848
+ @return.should == @articles.all(:publications => @publication_model.all)
849
+ end
850
+ end
851
+ end
852
+ end
853
+
854
+ it { @articles.should respond_to(:at) }
855
+
856
+ describe '#at' do
857
+ before :all do
858
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
859
+ @copy.to_a
860
+ end
861
+
862
+ describe 'with positive offset' do
863
+ before :all do
864
+ @return = @resource = @articles.at(0)
865
+ end
866
+
867
+ should_not_be_a_kicker
868
+
869
+ it 'should return a Resource' do
870
+ @return.should be_kind_of(DataMapper::Resource)
871
+ end
872
+
873
+ it 'should return expected Resource' do
874
+ @resource.should == @copy.entries.at(0)
875
+ end
876
+ end
877
+
878
+ describe 'with negative offset' do
879
+ before :all do
880
+ @return = @resource = @articles.at(-1)
881
+ end
882
+
883
+ should_not_be_a_kicker
884
+
885
+ it 'should return a Resource' do
886
+ @return.should be_kind_of(DataMapper::Resource)
887
+ end
888
+
889
+ it 'should return expected Resource' do
890
+ @resource.should == @copy.entries.at(-1)
891
+ end
892
+ end
893
+ end
894
+
895
+ it { @articles.should respond_to(:each) }
896
+
897
+ describe '#each' do
898
+ subject { @articles.each(&block) }
899
+
900
+ let(:yields) { [] }
901
+ let(:block) { lambda { |resource| yields << resource } }
902
+
903
+ before do
904
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
905
+ @copy.to_a
906
+ end
907
+
908
+ it { should equal(@articles) }
909
+
910
+ it { method(:subject).should change { yields.dup }.from([]).to(@copy.to_a) }
911
+ end
912
+
913
+ it { @articles.should respond_to(:fetch) }
914
+
915
+ describe '#fetch' do
916
+ subject { @articles.fetch(*args, &block) }
917
+
918
+ let(:block) { nil }
919
+
920
+ context 'with a valid index and no default' do
921
+ let(:args) { [ 0 ] }
922
+
923
+ before do
924
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
925
+ @copy.to_a
926
+ end
927
+
928
+ should_not_be_a_kicker
929
+
930
+ it { should be_kind_of(DataMapper::Resource) }
931
+
932
+ it { should == @copy.entries.fetch(*args) }
933
+ end
934
+
935
+ context 'with an invalid index and no default' do
936
+ let(:args) { [ 42 ] }
937
+
938
+ it { method(:subject).should raise_error(IndexError) }
939
+ end
940
+
941
+ context 'with an invalid index and a default' do
942
+ let(:default) { mock('Default') }
943
+ let(:args) { [ 42, default ] }
944
+
945
+ it { should equal(default) }
946
+ end
947
+
948
+ context 'with an invalid index and a block default' do
949
+ let(:yields) { [] }
950
+ let(:default) { mock('Default') }
951
+ let(:block) { lambda { |index| yields << index; default } }
952
+ let(:args) { [ 42 ] }
953
+
954
+ it { should equal(default) }
955
+
956
+ it { method(:subject).should change { yields.dup }.from([]).to([ 42 ]) }
957
+ end
958
+ end
959
+
960
+ it { @articles.should respond_to(:first) }
961
+
962
+ describe '#first' do
963
+ before :all do
964
+ 1.upto(5) { |number| @articles.create(:content => "Article #{number}") }
965
+
966
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
967
+ @copy.to_a
968
+ end
969
+
970
+ describe 'with no arguments' do
971
+ before :all do
972
+ @return = @resource = @articles.first
973
+ end
974
+
975
+ it 'should return a Resource' do
976
+ @return.should be_kind_of(DataMapper::Resource)
977
+ end
978
+
979
+ it 'should be first Resource in the Collection' do
980
+ @resource.should == @copy.entries.first
981
+ end
982
+ end
983
+
984
+ describe 'with empty query' do
985
+ before :all do
986
+ @return = @resource = @articles.first({})
987
+ end
988
+
989
+ it 'should return a Resource' do
990
+ @return.should be_kind_of(DataMapper::Resource)
991
+ end
992
+
993
+ it 'should be first Resource in the Collection' do
994
+ @resource.should == @copy.entries.first
995
+ end
996
+ end
997
+
998
+ describe 'with a query' do
999
+ before :all do
1000
+ @return = @resource = @articles.first(:content => 'Sample')
1001
+ end
1002
+
1003
+ it 'should return a Resource' do
1004
+ @return.should be_kind_of(DataMapper::Resource)
1005
+ end
1006
+
1007
+ it 'should should be the first Resource in the Collection matching the query' do
1008
+ @resource.should == @article
1009
+ end
1010
+ end
1011
+
1012
+ describe 'with a limit specified' do
1013
+ before :all do
1014
+ @return = @resources = @articles.first(1)
1015
+ end
1016
+
1017
+ it 'should return a Collection' do
1018
+ @return.should be_kind_of(DataMapper::Collection)
1019
+ end
1020
+
1021
+ it 'should be the first N Resources in the Collection' do
1022
+ @resources.should == @copy.entries.first(1)
1023
+ end
1024
+ end
1025
+
1026
+ describe 'on an empty collection' do
1027
+ before :all do
1028
+ @articles = @articles.all(:id => nil)
1029
+ @return = @articles.first
1030
+ end
1031
+
1032
+ it 'should still be an empty collection' do
1033
+ @articles.should be_empty
1034
+ end
1035
+
1036
+ it 'should return nil' do
1037
+ @return.should be_nil
1038
+ end
1039
+ end
1040
+
1041
+ describe 'with offset specified' do
1042
+ before :all do
1043
+ @return = @resource = @articles.first(:offset => 1)
1044
+ end
1045
+
1046
+ it 'should return a Resource' do
1047
+ @return.should be_kind_of(DataMapper::Resource)
1048
+ end
1049
+
1050
+ it 'should be the second Resource in the Collection' do
1051
+ @resource.should == @copy.entries[1]
1052
+ end
1053
+ end
1054
+
1055
+ describe 'with a limit and query specified' do
1056
+ before :all do
1057
+ @return = @resources = @articles.first(1, :content => 'Sample')
1058
+ end
1059
+
1060
+ it 'should return a Collection' do
1061
+ @return.should be_kind_of(DataMapper::Collection)
1062
+ end
1063
+
1064
+ it 'should be the first N Resources in the Collection matching the query' do
1065
+ @resources.should == [ @article ]
1066
+ end
1067
+ end
1068
+ end
1069
+
1070
+ it { @articles.should respond_to(:first_or_create) }
1071
+
1072
+ describe '#first_or_create' do
1073
+ describe 'with conditions that find an existing Resource' do
1074
+ before :all do
1075
+ @return = @resource = @articles.first_or_create(@article.attributes)
1076
+ end
1077
+
1078
+ it 'should return a Resource' do
1079
+ @return.should be_kind_of(DataMapper::Resource)
1080
+ end
1081
+
1082
+ it 'should be expected Resource' do
1083
+ @resource.should == @article
1084
+ end
1085
+
1086
+ it 'should be a saved Resource' do
1087
+ @resource.should be_saved
1088
+ end
1089
+ end
1090
+
1091
+ describe 'with conditions that do not find an existing Resource' do
1092
+ before :all do
1093
+ @conditions = { :content => 'Unknown Content' }
1094
+ @attributes = {}
1095
+
1096
+ @return = @resource = @articles.first_or_create(@conditions, @attributes)
1097
+ end
1098
+
1099
+ it 'should return a Resource' do
1100
+ @return.should be_kind_of(DataMapper::Resource)
1101
+ end
1102
+
1103
+ it 'should be expected Resource' do
1104
+ DataMapper::Ext::Hash.only(@resource.attributes, *@conditions.keys).should == @conditions
1105
+ end
1106
+
1107
+ it 'should be a saved Resource' do
1108
+ @resource.should be_saved
1109
+ end
1110
+ end
1111
+ end
1112
+
1113
+ it { @articles.should respond_to(:first_or_new) }
1114
+
1115
+ describe '#first_or_new' do
1116
+ describe 'with conditions that find an existing Resource' do
1117
+ before :all do
1118
+ @return = @resource = @articles.first_or_new(@article.attributes)
1119
+ end
1120
+
1121
+ it 'should return a Resource' do
1122
+ @return.should be_kind_of(DataMapper::Resource)
1123
+ end
1124
+
1125
+ it 'should be expected Resource' do
1126
+ @resource.should == @article
1127
+ end
1128
+
1129
+ it 'should be a saved Resource' do
1130
+ @resource.should be_saved
1131
+ end
1132
+ end
1133
+
1134
+ describe 'with conditions that do not find an existing Resource' do
1135
+ before :all do
1136
+ @conditions = { :content => 'Unknown Content' }
1137
+ @attributes = {}
1138
+
1139
+ @return = @resource = @articles.first_or_new(@conditions, @attributes)
1140
+ end
1141
+
1142
+ it 'should return a Resource' do
1143
+ @return.should be_kind_of(DataMapper::Resource)
1144
+ end
1145
+
1146
+ it 'should be expected Resource' do
1147
+ DataMapper::Ext::Hash.only(@resource.attributes, *@conditions.keys).should == @conditions
1148
+ end
1149
+
1150
+ it 'should not be a saved Resource' do
1151
+ @resource.should be_new
1152
+ end
1153
+ end
1154
+ end
1155
+
1156
+ [ :get, :get! ].each do |method|
1157
+ it { @articles.should respond_to(method) }
1158
+
1159
+ describe "##{method}" do
1160
+ describe 'with a key to a Resource within the Collection' do
1161
+ before :all do
1162
+ unless @skip
1163
+ @return = @resource = @articles.send(method, *@article.key)
1164
+ end
1165
+ end
1166
+
1167
+ it 'should return a Resource' do
1168
+ @return.should be_kind_of(DataMapper::Resource)
1169
+ end
1170
+
1171
+ it 'should be matching Resource in the Collection' do
1172
+ @resource.should == @article
1173
+ end
1174
+ end
1175
+
1176
+ describe 'with a key not typecast' do
1177
+ before :all do
1178
+ unless @skip
1179
+ @return = @resource = @articles.send(method, *@article.key.map { |value| value.to_s })
1180
+ end
1181
+ end
1182
+
1183
+ it 'should return a Resource' do
1184
+ @return.should be_kind_of(DataMapper::Resource)
1185
+ end
1186
+
1187
+ it 'should be matching Resource in the Collection' do
1188
+ @resource.should == @article
1189
+ end
1190
+ end
1191
+
1192
+ describe 'with a key to a Resource not within the Collection' do
1193
+ if method == :get
1194
+ it 'should return nil' do
1195
+ @articles.get(99).should be_nil
1196
+ end
1197
+ else
1198
+ it 'should raise an exception' do
1199
+ lambda {
1200
+ @articles.get!(99)
1201
+ }.should raise_error(DataMapper::ObjectNotFoundError, "Could not find #{@article_model} with key \[99\]")
1202
+ end
1203
+ end
1204
+ end
1205
+
1206
+ describe 'with a key that is nil' do
1207
+ if method == :get
1208
+ it 'should return nil' do
1209
+ @articles.get(nil).should be_nil
1210
+ end
1211
+ else
1212
+ it 'should raise an exception' do
1213
+ lambda {
1214
+ @articles.get!(nil)
1215
+ }.should raise_error(DataMapper::ObjectNotFoundError, "Could not find #{@article_model} with key [nil]")
1216
+ end
1217
+ end
1218
+ end
1219
+
1220
+ describe 'with a key that is an empty String' do
1221
+ if method == :get
1222
+ it 'should return nil' do
1223
+ @articles.get('').should be_nil
1224
+ end
1225
+ else
1226
+ it 'should raise an exception' do
1227
+ lambda {
1228
+ @articles.get!('')
1229
+ }.should raise_error(DataMapper::ObjectNotFoundError, "Could not find #{@article_model} with key [\"\"]")
1230
+ end
1231
+ end
1232
+ end
1233
+
1234
+ describe 'with a key that has incorrect number of arguments' do
1235
+ subject { @articles.send(method) }
1236
+
1237
+ it 'should raise an exception' do
1238
+ method(:subject).should raise_error(ArgumentError, 'The number of arguments for the key is invalid, expected 1 but was 0')
1239
+ end
1240
+ end
1241
+ end
1242
+ end
1243
+
1244
+ it { @articles.should respond_to(:last) }
1245
+
1246
+ describe '#last' do
1247
+ before :all do
1248
+ 1.upto(5) { |number| @articles.create(:content => "Article #{number}") }
1249
+
1250
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
1251
+ @copy.to_a
1252
+ end
1253
+
1254
+ describe 'with no arguments' do
1255
+ before :all do
1256
+ @return = @resource = @articles.last
1257
+ end
1258
+
1259
+ it 'should return a Resource' do
1260
+ @return.should be_kind_of(DataMapper::Resource)
1261
+ end
1262
+
1263
+ it 'should be last Resource in the Collection' do
1264
+ @resource.should == @copy.entries.last
1265
+ end
1266
+ end
1267
+
1268
+ describe 'with a query' do
1269
+ before :all do
1270
+ @return = @resource = @articles.last(:content => 'Sample')
1271
+ end
1272
+
1273
+ it 'should return a Resource' do
1274
+ @return.should be_kind_of(DataMapper::Resource)
1275
+ end
1276
+
1277
+ it 'should should be the last Resource in the Collection matching the query' do
1278
+ @resource.should == @article
1279
+ end
1280
+
1281
+ it 'should not update the original query order' do
1282
+ collection = @articles.all(:order => [ :title ])
1283
+ original_order = collection.query.order[0].dup
1284
+ last = collection.last(:content => 'Sample')
1285
+
1286
+ last.should == @resource
1287
+
1288
+ collection.query.order[0].should == original_order
1289
+ end
1290
+ end
1291
+
1292
+ describe 'with a limit specified' do
1293
+ before :all do
1294
+ @return = @resources = @articles.last(1)
1295
+ end
1296
+
1297
+ it 'should return a Collection' do
1298
+ @return.should be_kind_of(DataMapper::Collection)
1299
+ end
1300
+
1301
+ it 'should be the last N Resources in the Collection' do
1302
+ @resources.should == @copy.entries.last(1)
1303
+ end
1304
+ end
1305
+
1306
+ describe 'with offset specified' do
1307
+ before :all do
1308
+ @return = @resource = @articles.last(:offset => 1)
1309
+ end
1310
+
1311
+ it 'should return a Resource' do
1312
+ @return.should be_kind_of(DataMapper::Resource)
1313
+ end
1314
+
1315
+ it 'should be the second Resource in the Collection' do
1316
+ @resource.should == @copy.entries[-2]
1317
+ end
1318
+ end
1319
+
1320
+ describe 'with a limit and query specified' do
1321
+ before :all do
1322
+ @return = @resources = @articles.last(1, :content => 'Sample')
1323
+ end
1324
+
1325
+ it 'should return a Collection' do
1326
+ @return.should be_kind_of(DataMapper::Collection)
1327
+ end
1328
+
1329
+ it 'should be the last N Resources in the Collection matching the query' do
1330
+ @resources.should == [ @article ]
1331
+ end
1332
+ end
1333
+ end
1334
+
1335
+ it { @articles.should respond_to(:reverse) }
1336
+
1337
+ describe '#reverse' do
1338
+ before :all do
1339
+ @query = @articles.query
1340
+
1341
+ @new = @articles.create(:title => 'Sample Article')
1342
+
1343
+ @return = @articles.reverse
1344
+ end
1345
+
1346
+ it 'should return a Collection' do
1347
+ @return.should be_kind_of(DataMapper::Collection)
1348
+ end
1349
+
1350
+ it 'should return a Collection with reversed entries' do
1351
+ @return.should == @articles.entries.reverse
1352
+ end
1353
+
1354
+ it 'should return a Query that is the reverse of the original' do
1355
+ @return.query.should == @query.reverse
1356
+ end
1357
+ end
1358
+
1359
+ it { @articles.should respond_to(:values_at) }
1360
+
1361
+ describe '#values_at' do
1362
+ subject { @articles.values_at(*args) }
1363
+
1364
+ before :all do
1365
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
1366
+ @copy.to_a
1367
+ end
1368
+
1369
+ context 'with positive offset' do
1370
+ let(:args) { [ 0 ] }
1371
+
1372
+ should_not_be_a_kicker
1373
+
1374
+ it { should be_kind_of(Array) }
1375
+
1376
+ it { should == @copy.entries.values_at(*args) }
1377
+ end
1378
+
1379
+ describe 'with negative offset' do
1380
+ let(:args) { [ -1 ] }
1381
+
1382
+ should_not_be_a_kicker
1383
+
1384
+ it { should be_kind_of(Array) }
1385
+
1386
+ it { should == @copy.entries.values_at(*args) }
1387
+ end
1388
+ end
1389
+
1390
+ it 'should respond to a belongs_to relationship method with #method_missing' do
1391
+ pending_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class) do
1392
+ @articles.should respond_to(:original)
1393
+ end
1394
+ end
1395
+
1396
+ it 'should respond to a has n relationship method with #method_missing' do
1397
+ pending_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class) do
1398
+ @articles.should respond_to(:revisions)
1399
+ end
1400
+ end
1401
+
1402
+ it 'should respond to a has 1 relationship method with #method_missing' do
1403
+ pending_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class) do
1404
+ @articles.should respond_to(:previous)
1405
+ end
1406
+ end
1407
+
1408
+ describe '#method_missing' do
1409
+ before do
1410
+ pending 'Model#method_missing should delegate to relationships' if @articles.kind_of?(Class)
1411
+ end
1412
+
1413
+ describe 'with a belongs_to relationship method' do
1414
+ before :all do
1415
+ rescue_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class) do
1416
+ @articles.create(:content => 'Another Article', :original => @original)
1417
+
1418
+ @return = @collection = @articles.originals
1419
+ end
1420
+ end
1421
+
1422
+ should_not_be_a_kicker
1423
+
1424
+ it 'should return a Collection' do
1425
+ @return.should be_kind_of(DataMapper::Collection)
1426
+ end
1427
+
1428
+ it 'should return expected Collection' do
1429
+ @collection.should == [ @original ]
1430
+ end
1431
+
1432
+ it 'should set the association for each Resource' do
1433
+ @articles.map { |resource| resource.original }.should == [ @original, @original ]
1434
+ end
1435
+ end
1436
+
1437
+ describe 'with a has 1 relationship method' do
1438
+ before :all do
1439
+ # FIXME: create is necessary for m:m so that the intermediary
1440
+ # is created properly. This does not occur with @new.save
1441
+ @new = @articles.send(@many_to_many ? :create : :new)
1442
+
1443
+ @article.previous = @new
1444
+ @new.previous = @other
1445
+
1446
+ @article.save.should be(true)
1447
+ end
1448
+
1449
+ describe 'with no arguments' do
1450
+ before :all do
1451
+ @return = @articles.previous
1452
+ end
1453
+
1454
+ should_not_be_a_kicker
1455
+
1456
+ it 'should return a Collection' do
1457
+ @return.should be_kind_of(DataMapper::Collection)
1458
+ end
1459
+
1460
+ it 'should return expected Collection' do
1461
+ # association is sorted reverse by id
1462
+ @return.should == [ @new, @other ]
1463
+ end
1464
+
1465
+ it 'should set the association for each Resource' do
1466
+ @articles.map { |resource| resource.previous }.should == [ @new, @other ]
1467
+ end
1468
+ end
1469
+
1470
+ describe 'with arguments' do
1471
+ before :all do
1472
+ @return = @articles.previous(:fields => [ :id ])
1473
+ end
1474
+
1475
+ should_not_be_a_kicker
1476
+
1477
+ it 'should return a Collection' do
1478
+ @return.should be_kind_of(DataMapper::Collection)
1479
+ end
1480
+
1481
+ it 'should return expected Collection' do
1482
+ # association is sorted reverse by id
1483
+ @return.should == [ @new, @other ]
1484
+ end
1485
+
1486
+ { :id => true, :title => false, :content => false }.each do |attribute, expected|
1487
+ it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
1488
+ @return.each { |resource| resource.attribute_loaded?(attribute).should == expected }
1489
+ end
1490
+ end
1491
+
1492
+ it 'should set the association for each Resource' do
1493
+ @articles.map { |resource| resource.previous }.should == [ @new, @other ]
1494
+ end
1495
+ end
1496
+ end
1497
+
1498
+ describe 'with a has n relationship method' do
1499
+ before :all do
1500
+ # FIXME: create is necessary for m:m so that the intermediary
1501
+ # is created properly. This does not occur with @new.save
1502
+ @new = @articles.send(@many_to_many ? :create : :new)
1503
+
1504
+ # associate the article with children
1505
+ @article.revisions << @new
1506
+ @new.revisions << @other
1507
+
1508
+ @article.save.should be(true)
1509
+ end
1510
+
1511
+ describe 'with no arguments' do
1512
+ before :all do
1513
+ @return = @collection = @articles.revisions
1514
+ end
1515
+
1516
+ should_not_be_a_kicker
1517
+
1518
+ it 'should return a Collection' do
1519
+ @return.should be_kind_of(DataMapper::Collection)
1520
+ end
1521
+
1522
+ it 'should return expected Collection' do
1523
+ @collection.should == [ @other, @new ]
1524
+ end
1525
+
1526
+ it 'should set the association for each Resource' do
1527
+ @articles.map { |resource| resource.revisions }.should == [ [ @new ], [ @other ] ]
1528
+ end
1529
+ end
1530
+
1531
+ describe 'with arguments' do
1532
+ before :all do
1533
+ @return = @collection = @articles.revisions(:fields => [ :id ])
1534
+ end
1535
+
1536
+ should_not_be_a_kicker
1537
+
1538
+ it 'should return a Collection' do
1539
+ @return.should be_kind_of(DataMapper::Collection)
1540
+ end
1541
+
1542
+ it 'should return expected Collection' do
1543
+ @collection.should == [ @other, @new ]
1544
+ end
1545
+
1546
+ { :id => true, :title => false, :content => false }.each do |attribute, expected|
1547
+ it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
1548
+ @collection.each { |resource| resource.attribute_loaded?(attribute).should == expected }
1549
+ end
1550
+ end
1551
+
1552
+ it 'should set the association for each Resource' do
1553
+ @articles.map { |resource| resource.revisions }.should == [ [ @new ], [ @other ] ]
1554
+ end
1555
+ end
1556
+ end
1557
+
1558
+ describe 'with a has n :through relationship method' do
1559
+ before :all do
1560
+ @new = @articles.create
1561
+
1562
+ @publication1 = @article.publications.create(:name => 'Ruby Today')
1563
+ @publication2 = @new.publications.create(:name => 'Inside DataMapper')
1564
+ end
1565
+
1566
+ describe 'with no arguments' do
1567
+ before :all do
1568
+ @return = @collection = @articles.publications
1569
+ end
1570
+
1571
+ should_not_be_a_kicker
1572
+
1573
+ it 'should return a Collection' do
1574
+ @return.should be_kind_of(DataMapper::Collection)
1575
+ end
1576
+
1577
+ it 'should return expected Collection' do
1578
+ pending_if @no_join do
1579
+ @collection.should == [ @publication1, @publication2 ]
1580
+ end
1581
+ end
1582
+
1583
+ it 'should set the association for each Resource' do
1584
+ pending_if @no_join do
1585
+ @articles.map { |resource| resource.publications }.should == [ [ @publication1 ], [ @publication2 ] ]
1586
+ end
1587
+ end
1588
+ end
1589
+
1590
+ describe 'with arguments' do
1591
+ before :all do
1592
+ @return = @collection = @articles.publications(:fields => [ :id ])
1593
+ end
1594
+
1595
+ should_not_be_a_kicker
1596
+
1597
+ it 'should return a Collection' do
1598
+ @return.should be_kind_of(DataMapper::Collection)
1599
+ end
1600
+
1601
+ it 'should return expected Collection' do
1602
+ pending_if @no_join do
1603
+ @collection.should == [ @publication1, @publication2 ]
1604
+ end
1605
+ end
1606
+
1607
+ { :id => true, :name => false }.each do |attribute, expected|
1608
+ it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
1609
+ @collection.each { |resource| resource.attribute_loaded?(attribute).should == expected }
1610
+ end
1611
+ end
1612
+
1613
+ it 'should set the association for each Resource' do
1614
+ pending_if @no_join do
1615
+ @articles.map { |resource| resource.publications }.should == [ [ @publication1 ], [ @publication2 ] ]
1616
+ end
1617
+ end
1618
+ end
1619
+ end
1620
+
1621
+ describe 'with an unknown method' do
1622
+ it 'should raise an exception' do
1623
+ lambda {
1624
+ @articles.unknown
1625
+ }.should raise_error(NoMethodError)
1626
+ end
1627
+ end
1628
+ end
1629
+ end