ardm 0.0.1 → 0.1.0

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 (93) hide show
  1. checksums.yaml +5 -13
  2. data/Gemfile +1 -2
  3. data/LICENSE +2 -2
  4. data/README.md +72 -16
  5. data/ardm.gemspec +1 -0
  6. data/lib/ardm.rb +2 -1
  7. data/lib/ardm/active_record.rb +8 -1
  8. data/lib/ardm/active_record/associations.rb +33 -4
  9. data/lib/ardm/active_record/base.rb +2 -0
  10. data/lib/ardm/active_record/collection.rb +5 -0
  11. data/lib/ardm/active_record/data_mapper_constant.rb +1 -0
  12. data/lib/ardm/active_record/data_mapper_constant_proxy.rb +24 -0
  13. data/lib/ardm/active_record/finalize.rb +18 -0
  14. data/lib/ardm/active_record/predicate_builder/array_handler.rb +10 -16
  15. data/lib/ardm/active_record/predicate_builder/rails3.rb +42 -15
  16. data/lib/ardm/active_record/predicate_builder/rails4.rb +39 -13
  17. data/lib/ardm/active_record/property.rb +24 -12
  18. data/lib/ardm/active_record/query.rb +9 -18
  19. data/lib/ardm/active_record/record.rb +54 -11
  20. data/lib/ardm/active_record/relation.rb +36 -6
  21. data/lib/ardm/active_record/repository.rb +6 -2
  22. data/lib/ardm/data_mapper.rb +2 -0
  23. data/lib/ardm/data_mapper/record.rb +3 -9
  24. data/lib/ardm/version.rb +1 -1
  25. data/spec/ardm/datamapper_constants_spec.rb +31 -0
  26. data/spec/fixtures/article.rb +2 -0
  27. data/spec/integration/api_key_spec.rb +3 -3
  28. data/spec/integration/bcrypt_hash_spec.rb +7 -7
  29. data/spec/integration/comma_separated_list_spec.rb +11 -11
  30. data/spec/integration/dirty_minder_spec.rb +23 -39
  31. data/spec/integration/enum_spec.rb +11 -11
  32. data/spec/integration/epoch_time_spec.rb +6 -6
  33. data/spec/integration/file_path_spec.rb +23 -23
  34. data/spec/integration/flag_spec.rb +11 -13
  35. data/spec/integration/ip_address_spec.rb +15 -15
  36. data/spec/integration/json_spec.rb +7 -7
  37. data/spec/integration/slug_spec.rb +6 -6
  38. data/spec/integration/uri_spec.rb +11 -11
  39. data/spec/integration/uuid_spec.rb +16 -16
  40. data/spec/integration/yaml_spec.rb +8 -8
  41. data/spec/public/model_spec.rb +193 -0
  42. data/spec/public/property/binary_spec.rb +4 -4
  43. data/spec/public/property/boolean_spec.rb +3 -3
  44. data/spec/public/property/class_spec.rb +2 -2
  45. data/spec/public/property/date_spec.rb +2 -2
  46. data/spec/public/property/date_time_spec.rb +2 -2
  47. data/spec/public/property/decimal_spec.rb +2 -2
  48. data/spec/public/property/discriminator_spec.rb +21 -20
  49. data/spec/public/property/float_spec.rb +2 -2
  50. data/spec/public/property/integer_spec.rb +2 -2
  51. data/spec/public/property/object_spec.rb +14 -13
  52. data/spec/public/property/serial_spec.rb +2 -2
  53. data/spec/public/property/string_spec.rb +2 -2
  54. data/spec/public/property/text_spec.rb +2 -2
  55. data/spec/public/property/time_spec.rb +2 -2
  56. data/spec/public/property_spec.rb +44 -48
  57. data/spec/public/resource_spec.rb +278 -0
  58. data/spec/schema.rb +33 -4
  59. data/spec/semipublic/property/boolean_spec.rb +5 -5
  60. data/spec/semipublic/property/class_spec.rb +3 -3
  61. data/spec/semipublic/property/date_spec.rb +8 -8
  62. data/spec/semipublic/property/date_time_spec.rb +9 -9
  63. data/spec/semipublic/property/decimal_spec.rb +16 -16
  64. data/spec/semipublic/property/float_spec.rb +16 -16
  65. data/spec/semipublic/property/integer_spec.rb +16 -16
  66. data/spec/semipublic/property/lookup_spec.rb +4 -4
  67. data/spec/semipublic/property/text_spec.rb +2 -2
  68. data/spec/semipublic/property/time_spec.rb +10 -10
  69. data/spec/semipublic/property_spec.rb +4 -4
  70. data/spec/shared/finder_shared_spec.rb +1151 -0
  71. data/spec/shared/flags_shared_spec.rb +6 -6
  72. data/spec/shared/identity_function_group.rb +1 -1
  73. data/spec/shared/public_property_spec.rb +26 -25
  74. data/spec/shared/resource_spec.rb +1218 -0
  75. data/spec/shared/semipublic_property_spec.rb +23 -22
  76. data/spec/spec_helper.rb +17 -0
  77. data/spec/unit/bcrypt_hash_spec.rb +15 -15
  78. data/spec/unit/csv_spec.rb +11 -11
  79. data/spec/unit/dirty_minder_spec.rb +3 -5
  80. data/spec/unit/enum_spec.rb +17 -17
  81. data/spec/unit/epoch_time_spec.rb +8 -8
  82. data/spec/unit/file_path_spec.rb +9 -9
  83. data/spec/unit/flag_spec.rb +9 -9
  84. data/spec/unit/ip_address_spec.rb +9 -9
  85. data/spec/unit/json_spec.rb +11 -11
  86. data/spec/unit/paranoid_boolean_spec.rb +19 -17
  87. data/spec/unit/paranoid_datetime_spec.rb +21 -19
  88. data/spec/unit/regexp_spec.rb +4 -4
  89. data/spec/unit/uri_spec.rb +8 -8
  90. data/spec/unit/yaml_spec.rb +9 -9
  91. metadata +35 -27
  92. data/lib/ardm/active_record/not_found.rb +0 -7
  93. data/lib/ardm/data_mapper/not_found.rb +0 -5
