ardm 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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