cuprum-collections 0.5.0 → 0.6.0.rc.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 +4 -4
  2. data/CHANGELOG.md +51 -0
  3. data/README.md +1 -1
  4. data/config/locales/en.rb +18 -0
  5. data/lib/cuprum/collections/adaptable/collection.rb +18 -0
  6. data/lib/cuprum/collections/adaptable/command.rb +22 -0
  7. data/lib/cuprum/collections/adaptable/commands/abstract_assign_one.rb +27 -0
  8. data/lib/cuprum/collections/adaptable/commands/abstract_build_one.rb +25 -0
  9. data/lib/cuprum/collections/adaptable/commands/abstract_validate_one.rb +35 -0
  10. data/lib/cuprum/collections/adaptable/commands.rb +15 -0
  11. data/lib/cuprum/collections/adaptable/query.rb +64 -0
  12. data/lib/cuprum/collections/adaptable.rb +13 -0
  13. data/lib/cuprum/collections/adapter.rb +300 -0
  14. data/lib/cuprum/collections/adapters/data_adapter.rb +82 -0
  15. data/lib/cuprum/collections/adapters/entity_adapter.rb +76 -0
  16. data/lib/cuprum/collections/adapters/hash_adapter.rb +48 -0
  17. data/lib/cuprum/collections/adapters.rb +14 -0
  18. data/lib/cuprum/collections/basic/collection.rb +2 -20
  19. data/lib/cuprum/collections/basic/commands/destroy_one.rb +1 -1
  20. data/lib/cuprum/collections/basic/commands/find_many.rb +0 -31
  21. data/lib/cuprum/collections/basic/commands/find_matching.rb +0 -94
  22. data/lib/cuprum/collections/basic/commands/find_one.rb +0 -18
  23. data/lib/cuprum/collections/basic/commands/insert_one.rb +1 -1
  24. data/lib/cuprum/collections/basic/commands/update_one.rb +1 -1
  25. data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +36 -21
  26. data/lib/cuprum/collections/basic.rb +6 -5
  27. data/lib/cuprum/collections/collection.rb +6 -0
  28. data/lib/cuprum/collections/collection_command.rb +1 -1
  29. data/lib/cuprum/collections/commands/abstract_find_many.rb +40 -3
  30. data/lib/cuprum/collections/commands/abstract_find_matching.rb +102 -0
  31. data/lib/cuprum/collections/commands/abstract_find_one.rb +23 -1
  32. data/lib/cuprum/collections/commands/associations/find_many.rb +1 -3
  33. data/lib/cuprum/collections/commands/associations/require_many.rb +1 -1
  34. data/lib/cuprum/collections/commands/find_one_matching.rb +10 -10
  35. data/lib/cuprum/collections/commands/query_command.rb +6 -4
  36. data/lib/cuprum/collections/commands/upsert.rb +0 -2
  37. data/lib/cuprum/collections/constraints/order/attributes_array.rb +5 -4
  38. data/lib/cuprum/collections/constraints/order/attributes_hash.rb +5 -4
  39. data/lib/cuprum/collections/constraints/order/sort_direction.rb +2 -2
  40. data/lib/cuprum/collections/constraints/ordering.rb +11 -9
  41. data/lib/cuprum/collections/constraints/query_hash.rb +2 -2
  42. data/lib/cuprum/collections/errors/abstract_find_error.rb +101 -23
  43. data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
  44. data/lib/cuprum/collections/errors/failed_validation.rb +3 -3
  45. data/lib/cuprum/collections/errors/missing_default_contract.rb +12 -4
  46. data/lib/cuprum/collections/queries.rb +4 -0
  47. data/lib/cuprum/collections/relation.rb +0 -2
  48. data/lib/cuprum/collections/relations/parameters.rb +120 -68
  49. data/lib/cuprum/collections/repository.rb +71 -6
  50. data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +23 -4
  51. data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +18 -0
  52. data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +51 -0
  53. data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +10 -0
  54. data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +8 -0
  55. data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +18 -366
  56. data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +30 -0
  57. data/lib/cuprum/collections/rspec/contracts/scopes.rb +2 -0
  58. data/lib/cuprum/collections/rspec/contracts.rb +2 -10
  59. data/lib/cuprum/collections/rspec/deferred/adapter_examples.rb +1077 -0
  60. data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +27 -7
  61. data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +4 -4
  62. data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +2 -2
  63. data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +2 -2
  64. data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +5 -5
  65. data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +45 -12
  66. data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +2 -2
  67. data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +1 -1
  68. data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +1 -1
  69. data/lib/cuprum/collections/rspec/deferred/query_examples.rb +930 -0
  70. data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +48 -17
  71. data/lib/cuprum/collections/rspec/deferred/repository_examples.rb +961 -0
  72. data/lib/cuprum/collections/rspec/deferred/scope_examples.rb +598 -0
  73. data/lib/cuprum/collections/rspec/deferred/scopes/all_examples.rb +391 -0
  74. data/lib/cuprum/collections/rspec/deferred/scopes/builder_examples.rb +857 -0
  75. data/lib/cuprum/collections/rspec/deferred/scopes/composition_examples.rb +93 -0
  76. data/lib/cuprum/collections/rspec/deferred/scopes/conjunction_examples.rb +438 -0
  77. data/lib/cuprum/collections/rspec/deferred/scopes/criteria_examples.rb +1941 -0
  78. data/lib/cuprum/collections/rspec/deferred/scopes/disjunction_examples.rb +415 -0
  79. data/lib/cuprum/collections/rspec/deferred/scopes/none_examples.rb +385 -0
  80. data/lib/cuprum/collections/rspec/deferred/scopes/parser_examples.rb +740 -0
  81. data/lib/cuprum/collections/rspec/deferred/scopes.rb +8 -0
  82. data/lib/cuprum/collections/scope.rb +2 -2
  83. data/lib/cuprum/collections/scopes/container.rb +5 -4
  84. data/lib/cuprum/collections/scopes/criteria/parser.rb +24 -48
  85. data/lib/cuprum/collections/scopes/criteria.rb +7 -6
  86. data/lib/cuprum/collections/version.rb +3 -3
  87. data/lib/cuprum/collections.rb +5 -1
  88. metadata +48 -11
  89. data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +0 -2127
  90. data/lib/cuprum/collections/rspec/contracts/basic.rb +0 -11
  91. data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +0 -387
  92. data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +0 -169
  93. data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +0 -1264
