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