@@ -12,16 +12,16 @@ describe Ardm::Property::Lookup do
12
12
  end
13
13
 
14
14
  it 'should provide access to Property classes' do
15
- @klass::Serial.should == Ardm::Property::Serial
15
+ expect(@klass::Serial).to eq(Ardm::Property::Serial)
16
16
  end
17
17
 
18
18
  it 'should provide access to Property classes from outside of the Property namespace' do
19
- @klass::OtherProperty.should eq(LookupFoo::OtherProperty)
19
+ expect(@klass::OtherProperty).to eq(LookupFoo::OtherProperty)
20
20
  end
21
21
 
22
22
  it 'should not provide access to unknown Property classes' do
23
- lambda {
23
+ expect {
24
24
  @klass::Bla
25
- }.should raise_error(NameError)
25
+ }.to raise_error(NameError)
26
26
  end
27
27
  end
@@ -23,8 +23,8 @@ describe Ardm::Property::Text do
23
23
 
24
24
  it 'should delegate to #type.load' do
25
25
  return_value = 'return value'
26
- property.should_receive(:load).with(@value).and_return(return_value)
27
- subject.should == return_value
26
+ expect(property).to receive(:load).with(@value).and_return(return_value)
27
+ expect(subject).to eq(return_value)
28
28
  end
29
29
  end
30
30
  end
@@ -24,26 +24,26 @@ describe Ardm::Property::Time do
24
24
  :sec => '0'
25
25
  )
26
26
 
27
- result.should be_kind_of(Time)
28
- result.year.should eql(2006)
29
- result.month.should eql(11)
30
- result.day.should eql(23)
31
- result.hour.should eql(12)
32
- result.min.should eql(0)
33
- result.sec.should eql(0)
27
+ expect(result).to be_kind_of(Time)
28
+ expect(result.year).to eql(2006)
29
+ expect(result.month).to eql(11)
30
+ expect(result.day).to eql(23)
31
+ expect(result.hour).to eql(12)
32
+ expect(result.min).to eql(0)
33
+ expect(result.sec).to eql(0)
34
34
  end
35
35
  end
36
36
 
37
37
  describe 'and value is a string' do
38
38
  it 'parses the string' do
39
39
  result = property.typecast('22:24')
40
- result.hour.should eql(22)
41
- result.min.should eql(24)
40
+ expect(result.hour).to eql(22)
41
+ expect(result.min).to eql(24)
42
42
  end
43
43
  end
44
44
 
45
45
  it 'does not typecast non-time values' do
46
- property.typecast('not-time').should eql('not-time')
46
+ expect(property.typecast('not-time')).to eql('not-time')
47
47
  end
48
48
  end
49
49
  end
@@ -7,7 +7,7 @@ describe Ardm::Property do
7
7
  describe "with #{type}" do
8
8
  subject { Ardm::Property.find_class(type) }
9
9
 
10
- it { subject.should be(Ardm::Property.const_get(type)) }
10
+ it { expect(subject).to be(Ardm::Property.const_get(type)) }
11
11
  end
12
12
  end
13
13
  end
@@ -17,7 +17,7 @@ describe Ardm::Property do
17
17
  describe "with #{type}" do
18
18
  subject { Ardm::Property.determine_class(type) }
19
19
 
20
- it { subject.should be(Ardm::Property.const_get(type.name)) }
20
+ it { expect(subject).to be(Ardm::Property.const_get(type.name)) }
21
21
  end
22
22
  end
23
23
 
@@ -37,13 +37,13 @@ describe Ardm::Property do
37
37
  describe "with ::Foo::Property::Hash" do
38
38
  subject { Ardm::Property.determine_class(Hash) }
39
39
 
40
- it { subject.should be(::CustomProps::Property::Hash) }
40
+ it { expect(subject).to be(::CustomProps::Property::Hash) }
41
41
  end
42
42
 
43
43
  describe "with ::Foo::Property::Other" do