@@ -0,0 +1,598 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/sleeping_king_studios/deferred'
4
+
5
+ require 'cuprum/collections/rspec/deferred'
6
+
7
+ module Cuprum::Collections::RSpec::Deferred
8
+ # Deferred examples for asserting on scope objects.
9
+ module ScopeExamples
10
+ include RSpec::SleepingKingStudios::Deferred::Provider
11
+
12
+ deferred_examples 'should implement the Scope methods' \
13
+ do |**deferred_options|
14
+ describe '#==' do
15
+ it { expect(subject == nil).to be false } # rubocop:disable Style/NilComparison
16
+
17
+ it { expect(subject == Object.new.freeze).to be false }
18
+
19
+ describe 'with a scope of different type' do
20
+ let(:other) { Spec::OtherScope.new }
21
+
22
+ example_class 'Spec::OtherScope',
23
+ Cuprum::Collections::Scopes::Base \
24
+ do |klass|
25
+ klass.define_method(:type) { :invalid }
26
+ end
27
+
28
+ it { expect(subject == other).to be false }
29
+ end
30
+ end
31
+
32
+ describe '#as_json' do
33
+ it { expect(subject).to respond_to(:as_json).with(0).arguments }
34
+
35
+ it { expect(subject.as_json).to be_a Hash }
36
+
37
+ it { expect(subject.as_json['type']).to be subject.type }
38
+ end
39
+
40
+ describe '#empty?' do
41
+ include_examples 'should define predicate', :empty?, -> { be_boolean }
42
+ end
43
+
44
+ describe '#invert' do
45
+ let(:error_class) do
46
+ Cuprum::Collections::Scopes::Base::UninvertibleScopeException
47
+ end
48
+ let(:error_message) do
49
+ "Scope class #{described_class} does not implement #invert"
50
+ end
51
+
52
+ it { expect(subject).to respond_to(:invert).with(0).arguments }
53
+
54
+ next if deferred_options.fetch(:invertible, true)
55
+
56
+ it 'should raise an exception' do
57
+ expect { subject.invert }.to raise_error error_class, error_message
58
+ end
59
+ end
60
+
61
+ describe '#type' do
62
+ include_examples 'should define reader', :type, -> { be_a(Symbol) }
63
+ end
64
+ end
65
+
66
+ deferred_examples 'should define child scopes' do
67
+ deferred_context 'with scopes' do
68
+ let(:scopes) do
69
+ [
70
+ build_scope({ 'title' => 'J.R.R. Tolkien' }),
71
+ build_scope({ 'series' => 'The Lord of the Rings' }),
72
+ build_scope({ 'category' => 'Science Fiction and Fantasy' })
73
+ ]
74
+ end
75
+ end
76
+
77
+ describe '.new' do
78
+ it 'should define the constructor' do
79
+ expect(described_class)
80
+ .to be_constructible
81
+ .with(0).arguments
82
+ .and_keywords(:scopes)
83
+ .and_any_keywords
84
+ end
85
+ end
86
+
87
+ describe '#==' do
88
+ describe 'with a scope with the same class' do
89
+ let(:other) { described_class.new(scopes: other_scopes) }
90
+
91
+ describe 'with empty scopes' do
92
+ let(:other_scopes) { [] }
93
+
94
+ it { expect(subject == other).to be true }
95
+ end
96
+
97
+ describe 'with non-matching scopes' do
98
+ let(:other_scopes) do
99
+ Array.new(3) do
100
+ Cuprum::Collections::Scope.new({ 'ok' => true })
101
+ end
102
+ end
103
+
104
+ it { expect(subject == other).to be false }
105
+ end
106
+
107
+ wrap_deferred 'with scopes' do
108
+ describe 'with empty scopes' do
109
+ let(:other_scopes) { [] }
110
+
111
+ it { expect(subject == other).to be false }
112
+ end
113
+
114
+ describe 'with non-matching scopes' do
115
+ let(:other_scopes) do
116
+ Array.new(3) do
117
+ Cuprum::Collections::Scope.new({ 'ok' => true })
118
+ end
119
+ end
120
+
121
+ it { expect(subject == other).to be false }
122
+ end
123
+
124
+ describe 'with matching scopes' do
125
+ let(:other_scopes) { subject.scopes }
126
+
127
+ it { expect(subject == other).to be true }
128
+ end
129
+ end
130
+ end
131
+
132
+ describe 'with a scope with the same type' do
133
+ let(:other) { Spec::CustomScope.new(scopes: other_scopes) }
134
+
135
+ example_class 'Spec::CustomScope',
136
+ Cuprum::Collections::Scopes::Base \
137
+ do |klass|
138
+ klass.include Cuprum::Collections::Scopes::Container
139
+ end
140
+
141
+ before(:example) do
142
+ allow(other).to receive(:type).and_return(scope.type)
143
+ end
144
+
145
+ describe 'with empty scopes' do
146
+ let(:other_scopes) { [] }
147
+
148
+ it { expect(subject == other).to be true }
149
+ end
150
+
151
+ describe 'with non-matching scopes' do
152
+ let(:other_scopes) do
153
+ Array.new(3) do
154
+ Cuprum::Collections::Scope.new({ 'ok' => true })
155
+ end
156
+ end
157
+
158
+ it { expect(subject == other).to be false }
159
+ end
160
+
161
+ wrap_deferred 'with scopes' do
162
+ describe 'with empty scopes' do
163
+ let(:other_scopes) { [] }
164
+
165
+ it { expect(subject == other).to be false }
166
+ end
167
+
168
+ describe 'with non-matching scopes' do
169
+ let(:other_scopes) do
170
+ Array.new(3) do
171
+ Cuprum::Collections::Scope.new({ 'ok' => true })
172
+ end
173
+ end
174
+
175
+ it { expect(subject == other).to be false }
176
+ end
177
+
178
+ describe 'with matching scopes' do
179
+ let(:other_scopes) { subject.scopes }
180
+
181
+ it { expect(subject == other).to be true }
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ describe '#as_json' do
188
+ it { expect(subject.as_json['scopes']).to be == [] }
189
+
190
+ wrap_deferred 'with scopes' do
191
+ let(:expected) { subject.scopes.map(&:as_json) }
192
+
193
+ it { expect(subject.as_json['scopes']).to be == expected }
194
+ end
195
+ end
196
+
197
+ describe '#empty?' do
198
+ it { expect(subject.empty?).to be true }
199
+
200
+ wrap_deferred 'with scopes' do
201
+ it { expect(subject.empty?).to be false }
202
+ end
203
+ end
204
+
205
+ describe '#scopes' do
206
+ include_examples 'should define reader', :scopes, -> { scopes }
207
+
208
+ wrap_deferred 'with scopes' do
209
+ it { expect(subject.scopes).to be == scopes }
210
+ end
211
+ end
212
+
213
+ describe '#with_scopes' do
214
+ let(:new_scopes) do
215
+ [
216
+ described_class.new(scopes: []),
217
+ described_class.new(scopes: [])
218
+ ]
219
+ end
220
+
221
+ it { expect(subject).to respond_to(:with_scopes).with(1).arguments }
222
+
223
+ it 'should return a scope' do
224
+ expect(subject.with_scopes(new_scopes)).to be_a described_class
225
+ end
226
+
227
+ it "should not change the original scope's child scopes" do
228
+ expect { subject.with_scopes(new_scopes) }
229
+ .not_to change(subject, :scopes)
230
+ end
231
+
232
+ it "should set the copied scope's child scopes" do
233
+ expect(subject.with_scopes(new_scopes).scopes)
234
+ .to be == new_scopes
235
+ end
236
+
237
+ wrap_deferred 'with scopes' do
238
+ it "should not change the original scope's child scopes" do
239
+ expect { subject.with_scopes(new_scopes) }
240
+ .not_to change(subject, :scopes)
241
+ end
242
+
243
+ it "should set the copied scope's child scopes" do
244
+ expect(subject.with_scopes(new_scopes).scopes)
245
+ .to be == new_scopes
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ deferred_examples 'should compose scopes' do |**deferred_options|
252
+ deferred_context 'with an all scope' do
253
+ let(:original) do
254
+ Cuprum::Collections::Scopes::AllScope.new
255
+ end
256
+ end
257
+
258
+ deferred_context 'with a none scope' do
259
+ let(:original) do
260
+ Cuprum::Collections::Scopes::NoneScope.new
261
+ end
262
+ end
263
+
264
+ deferred_context 'with an empty conjunction scope' do
265
+ let(:original) do
266
+ Cuprum::Collections::Scopes::ConjunctionScope.new(scopes: [])
267
+ end
268
+ end
269
+
270
+ deferred_context 'with an empty criteria scope' do
271
+ let(:original) do
272
+ Cuprum::Collections::Scopes::CriteriaScope.new(criteria: [])
273
+ end
274
+ end
275
+
276
+ deferred_context 'with an empty disjunction scope' do
277
+ let(:original) do
278
+ Cuprum::Collections::Scopes::DisjunctionScope.new(scopes: [])
279
+ end
280
+ end
281
+
282
+ deferred_context 'with a non-empty conjunction scope' do
283
+ let(:original) do
284
+ operators = Cuprum::Collections::Queries::Operators
285
+ criteria = [
286
+ [
287
+ 'category',
288
+ operators::EQUAL,
289
+ 'Science Fiction and Fantasy'
290
+ ]
291
+ ]
292
+ wrapped =
293
+ Cuprum::Collections::Scopes::CriteriaScope.new(criteria:)
294
+
295
+ Cuprum::Collections::Scopes::ConjunctionScope.new(scopes: [wrapped])
296
+ end
297
+ end
298
+
299
+ deferred_context 'with a non-empty criteria scope' do
300
+ let(:original) do
301
+ operators = Cuprum::Collections::Queries::Operators
302
+ criteria = [
303
+ [
304
+ 'category',
305
+ operators::EQUAL,
306
+ 'Science Fiction and Fantasy'
307
+ ]
308
+ ]
309
+
310
+ Cuprum::Collections::Scopes::CriteriaScope.new(criteria:)
311
+ end
312
+ end
313
+
314
+ deferred_context 'with a non-empty disjunction scope' do
315
+ let(:original) do
316
+ operators = Cuprum::Collections::Queries::Operators
317
+ criteria = [
318
+ [
319
+ 'category',
320
+ operators::EQUAL,
321
+ 'Science Fiction and Fantasy'
322
+ ]
323
+ ]
324
+ wrapped =
325
+ Cuprum::Collections::Scopes::CriteriaScope.new(criteria:)
326
+
327
+ Cuprum::Collections::Scopes::DisjunctionScope.new(scopes: [wrapped])
328
+ end
329
+ end
330
+
331
+ describe '#and' do
332
+ it 'should define the method' do
333
+ expect(subject)
334
+ .to respond_to(:and)
335
+ .with(0..1).arguments
336
+ .and_a_block
337
+ end
338
+
339
+ it { expect(subject).to have_aliased_method(:and).as(:where) }
340
+
341
+ next if deferred_options.fetch(:include, []).include?(:and)
342
+
343
+ describe 'with a block' do
344
+ let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
345
+ let(:expected) do
346
+ wrapped = Cuprum::Collections::Scope.new(&block)
347
+
348
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
349
+ scopes: [subject, wrapped]
350
+ )
351
+ end
352
+
353
+ it { expect(subject.and(&block)).to be == expected }
354
+ end
355
+
356
+ describe 'with a hash' do
357
+ let(:value) { { 'title' => 'A Wizard of Earthsea' } }
358
+ let(:expected) do
359
+ wrapped = Cuprum::Collections::Scope.new(value)
360
+
361
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
362
+ scopes: [subject, wrapped]
363
+ )
364
+ end
365
+
366
+ it { expect(subject.and(value)).to be == expected }
367
+ end
368
+
369
+ wrap_deferred 'with an all scope' do
370
+ it { expect(subject.and(original)).to be subject }
371
+ end
372
+
373
+ wrap_deferred 'with a none scope' do
374
+ it { expect(subject.and(original)).to be == original }
375
+ end
376
+
377
+ wrap_deferred 'with an empty conjunction scope' do
378
+ it { expect(subject.and(original)).to be subject }
379
+ end
380
+
381
+ wrap_deferred 'with an empty criteria scope' do
382
+ it { expect(subject.and(original)).to be subject }
383
+ end
384
+
385
+ wrap_deferred 'with an empty disjunction scope' do
386
+ it { expect(subject.and(original)).to be subject }
387
+ end
388
+
389
+ wrap_deferred 'with a non-empty conjunction scope' do
390
+ let(:expected) do
391
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
392
+ scopes: [subject, *original.scopes]
393
+ )
394
+ end
395
+
396
+ it { expect(subject.and(original)).to be == expected }
397
+ end
398
+
399
+ wrap_deferred 'with a non-empty criteria scope' do
400
+ let(:expected) do
401
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
402
+ scopes: [subject, original]
403
+ )
404
+ end
405
+
406
+ it { expect(subject.and(original)).to be == expected }
407
+ end
408
+
409
+ wrap_deferred 'with a non-empty disjunction scope' do
410
+ let(:expected) do
411
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
412
+ scopes: [subject, original]
413
+ )
414
+ end
415
+
416
+ it { expect(subject.and(original)).to be == expected }
417
+ end
418
+ end
419
+
420
+ describe '#not' do
421
+ it 'should define the method' do
422
+ expect(subject)
423
+ .to respond_to(:not)
424
+ .with(0..1).arguments
425
+ .and_a_block
426
+ end
427
+
428
+ next if deferred_options.fetch(:include, []).include?(:not)
429
+
430
+ describe 'with a block' do
431
+ let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
432
+ let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
433
+ let(:expected) do
434
+ wrapped = Cuprum::Collections::Scope.new(&block)
435
+
436
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
437
+ scopes: [subject, wrapped.invert]
438
+ )
439
+ end
440
+
441
+ it { expect(subject.not(&block)).to be == expected }
442
+ end
443
+
444
+ describe 'with a hash' do
445
+ let(:value) { { 'title' => 'A Wizard of Earthsea' } }
446
+ let(:expected) do
447
+ wrapped = Cuprum::Collections::Scope.new(value)
448
+
449
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
450
+ scopes: [subject, wrapped.invert]
451
+ )
452
+ end
453
+
454
+ it { expect(subject.not(value)).to be == expected }
455
+ end
456
+
457
+ wrap_deferred 'with an all scope' do
458
+ let(:expected) { Cuprum::Collections::Scopes::NoneScope.new }
459
+
460
+ it { expect(subject.not(original)).to be == expected }
461
+ end
462
+
463
+ wrap_deferred 'with a none scope' do
464
+ it { expect(subject.not(original)).to be subject }
465
+ end
466
+
467
+ wrap_deferred 'with an empty conjunction scope' do
468
+ it { expect(subject.not(original)).to be subject }
469
+ end
470
+
471
+ wrap_deferred 'with an empty criteria scope' do
472
+ it { expect(subject.not(original)).to be subject }
473
+ end
474
+
475
+ wrap_deferred 'with an empty disjunction scope' do
476
+ it { expect(subject.not(original)).to be subject }
477
+ end
478
+
479
+ wrap_deferred 'with a non-empty conjunction scope' do
480
+ let(:expected) do
481
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
482
+ scopes: [subject, original.invert]
483
+ )
484
+ end
485
+
486
+ it { expect(subject.not(original)).to be == expected }
487
+ end
488
+
489
+ wrap_deferred 'with a non-empty criteria scope' do
490
+ let(:expected) do
491
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
492
+ scopes: [subject, original.invert]
493
+ )
494
+ end
495
+
496
+ it { expect(subject.not(original)).to be == expected }
497
+ end
498
+
499
+ wrap_deferred 'with a non-empty disjunction scope' do
500
+ let(:expected) do
501
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
502
+ scopes: [subject, *original.invert.scopes]
503
+ )
504
+ end
505
+
506
+ it { expect(subject.not(original)).to be == expected }
507
+ end
508
+ end
509
+
510
+ describe '#or' do
511
+ it 'should define the method' do
512
+ expect(subject)
513
+ .to respond_to(:or)
514
+ .with(0..1).arguments
515
+ .and_a_block
516
+ end
517
+
518
+ next if deferred_options.fetch(:include, []).include?(:or)
519
+
520
+ describe 'with a block' do
521
+ let(:block) { -> { { 'title' => 'A Wizard of Earthsea' } } }
522
+ let(:expected) do
523
+ wrapped = Cuprum::Collections::Scope.new(&block)
524
+
525
+ Cuprum::Collections::Scopes::DisjunctionScope.new(
526
+ scopes: [subject, wrapped]
527
+ )
528
+ end
529
+
530
+ it { expect(subject.or(&block)).to be == expected }
531
+ end
532
+
533
+ describe 'with a hash' do
534
+ let(:value) { { 'title' => 'A Wizard of Earthsea' } }
535
+ let(:expected) do
536
+ wrapped = Cuprum::Collections::Scope.new(value)
537
+
538
+ Cuprum::Collections::Scopes::DisjunctionScope.new(
539
+ scopes: [subject, wrapped]
540
+ )
541
+ end
542
+
543
+ it { expect(subject.or(value)).to be == expected }
544
+ end
545
+
546
+ wrap_deferred 'with an all scope' do
547
+ it { expect(subject.or(original)).to be == original }
548
+ end
549
+
550
+ wrap_deferred 'with a none scope' do
551
+ it { expect(subject.or(original)).to be subject }
552
+ end
553
+
554
+ wrap_deferred 'with an empty conjunction scope' do
555
+ it { expect(subject.or(original)).to be subject }
556
+ end
557
+
558
+ wrap_deferred 'with an empty criteria scope' do
559
+ it { expect(subject.or(original)).to be subject }
560
+ end
561
+
562
+ wrap_deferred 'with an empty disjunction scope' do
563
+ it { expect(subject.or(original)).to be subject }
564
+ end
565
+
566
+ wrap_deferred 'with a non-empty conjunction scope' do
567
+ let(:expected) do
568
+ Cuprum::Collections::Scopes::DisjunctionScope.new(
569
+ scopes: [subject, original]
570
+ )
571
+ end
572
+
573
+ it { expect(subject.or(original)).to be == expected }
574
+ end
575
+
576
+ wrap_deferred 'with a non-empty criteria scope' do
577
+ let(:expected) do
578
+ Cuprum::Collections::Scopes::DisjunctionScope.new(
579
+ scopes: [subject, original]
580
+ )
581
+ end
582
+
583
+ it { expect(subject.or(original)).to be == expected }
584
+ end
585
+
586
+ wrap_deferred 'with a non-empty disjunction scope' do
587
+ let(:expected) do
588
+ Cuprum::Collections::Scopes::DisjunctionScope.new(
589
+ scopes: [subject, *original.scopes]
590
+ )
591
+ end
592
+
593
+ it { expect(subject.or(original)).to be == expected }
594
+ end
595
+ end
596
+ end
597
+ end
598
+ end