44
44
  subject { Ardm::Property.determine_class(::CustomProps::Property::Other) }
45
45
 
46
- it { subject.should be(::CustomProps::Property::Other) }
46
+ it { expect(subject).to be(::CustomProps::Property::Other) }
47
47
  end
48
48
 
49
49
  end
@@ -0,0 +1,1151 @@
1
+ shared_examples 'Finder Interface' do
2
+ before 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 do
10
+ @no_join = defined?(Ardm::Adapters::InMemoryAdapter) && @adapter.kind_of?(Ardm::Adapters::InMemoryAdapter) ||
11
+ defined?(Ardm::Adapters::YamlAdapter) && @adapter.kind_of?(Ardm::Adapters::YamlAdapter)
12
+
13
+ @do_adapter = defined?(Ardm::Adapters::DataObjectsAdapter) && @adapter.kind_of?(Ardm::Adapters::DataObjectsAdapter)
14
+
15
+ #@many_to_many = @articles.kind_of?(Ardm::Associations::ManyToMany::Collection)
16
+
17
+ @skip = @no_join && @many_to_many
18
+ end
19
+
20
+ before do
21
+ skip if @skip
22
+ end
23
+
24
+ it 'should be 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 do
33
+ 1.upto(10) { |number| @articles.create(:body => "Article #{number}") }
34
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
35
+ end
36
+
37
+ describe 'with a positive offset' do
38
+ before do
39
+ unless @skip
40
+ @return = @resource = @articles.send(method, 0)
41
+ end
42
+ end
43
+
44
+ it 'should return a Resource' do
45
+ expect(@return).to be_kind_of(Ardm::Record)
46
+ end
47
+
48
+ it 'should return 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 do
55
+ @return = @resources = @articles.send(method, 5, 5)
56
+ end
57
+
58
+ it 'should return a Collection' do
59
+ expect(@return).to be_kind_of(Ardm::Collection)
60
+ end
61
+
62
+ it 'should return the expected Resource' do
63
+ expect(@return).to eq(@copy.entries.send(method, 5, 5))
64
+ end
65
+
66
+ it 'should scope 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 do
73
+ @return = @resources = @articles.send(method, 5..10)
74
+ end
75
+
76
+ it 'should return a Collection' do
77
+ expect(@return).to be_kind_of(Ardm::Collection)
78
+ end
79
+
80
+ it 'should return the expected Resources' do
81
+ expect(@return).to eq(@copy.entries.send(method, 5..10))
82
+ end
83
+
84
+ it 'should scope 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 do
91
+ unless @skip
92
+ @return = @resource = @articles.send(method, -1)
93
+ end
94
+ end
95
+
96
+ it 'should return a Resource' do
97
+ expect(@return).to be_kind_of(Ardm::Record)
98
+ end
99
+
100
+ it 'should return 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 do
107
+ @return = @resources = @articles.send(method, -5, 5)
108
+ end
109
+
110
+ it 'should return a Collection' do
111
+ expect(@return).to be_kind_of(Ardm::Collection)
112
+ end
113
+
114
+ it 'should return the expected Resources' do
115
+ expect(@return).to eq(@copy.entries.send(method, -5, 5))
116
+ end
117
+
118
+ it 'should scope 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 do
125
+ @return = @resources = @articles.send(method, -5..-2)
126
+ end
127
+
128
+ it 'should return a Collection' do
129
+ expect(@return).to be_kind_of(Ardm::Collection)
130
+ end
131
+
132
+ it 'should return the expected Resources' do
133
+ expect(@return.to_a).to eq(@copy.entries.send(method, -5..-2))
134
+ end
135
+
136
+ it 'should scope 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 do
143
+ @return = @resources = @articles.send(method, 0...0)
144
+ end
145
+
146
+ it 'should return a Collection' do
147
+ expect(@return).to be_kind_of(Ardm::Collection)
148
+ end
149
+
150
+ it 'should return the expected value' do
151
+ expect(@return.to_a).to eq(@copy.entries.send(method, 0...0))
152
+ end
153
+
154
+ it 'should be 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 do
161
+ unless @skip
162
+ @return = @articles.send(method, 99)
163
+ end
164
+ end
165
+
166
+ it 'should return 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 do
173
+ @return = @articles.send(method, 99, 1)
174
+ end
175
+
176
+ it 'should return a Collection' do
177
+ expect(@return).to be_kind_of(Ardm::Collection)
178
+ end
179
+
180
+ it 'should be 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 do
187
+ @return = @articles.send(method, 99..100)
188
+ end
189
+
190
+ it 'should return a Collection' do
191
+ expect(@return).to be_kind_of(Ardm::Collection)
192
+ end
193
+
194
+ it 'should be 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 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
+ expect(@return).to be_kind_of(Ardm::Collection)
213
+ end
214
+
215
+ it 'should return a new instance' do
216
+ expect(@return).not_to equal(@articles)
217
+ end
218
+
219
+ it 'should be expected Resources' do
220
+ expect(@collection).to eq(@articles.entries)
221
+ end
222
+
223
+ it 'should not have a Query the same as the original' do
224
+ expect(@return.query).not_to equal(@articles.query)
225
+ end
226
+
227
+ it 'should have a Query equal to the original' do
228
+ expect(@return.query).to eql(@articles.query)
229
+ end
230
+
231
+ it 'should scope the Collection' do
232
+ expect(@collection.reload).to eq(@copy.entries)
233
+ end
234
+ end
235
+
236
+ describe 'with a query' do
237
+ before do
238
+ @new = @articles.create(:body => 'New Article')
239
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
240
+
241
+ @return = @articles.all(:body => [ 'New Article' ])
242
+ end
243
+
244
+ it 'should return a Collection' do
245
+ expect(@return).to be_kind_of(Ardm::Collection)
246
+ end
247
+
248
+ it 'should return a new instance' do
249
+ expect(@return).not_to equal(@articles)
250
+ end
251
+
252
+ it 'should be expected Resources' do
253
+ expect(@return).to eq([ @new ])
254
+ end
255
+
256
+ it 'should have a different query than original Collection' do
257
+ expect(@return.query).not_to equal(@articles.query)
258
+ end
259
+
260
+ it 'should scope the Collection' do
261
+ expect(@return.reload).to eq(@copy.entries.select { |resource| resource.body == 'New Article' })
262
+ end
263
+ end
264
+
265
+ describe 'with a query using raw conditions' do
266
+ before do
267
+ skip unless defined?(Ardm::Adapters::DataObjectsAdapter) && @adapter.kind_of?(Ardm::Adapters::DataObjectsAdapter)
268
+ end
269
+
270
+ before 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
+ expect(@return).to be_kind_of(Ardm::Collection)
279
+ end
280
+
281
+ it 'should return a new instance' do
282
+ expect(@return).not_to equal(@articles)
283
+ end
284
+
285
+ it 'should be expected Resources' do
286
+ expect(@return).to eq([ @new ])
287
+ end
288
+
289
+ it 'should have a different query than original Collection' do
290
+ expect(@return.query).not_to eq(@articles.query)
291
+ end
292
+
293
+ it 'should scope 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 'should raise 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 do
309
+ @return = @articles.all(:original => @original.attributes)
310
+ end
311
+
312
+ it 'should return a Collection' do
313
+ expect(@return).to be_kind_of(Ardm::Collection)
314
+ end
315
+
316
+ it 'should be expected Resources' do
317
+ expect(@return).to eq([ @article ])
318
+ end
319
+
320
+ it 'should have a valid query' do
321
+ expect(@return.query).to be_valid
322
+ end
323
+ end
324
+
325
+ describe 'with a resource' do
326
+ before do
327
+ @return = @articles.all(:original => @original)
328
+ end
329
+
330
+ it 'should return a Collection' do
331
+ expect(@return).to be_kind_of(Ardm::Collection)
332
+ end
333
+
334
+ it 'should be expected Resources' do
335
+ expect(@return).to eq([ @article ])
336
+ end
337
+
338
+ it 'should have a valid query' do
339
+ expect(@return.query).to be_valid
340
+ end
341
+ end
342
+
343
+ describe 'with a collection' do
344
+ before 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
+ expect(@return).to be_kind_of(Ardm::Collection)
354
+ end
355
+
356
+ it 'should be expected Resources' do
357
+ expect(@return).to eq([ @article ])
358
+ end
359
+
360
+ it 'should have 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 do
368
+ @return = @articles.all(:original => [])
369
+ end
370
+
371
+ it 'should return a Collection' do
372
+ expect(@return).to be_kind_of(Ardm::Collection)
373
+ end
374
+
375
+ it 'should be an empty Collection' do
376
+ expect(@return).to be_empty
377
+ end
378
+
379
+ it 'should 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 do
386
+ @return = @articles.all(:original => nil)
387
+ end
388
+
389
+ it 'should return a Collection' do
390
+ expect(@return).to be_kind_of(Ardm::Collection)
391
+ end
392
+
393
+ if respond_to?(:model?) && model?
394
+ it 'should be expected Resources' do
395
+ expect(@return).to eq([ @original, @other ])
396
+ end
397
+ else
398
+ it 'should be an empty Collection' do
399
+ expect(@return).to be_empty
400
+ end
401
+ end
402
+
403
+ it 'should have a valid query' do
404
+ expect(@return.query).to 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?(Ardm::Record)
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 do
420
+ @return = @articles.all(:original.not => nil)
421
+ end
422
+
423
+ it 'should return a Collection' do
424
+ expect(@return).to be_kind_of(Ardm::Collection)
425
+ end
426
+
427
+ it 'should be expected Resources' do
428
+ expect(@return).to eq([ @article ])
429
+ end
430
+
431
+ it 'should have a valid query' do
432
+ expect(@return.query).to be_valid
433
+ end
434
+
435
+ it 'should be 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 do
443
+ @new = @articles.create(:body => 'New Article', :original => @article)
444
+ end
445
+
446
+ describe 'with a Hash' do
447
+ before do
448
+ @return = @articles.all(:previous => @new.attributes)
449
+ end
450
+
451
+ it 'should return a Collection' do
452
+ expect(@return).to be_kind_of(Ardm::Collection)
453
+ end
454
+
455
+ it 'should be expected Resources' do
456
+ expect(@return).to eq([ @article ])
457
+ end
458
+
459
+ it 'should have a valid query' do
460
+ expect(@return.query).to be_valid
461
+ end
462
+ end
463
+
464
+ describe 'with a resource' do
465
+ before do
466
+ @return = @articles.all(:previous => @new)
467
+ end
468
+
469
+ it 'should return a Collection' do
470
+ expect(@return).to be_kind_of(Ardm::Collection)
471
+ end
472
+
473
+ it 'should be expected Resources' do
474
+ expect(@return).to eq([ @article ])
475
+ end
476
+
477
+ it 'should have a valid query' do
478
+ expect(@return.query).to be_valid
479
+ end
480
+ end
481
+
482
+ describe 'with a collection' do
483
+ before 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
+ expect(@return).to be_kind_of(Ardm::Collection)
493
+ end
494
+
495
+ it 'should be expected Resources' do
496
+ expect(@return).to eq([ @article ])
497
+ end
498
+
499
+ it 'should have 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 do
506
+ @return = @articles.all(:previous => [])
507
+ end
508
+
509
+ it 'should return a Collection' do
510
+ expect(@return).to be_kind_of(Ardm::Collection)
511
+ end
512
+
513
+ it 'should be an empty Collection' do
514
+ expect(@return).to be_empty
515
+ end
516
+
517
+ it 'should 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 do
524
+ @return = @articles.all(:previous => nil)
525
+ end
526
+
527
+ it 'should return a Collection' do
528
+ expect(@return).to be_kind_of(Ardm::Collection)
529
+ end
530
+
531
+ if respond_to?(:model?) && model?
532
+ it 'should be expected Resources' do
533
+ expect(@return).to eq([ @other, @new ])
534
+ end
535
+ else
536
+ it 'should be expected Resources' do
537
+ expect(@return).to eq([ @new ])
538
+ end
539
+ end
540
+
541
+ it 'should have a valid query' do
542
+ expect(@return.query).to be_valid
543
+ end
544
+
545
+ it 'should be 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 do
552
+ @return = @articles.all(:previous.not => nil)
553
+ end
554
+
555
+ it 'should return a Collection' do
556
+ expect(@return).to be_kind_of(Ardm::Collection)
557
+ end
558
+
559
+ if respond_to?(:model?) && model?
560
+ it 'should be expected Resources' do
561
+ expect(@return).to eq([ @original, @article ])
562
+ end
563
+ else
564
+ it 'should be expected Resources' do
565
+ expect(@return).to eq([ @article ])
566
+ end
567
+ end
568
+
569
+ it 'should have a valid query' do
570
+ expect(@return.query).to be_valid
571
+ end
572
+
573
+ it 'should be 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 do
581
+ @new = @articles.create(:body => 'New Article', :original => @article)
582
+ end
583
+
584
+ describe 'with a Hash' do
585
+ before do
586
+ @return = @articles.all(:revisions => @new.attributes)
587
+ end
588
+
589
+ it 'should return a Collection' do
590
+ expect(@return).to be_kind_of(Ardm::Collection)
591
+ end
592
+
593
+ it 'should be expected Resources' do
594
+ expect(@return).to eq([ @article ])
595
+ end
596
+
597
+ it 'should have a valid query' do
598
+ expect(@return.query).to be_valid
599
+ end
600
+ end
601
+
602
+ describe 'with a resource' do
603
+ before do
604
+ @return = @articles.all(:revisions => @new)
605
+ end
606
+
607
+ it 'should return a Collection' do
608
+ expect(@return).to be_kind_of(Ardm::Collection)
609
+ end
610
+
611
+ it 'should be expected Resources' do
612
+ expect(@return).to eq([ @article ])
613
+ end
614
+
615
+ it 'should have a valid query' do
616
+ expect(@return.query).to be_valid
617
+ end
618
+ end
619
+
620
+ describe 'with a collection' do
621
+ before 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
+ expect(@return).to be_kind_of(Ardm::Collection)
631
+ end
632
+
633
+ it 'should be expected Resources' do
634
+ expect(@return).to eq([ @article ])
635
+ end
636
+
637
+ it 'should have 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 do
644
+ @return = @articles.all(:revisions => [])
645
+ end
646
+
647
+ it 'should return a Collection' do
648
+ expect(@return).to be_kind_of(Ardm::Collection)
649
+ end
650
+
651
+ it 'should be an empty Collection' do
652
+ expect(@return).to be_empty
653
+ end
654
+
655
+ it 'should 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 do
662
+ @return = @articles.all(:revisions => nil)
663
+ end
664
+
665
+ it 'should return a Collection' do
666
+ expect(@return).to be_kind_of(Ardm::Collection)
667
+ end
668
+
669
+ if respond_to?(:model?) && model?
670
+ it 'should be expected Resources' do
671
+ expect(@return).to eq([ @other, @new ])
672
+ end
673
+ else
674
+ it 'should be expected Resources' do
675
+ expect(@return).to eq([ @new ])
676
+ end
677
+ end
678
+
679
+ it 'should have a valid query' do
680
+ expect(@return.query).to be_valid
681
+ end
682
+
683
+ it 'should be 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 do
690
+ @return = @articles.all(:revisions.not => nil)
691
+ end
692
+
693
+ it 'should return a Collection' do
694
+ expect(@return).to be_kind_of(Ardm::Collection)
695
+ end
696
+
697
+ if respond_to?(:model?) && model?
698
+ it 'should be expected Resources' do
699
+ expect(@return).to eq([ @original, @article ])
700
+ end
701
+ else
702
+ it 'should be expected Resources' do
703
+ expect(@return).to eq([ @article ])
704
+ end
705
+ end
706
+
707
+ it 'should have a valid query' do
708
+ expect(@return.query).to be_valid
709
+ end
710
+
711
+ it 'should be 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 do
719
+ @publication = @article.publications.create(:name => 'Ardm Now')
720
+ end
721
+
722
+ describe 'with a Hash' do
723
+ before do
724
+ @return = @articles.all(:publications => @publication.attributes)
725
+ end
726
+
727
+ it 'should return a Collection' do
728
+ expect(@return).to be_kind_of(Ardm::Collection)
729
+ end
730
+
731
+ it 'should be expected Resources' do
732
+ skip 'TODO'
733
+ expect(@return).to eq([ @article ])
734
+ end
735
+
736
+ it 'should have a valid query' do
737
+ expect(@return.query).to be_valid
738
+ end
739
+ end
740
+
741
+ describe 'with a resource' do
742
+ before do
743
+ @return = @articles.all(:publications => @publication)
744
+ end
745
+
746
+ it 'should return a Collection' do
747
+ expect(@return).to be_kind_of(Ardm::Collection)
748
+ end
749
+
750
+ it 'should be expected Resources' do
751
+ skip 'TODO'
752
+ expect(@return).to eq([ @article ])
753
+ end
754
+
755
+ it 'should have a valid query' do
756
+ expect(@return.query).to be_valid
757
+ end
758
+ end
759
+
760
+ describe 'with a collection' do
761
+ before do
762
+ @collection = @publication_model.all(
763
+ Hash[ @publication_model.key.zip(@publication.key) ]
764
+ )
765
+
766
+ @return = @articles.all(:publications => @collection)
767
+ end
768
+
769
+ it 'should return a Collection' do
770
+ expect(@return).to be_kind_of(Ardm::Collection)
771
+ end
772
+
773
+ it 'should be expected Resources' do
774
+ skip 'TODO'
775
+ expect(@return).to eq([ @article ])
776
+ end
777
+
778
+ it 'should have a valid query' do
779
+ expect(@return.query).to be_valid
780
+ end
781
+ end
782
+
783
+ describe 'with an empty Array' do
784
+ before do
785
+ @return = @articles.all(:publications => [])
786
+ end
787
+
788
+ it 'should return a Collection' do
789
+ expect(@return).to be_kind_of(Ardm::Collection)
790
+ end
791
+
792
+ it 'should be an empty Collection' do
793
+ expect(@return).to be_empty
794
+ end
795
+
796
+ it 'should not have a valid query' do
797
+ expect(@return.query).not_to be_valid
798
+ end
799
+ end
800
+
801
+ describe 'with a nil value' do
802
+ before do
803
+ @return = @articles.all(:publications => nil)
804
+ end
805
+
806
+ it 'should return a Collection' do
807
+ expect(@return).to be_kind_of(Ardm::Collection)
808
+ end
809
+
810
+ it 'should be empty' do
811
+ skip 'TODO'
812
+ expect(@return).to be_empty
813
+ end
814
+
815
+ it 'should have a valid query' do
816
+ expect(@return.query).to be_valid
817
+ end
818
+
819
+ it 'should be equivalent to negated collection query' do
820
+ expect(@return).to eq(@articles.all(:publications.not => @publication_model.all))
821
+ end
822
+ end
823
+
824
+ describe 'with a negated nil value' do
825
+ before do
826
+ @return = @articles.all(:publications.not => nil)
827
+ end
828
+
829
+ it 'should return a Collection' do
830
+ expect(@return).to be_kind_of(Ardm::Collection)
831
+ end
832
+
833
+ it 'should be expected Resources' do
834
+ skip 'TODO'
835
+ expect(@return).to eq([ @article ])
836
+ end
837
+
838
+ it 'should have a valid query' do
839
+ expect(@return.query).to be_valid
840
+ end
841
+
842
+ it 'should be equivalent to collection query' do
843
+ expect(@return).to eq(@articles.all(:publications => @publication_model.all))
844
+ end
845
+ end
846
+ end
847
+ end
848
+
849
+ it { expect(@articles).to respond_to(:at) }
850
+
851
+ describe '#at' do
852
+ before do
853
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
854
+ @copy.to_a
855
+ end
856
+
857
+ describe 'with positive offset' do
858
+ before do
859
+ @return = @resource = @articles.at(0)
860
+ end
861
+
862
+ it 'should return a Resource' do
863
+ expect(@return).to be_kind_of(Ardm::Record)
864
+ end
865
+
866
+ it 'should return expected Resource' do
867
+ expect(@resource).to eq(@copy.entries.at(0))
868
+ end
869
+ end
870
+
871
+ describe 'with negative offset' do
872
+ before do
873
+ @return = @resource = @articles.at(-1)
874
+ end
875
+
876
+ it 'should return a Resource' do
877
+ expect(@return).to be_kind_of(Ardm::Record)
878
+ end
879
+
880
+ it 'should return expected Resource' do
881
+ expect(@resource).to eq(@copy.entries.at(-1))
882
+ end
883
+ end
884
+ end
885
+
886
+ it { expect(@articles).to respond_to(:each) }
887
+
888
+ describe '#each' do
889
+ subject { @articles.each(&block) }
890
+
891
+ let(:yields) { [] }
892
+ let(:block) { lambda { |resource| yields << resource } }
893
+
894
+ before do
895
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
896
+ @copy.to_a
897
+ end
898
+
899
+ it { is_expected.to equal(@articles) }
900
+
901
+ it { expect(method(:subject)).to change { yields.dup }.from([]).to(@copy.to_a) }
902
+ end
903
+
904
+ it { expect(@articles).to respond_to(:fetch) }
905
+
906
+ describe '#fetch' do
907
+ subject { @articles.fetch(*args, &block) }
908
+
909
+ let(:block) { nil }
910
+
911
+ context 'with a valid index and no default' do
912
+ let(:args) { [ 0 ] }
913
+
914
+ before do
915
+ @copy = @articles.kind_of?(Class) ? @articles : @articles.dup
916
+ @copy.to_a
917
+ end
918
+
919
+ it { is_expected.to be_kind_of(Array) }
920
+
921
+ it { is_expected.to eq(@copy.entries.values_at(*args)) }
922
+ end
923
+
924
+ describe 'with negative offset' do
925
+ let(:args) { [ -1 ] }
926
+
927
+ it { is_expected.to be_kind_of(Array) }
928
+
929
+ it { is_expected.to eq(@copy.entries.values_at(*args)) }
930
+ end
931
+ end
932
+
933
+ it 'should respond to a belongs_to relationship method with #method_missing' do
934
+ pending_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class)
935
+ expect(@articles).to respond_to(:original)
936
+ end
937
+
938
+ it 'should respond to a has n relationship method with #method_missing' do
939
+ pending_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class)
940
+ expect(@articles).to respond_to(:revisions)
941
+ end
942
+
943
+ it 'should respond to a has 1 relationship method with #method_missing' do
944
+ pending_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class)
945
+ expect(@articles).to respond_to(:previous)
946
+ end
947
+
948
+ describe '#method_missing' do
949
+ before do
950
+ skip 'Model#method_missing should delegate to relationships' if @articles.kind_of?(Class)
951
+ end
952
+
953
+ describe 'with a belongs_to relationship method' do
954
+ before do
955
+ rescue_if 'Model#method_missing should delegate to relationships', @articles.kind_of?(Class) do
956
+ @articles.create(:body => 'Another Article', :original => @original)
957
+
958
+ @return = @collection = @articles.originals
959
+ end
960
+ end
961
+
962
+ it 'should return a Collection' do
963
+ expect(@return).to be_kind_of(Ardm::Collection)
964
+ end
965
+
966
+ it 'should return expected Collection' do
967
+ expect(@collection).to eq([ @original ])
968
+ end
969
+
970
+ it 'should set the association for each Resource' do
971
+ expect(@articles.map { |resource| resource.original }).to eq([ @original, @original ])
972
+ end
973
+ end
974
+
975
+ describe 'with a has 1 relationship method' do
976
+ before do
977
+ # FIXME: create is necessary for m:m so that the intermediary
978
+ # is created properly. This does not occur with @new.save
979
+ @new = @articles.send(@many_to_many ? :create : :new)
980
+
981
+ @article.previous = @new
982
+ @new.previous = @other
983
+
984
+ expect(@article.save).to be(true)
985
+ end
986
+
987
+ describe 'with no arguments' do
988
+ before do
989
+ @return = @articles.previous
990
+ end
991
+
992
+ it 'should return a Collection' do
993
+ expect(@return).to be_kind_of(Ardm::Collection)
994
+ end
995
+
996
+ it 'should return expected Collection' do
997
+ # association is sorted reverse by id
998
+ expect(@return).to eq([ @new, @other ])
999
+ end
1000
+
1001
+ it 'should set the association for each Resource' do
1002
+ expect(@articles.map { |resource| resource.previous }).to eq([ @new, @other ])
1003
+ end
1004
+ end
1005
+
1006
+ describe 'with arguments' do
1007
+ before do
1008
+ @return = @articles.previous(:fields => [ :id ])
1009
+ end
1010
+
1011
+ it 'should return a Collection' do
1012
+ expect(@return).to be_kind_of(Ardm::Collection)
1013
+ end
1014
+
1015
+ it 'should return expected Collection' do
1016
+ # association is sorted reverse by id
1017
+ expect(@return).to eq([ @new, @other ])
1018
+ end
1019
+
1020
+ { :id => true, :title => false, :body => false }.each do |attribute, expected|
1021
+ it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
1022
+ @return.each { |resource| expect(resource.attribute_loaded?(attribute)).to eq(expected) }
1023
+ end
1024
+ end
1025
+
1026
+ it 'should set the association for each Resource' do
1027
+ expect(@articles.map { |resource| resource.previous }).to eq([ @new, @other ])
1028
+ end
1029
+ end
1030
+ end
1031
+
1032
+ describe 'with a has n relationship method' do
1033
+ before do
1034
+ # FIXME: create is necessary for m:m so that the intermediary
1035
+ # is created properly. This does not occur with @new.save
1036
+ @new = @articles.send(@many_to_many ? :create : :new)
1037
+
1038
+ # associate the article with children
1039
+ @article.revisions << @new
1040
+ @new.revisions << @other
1041
+
1042
+ expect(@article.save).to be(true)
1043
+ end
1044
+
1045
+ describe 'with no arguments' do
1046
+ before do
1047
+ @return = @collection = @articles.revisions
1048
+ end
1049
+
1050
+ it 'should return a Collection' do
1051
+ expect(@return).to be_kind_of(Ardm::Collection)
1052
+ end
1053
+
1054
+ it 'should return expected Collection' do
1055
+ expect(@collection).to eq([ @other, @new ])
1056
+ end
1057
+
1058
+ it 'should set the association for each Resource' do
1059
+ expect(@articles.map { |resource| resource.revisions }).to eq([ [ @new ], [ @other ] ])
1060
+ end
1061
+ end
1062
+
1063
+ describe 'with arguments' do
1064
+ before do
1065
+ @return = @collection = @articles.revisions(:fields => [ :id ])
1066
+ end
1067
+
1068
+ it 'should return a Collection' do
1069
+ expect(@return).to be_kind_of(Ardm::Collection)
1070
+ end
1071
+
1072
+ it 'should return expected Collection' do
1073
+ expect(@collection).to eq([ @other, @new ])
1074
+ end
1075
+
1076
+ { :id => true, :title => false, :body => false }.each do |attribute, expected|
1077
+ it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
1078
+ @collection.each { |resource| expect(resource.attribute_loaded?(attribute)).to eq(expected) }
1079
+ end
1080
+ end
1081
+
1082
+ it 'should set the association for each Resource' do
1083
+ expect(@articles.map { |resource| resource.revisions }).to eq([ [ @new ], [ @other ] ])
1084
+ end
1085
+ end
1086
+ end
1087
+
1088
+ describe 'with a has n :through relationship method' do
1089
+ before do
1090
+ @new = @articles.create
1091
+
1092
+ @publication1 = @article.publications.create(:name => 'Ruby Today')
1093
+ @publication2 = @new.publications.create(:name => 'Inside Ardm')
1094
+ end
1095
+
1096
+ describe 'with no arguments' do
1097
+ before do
1098
+ @return = @collection = @articles.publications
1099
+ end
1100
+
1101
+ it 'should return a Collection' do
1102
+ expect(@return).to be_kind_of(Ardm::Collection)
1103
+ end
1104
+
1105
+ it 'should return expected Collection' do
1106
+ pending_if @no_join
1107
+ expect(@collection).to eq([ @publication1, @publication2 ])
1108
+ end
1109
+
1110
+ it 'should set the association for each Resource' do
1111
+ pending_if @no_join
1112
+ expect(@articles.map { |resource| resource.publications }).to eq([ [ @publication1 ], [ @publication2 ] ])
1113
+ end
1114
+ end
1115
+
1116
+ describe 'with arguments' do
1117
+ before do
1118
+ @return = @collection = @articles.publications(:fields => [ :id ])
1119
+ end
1120
+
1121
+ it 'should return a Collection' do
1122
+ expect(@return).to be_kind_of(Ardm::Collection)
1123
+ end
1124
+
1125
+ it 'should return expected Collection' do
1126
+ pending_if @no_join
1127
+ expect(@collection).to eq([ @publication1, @publication2 ])
1128
+ end
1129
+
1130
+ { :id => true, :name => false }.each do |attribute, expected|
1131
+ it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
1132
+ @collection.each { |resource| expect(resource.attribute_loaded?(attribute)).to eq(expected) }
1133
+ end
1134
+ end
1135
+
1136
+ it 'should set the association for each Resource' do
1137
+ pending_if @no_join
1138
+ expect(@articles.map { |resource| resource.publications }).to eq([ [ @publication1 ], [ @publication2 ] ])
1139
+ end
1140
+ end
1141
+ end
1142
+
1143
+ describe 'with an unknown method' do
1144
+ it 'should raise an exception' do
1145
+ expect {
1146
+ @articles.unknown
1147
+ }.to raise_error(NoMethodError)
1148
+ end
1149
+ end
1150
+ end
1151
+ end