cuprum-collections 0.5.1 → 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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/lib/cuprum/collections/adaptable/collection.rb +18 -0
  4. data/lib/cuprum/collections/adaptable/command.rb +22 -0
  5. data/lib/cuprum/collections/adaptable/commands/abstract_assign_one.rb +27 -0
  6. data/lib/cuprum/collections/adaptable/commands/abstract_build_one.rb +25 -0
  7. data/lib/cuprum/collections/adaptable/commands/abstract_validate_one.rb +35 -0
  8. data/lib/cuprum/collections/adaptable/commands.rb +15 -0
  9. data/lib/cuprum/collections/adaptable/query.rb +64 -0
  10. data/lib/cuprum/collections/adaptable.rb +13 -0
  11. data/lib/cuprum/collections/adapter.rb +300 -0
  12. data/lib/cuprum/collections/adapters/data_adapter.rb +82 -0
  13. data/lib/cuprum/collections/adapters/entity_adapter.rb +76 -0
  14. data/lib/cuprum/collections/adapters/hash_adapter.rb +48 -0
  15. data/lib/cuprum/collections/adapters.rb +14 -0
  16. data/lib/cuprum/collections/basic/collection.rb +2 -20
  17. data/lib/cuprum/collections/basic/commands/destroy_one.rb +1 -1
  18. data/lib/cuprum/collections/basic/commands/find_many.rb +0 -31
  19. data/lib/cuprum/collections/basic/commands/find_matching.rb +0 -94
  20. data/lib/cuprum/collections/basic/commands/find_one.rb +0 -18
  21. data/lib/cuprum/collections/basic/commands/insert_one.rb +1 -1
  22. data/lib/cuprum/collections/basic/commands/update_one.rb +1 -1
  23. data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +36 -21
  24. data/lib/cuprum/collections/basic.rb +6 -5
  25. data/lib/cuprum/collections/collection.rb +6 -0
  26. data/lib/cuprum/collections/collection_command.rb +1 -1
  27. data/lib/cuprum/collections/commands/abstract_find_many.rb +40 -3
  28. data/lib/cuprum/collections/commands/abstract_find_matching.rb +102 -0
  29. data/lib/cuprum/collections/commands/abstract_find_one.rb +23 -1
  30. data/lib/cuprum/collections/commands/associations/find_many.rb +1 -3
  31. data/lib/cuprum/collections/commands/associations/require_many.rb +1 -1
  32. data/lib/cuprum/collections/commands/find_one_matching.rb +10 -10
  33. data/lib/cuprum/collections/commands/query_command.rb +6 -4
  34. data/lib/cuprum/collections/commands/upsert.rb +0 -2
  35. data/lib/cuprum/collections/constraints/order/attributes_array.rb +5 -4
  36. data/lib/cuprum/collections/constraints/order/attributes_hash.rb +5 -4
  37. data/lib/cuprum/collections/constraints/order/sort_direction.rb +2 -2
  38. data/lib/cuprum/collections/constraints/ordering.rb +11 -9
  39. data/lib/cuprum/collections/constraints/query_hash.rb +2 -2
  40. data/lib/cuprum/collections/errors/abstract_find_error.rb +101 -23
  41. data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
  42. data/lib/cuprum/collections/errors/failed_validation.rb +3 -3
  43. data/lib/cuprum/collections/errors/missing_default_contract.rb +12 -4
  44. data/lib/cuprum/collections/queries.rb +4 -0
  45. data/lib/cuprum/collections/relation.rb +0 -2
  46. data/lib/cuprum/collections/relations/parameters.rb +120 -68
  47. data/lib/cuprum/collections/repository.rb +71 -6
  48. data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +23 -4
  49. data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +18 -0
  50. data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +51 -0
  51. data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +10 -0
  52. data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +8 -0
  53. data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +18 -366
  54. data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +30 -0
  55. data/lib/cuprum/collections/rspec/contracts/scopes.rb +2 -0
  56. data/lib/cuprum/collections/rspec/contracts.rb +2 -10
  57. data/lib/cuprum/collections/rspec/deferred/adapter_examples.rb +1077 -0
  58. data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +27 -7
  59. data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +4 -4
  60. data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +2 -2
  61. data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +2 -2
  62. data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +5 -5
  63. data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +45 -12
  64. data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +2 -2
  65. data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +1 -1
  66. data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +1 -1
  67. data/lib/cuprum/collections/rspec/deferred/query_examples.rb +930 -0
  68. data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +48 -17
  69. data/lib/cuprum/collections/rspec/deferred/repository_examples.rb +961 -0
  70. data/lib/cuprum/collections/rspec/deferred/scope_examples.rb +598 -0
  71. data/lib/cuprum/collections/rspec/deferred/scopes/all_examples.rb +391 -0
  72. data/lib/cuprum/collections/rspec/deferred/scopes/builder_examples.rb +857 -0
  73. data/lib/cuprum/collections/rspec/deferred/scopes/composition_examples.rb +93 -0
  74. data/lib/cuprum/collections/rspec/deferred/scopes/conjunction_examples.rb +438 -0
  75. data/lib/cuprum/collections/rspec/deferred/scopes/criteria_examples.rb +1941 -0
  76. data/lib/cuprum/collections/rspec/deferred/scopes/disjunction_examples.rb +415 -0
  77. data/lib/cuprum/collections/rspec/deferred/scopes/none_examples.rb +385 -0
  78. data/lib/cuprum/collections/rspec/deferred/scopes/parser_examples.rb +740 -0
  79. data/lib/cuprum/collections/rspec/deferred/scopes.rb +8 -0
  80. data/lib/cuprum/collections/scope.rb +2 -2
  81. data/lib/cuprum/collections/scopes/container.rb +5 -4
  82. data/lib/cuprum/collections/scopes/criteria/parser.rb +24 -48
  83. data/lib/cuprum/collections/scopes/criteria.rb +7 -6
  84. data/lib/cuprum/collections/version.rb +4 -4
  85. data/lib/cuprum/collections.rb +5 -1
  86. metadata +47 -11
  87. data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +0 -2127
  88. data/lib/cuprum/collections/rspec/contracts/basic.rb +0 -11
  89. data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +0 -387
  90. data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +0 -169
  91. data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +0 -1264
@@ -1,1264 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cuprum/collections/rspec/contracts'
4
-
5
- module Cuprum::Collections::RSpec::Contracts
6
- # Contracts for asserting on Relation objects.
7
- #
8
- # @deprecated 0.5.0 Relation contracts are deprecated. Use
9
- # Deferred::RelationExamples instead.
10
- module RelationContracts
11
- # Contract asserting that the method validates the required parameters.
12
- module ShouldValidateTheParametersContract
13
- extend RSpec::SleepingKingStudios::Contract
14
-
15
- # @!method apply(example_group)
16
- # Adds the contract to the example group.
17
- #
18
- # @param example_group [RSpec::Core::ExampleGroup] the example group to
19
- # which the contract is applied.
20
- contract do
21
- describe 'with no parameters' do
22
- let(:error_message) { "name or entity class can't be blank" }
23
-
24
- it 'should raise an exception' do
25
- expect { call_method }
26
- .to raise_error ArgumentError, error_message
27
- end
28
- end
29
-
30
- describe 'with entity_class: nil' do
31
- let(:error_message) { "name or entity class can't be blank" }
32
-
33
- it 'should raise an exception' do
34
- expect { call_method(entity_class: nil) }
35
- .to raise_error ArgumentError, error_message
36
- end
37
- end
38
-
39
- describe 'with entity_class: an Object' do
40
- let(:error_message) do
41
- 'entity class is not a Class, a String or a Symbol'
42
- end
43
-
44
- it 'should raise an exception' do
45
- expect do
46
- call_method(entity_class: Object.new.freeze)
47
- end
48
- .to raise_error ArgumentError, error_message
49
- end
50
- end
51
-
52
- describe 'with entity_class: an empty String' do
53
- let(:error_message) { "entity class can't be blank" }
54
-
55
- it 'should raise an exception' do
56
- expect { call_method(entity_class: '') }
57
- .to raise_error ArgumentError, error_message
58
- end
59
- end
60
-
61
- describe 'with entity_class: an empty Symbol' do
62
- let(:error_message) { "entity class can't be blank" }
63
-
64
- it 'should raise an exception' do
65
- expect { call_method(entity_class: :'') }
66
- .to raise_error ArgumentError, error_message
67
- end
68
- end
69
-
70
- describe 'with name: nil' do
71
- let(:error_message) { "name or entity class can't be blank" }
72
-
73
- it 'should raise an exception' do
74
- expect { call_method(name: nil) }
75
- .to raise_error ArgumentError, error_message
76
- end
77
- end
78
-
79
- describe 'with name: nil and entity_class: value' do
80
- it 'should not raise an exception' do
81
- expect do
82
- call_method(entity_class: 'Book', name: nil)
83
- end
84
- .not_to raise_error
85
- end
86
- end
87
-
88
- describe 'with name: an Object' do
89
- let(:error_message) { 'name is not a String or a Symbol' }
90
-
91
- it 'should raise an exception' do
92
- expect { call_method(name: Object.new.freeze) }
93
- .to raise_error ArgumentError, error_message
94
- end
95
- end
96
-
97
- describe 'with name: an empty String' do
98
- let(:error_message) { "name can't be blank" }
99
-
100
- it 'should raise an exception' do
101
- expect { call_method(name: '') }
102
- .to raise_error ArgumentError, error_message
103
- end
104
- end
105
-
106
- describe 'with name: an empty Symbol' do
107
- let(:error_message) { "name can't be blank" }
108
-
109
- it 'should raise an exception' do
110
- expect { call_method(name: '') }
111
- .to raise_error ArgumentError, error_message
112
- end
113
- end
114
-
115
- describe 'with name: value and entity_class: nil' do
116
- it 'should not raise an exception' do
117
- expect do
118
- call_method(entity_class: 'Book', name: nil)
119
- end
120
- .not_to raise_error
121
- end
122
- end
123
-
124
- describe 'with name: value and entity_class: an Object' do
125
- let(:error_message) do
126
- 'entity class is not a Class, a String or a Symbol'
127
- end
128
-
129
- it 'should raise an exception' do
130
- expect do
131
- call_method(
132
- entity_class: Object.new.freeze,
133
- name: 'books'
134
- )
135
- end
136
- .to raise_error ArgumentError, error_message
137
- end
138
- end
139
-
140
- describe 'with name: value and entity_class: an empty String' do
141
- let(:error_message) { "entity class can't be blank" }
142
-
143
- it 'should raise an exception' do
144
- expect { call_method(entity_class: '', name: 'books') }
145
- .to raise_error ArgumentError, error_message
146
- end
147
- end
148
-
149
- describe 'with name: value and entity_class: an empty Symbol' do
150
- let(:error_message) { "entity class can't be blank" }
151
-
152
- it 'should raise an exception' do
153
- expect { call_method(entity_class: :'', name: 'books') }
154
- .to raise_error ArgumentError, error_message
155
- end
156
- end
157
-
158
- describe 'with plural_name: an Object' do
159
- let(:error_message) { 'plural name is not a String or a Symbol' }
160
-
161
- it 'should raise an exception' do
162
- expect do
163
- call_method(
164
- name: 'books',
165
- plural_name: Object.new.freeze
166
- )
167
- end
168
- .to raise_error ArgumentError, error_message
169
- end
170
- end
171
-
172
- describe 'with plural_name: an empty String' do
173
- let(:error_message) { "plural name can't be blank" }
174
-
175
- it 'should raise an exception' do
176
- expect do
177
- call_method(
178
- name: 'books',
179
- plural_name: ''
180
- )
181
- end
182
- .to raise_error ArgumentError, error_message
183
- end
184
- end
185
-
186
- describe 'with plural_name: an empty Symbol' do
187
- let(:error_message) { "plural name can't be blank" }
188
-
189
- it 'should raise an exception' do
190
- expect do
191
- call_method(
192
- name: 'books',
193
- plural_name: :''
194
- )
195
- end
196
- .to raise_error ArgumentError, error_message
197
- end
198
- end
199
-
200
- describe 'with qualified_name: an Object' do
201
- let(:error_message) { 'qualified name is not a String or a Symbol' }
202
-
203
- it 'should raise an exception' do
204
- expect do
205
- call_method(
206
- name: 'books',
207
- qualified_name: Object.new.freeze
208
- )
209
- end
210
- .to raise_error ArgumentError, error_message
211
- end
212
- end
213
-
214
- describe 'with qualified_name: an empty String' do
215
- let(:error_message) { "qualified name can't be blank" }
216
-
217
- it 'should raise an exception' do
218
- expect do
219
- call_method(
220
- name: 'books',
221
- qualified_name: ''
222
- )
223
- end
224
- .to raise_error ArgumentError, error_message
225
- end
226
- end
227
-
228
- describe 'with qualified_name: an empty Symbol' do
229
- let(:error_message) { "qualified name can't be blank" }
230
-
231
- it 'should raise an exception' do
232
- expect do
233
- call_method(
234
- name: 'books',
235
- qualified_name: :''
236
- )
237
- end
238
- .to raise_error ArgumentError, error_message
239
- end
240
- end
241
-
242
- describe 'with qualified_name: value and name, entity_class: nil' do
243
- it 'should not raise an exception' do
244
- expect do
245
- call_method(entity_class: nil, name: nil, qualified_name: 'books')
246
- end
247
- .not_to raise_error
248
- end
249
- end
250
-
251
- describe 'with singular_name: an Object' do
252
- let(:error_message) { 'singular name is not a String or a Symbol' }
253
-
254
- it 'should raise an exception' do
255
- expect do
256
- call_method(
257
- name: 'books',
258
- singular_name: Object.new.freeze
259
- )
260
- end
261
- .to raise_error ArgumentError, error_message
262
- end
263
- end
264
-
265
- describe 'with singular_name: an empty String' do
266
- let(:error_message) { "singular name can't be blank" }
267
-
268
- it 'should raise an exception' do
269
- expect do
270
- call_method(
271
- name: 'books',
272
- singular_name: ''
273
- )
274
- end
275
- .to raise_error ArgumentError, error_message
276
- end
277
- end
278
-
279
- describe 'with singular_name: an empty Symbol' do
280
- let(:error_message) { "singular name can't be blank" }
281
-
282
- it 'should raise an exception' do
283
- expect do
284
- call_method(
285
- name: 'books',
286
- singular_name: :''
287
- )
288
- end
289
- .to raise_error ArgumentError, error_message
290
- end
291
- end
292
- end
293
- end
294
-
295
- # Contract validating the behavior of a Relation.
296
- module ShouldBeARelationContract
297
- extend RSpec::SleepingKingStudios::Contract
298
-
299
- # @!method apply(example_group, **options)
300
- # Adds the contract to the example group.
301
- #
302
- # @param example_group [RSpec::Core::ExampleGroup] the example group to
303
- # which the contract is applied.
304
- # @param options [Hash] additional options for the contract.
305
- #
306
- # @option options cardinality [Boolean] true if the relation accepts
307
- # cardinality keywords (:plural, :singular); otherwise false.
308
- # @option options constructor [Boolean] if false, does not generate
309
- # constructor specs. Defaults to true.
310
- # @option options default_entity_class [Class] the default entity class
311
- # for the relation, if any.
312
- # @option options expected_keywords [Array<Symbol>] additional keywords
313
- # for the constructor.
314
- contract do |**options|
315
- include Cuprum::Collections::RSpec::Contracts::RelationContracts
316
-
317
- if options.fetch(:constructor, true)
318
- describe '.new' do
319
- let(:expected_keywords) do
320
- keywords = %i[
321
- entity_class
322
- name
323
- plural_name
324
- qualified_name
325
- singular_name
326
- ]
327
-
328
- keywords += %i[plural singular] if options[:cardinality]
329
-
330
- keywords + options.fetch(:expected_keywords, [])
331
- end
332
-
333
- def call_method(**parameters)
334
- described_class.new(**parameters)
335
- end
336
-
337
- it 'should define the constructor' do
338
- expect(described_class)
339
- .to be_constructible
340
- .with(0).arguments
341
- .and_keywords(*expected_keywords)
342
- .and_any_keywords
343
- end
344
-
345
- include_contract 'should validate the parameters'
346
- end
347
- end
348
-
349
- describe '#entity_class' do
350
- include_examples 'should define reader', :entity_class
351
-
352
- context 'when initialized with entity_class: a Class' do
353
- let(:entity_class) { Grimoire }
354
- let(:constructor_options) do
355
- super()
356
- .tap { |hsh| hsh.delete(:name) }
357
- .merge(entity_class:)
358
- end
359
-
360
- it { expect(subject.entity_class).to be Grimoire }
361
- end
362
-
363
- context 'when initialized with entity_class: a scoped Class' do
364
- let(:entity_class) { Spec::ScopedBook }
365
- let(:constructor_options) do
366
- super()
367
- .tap { |hsh| hsh.delete(:name) }
368
- .merge(entity_class:)
369
- end
370
-
371
- it { expect(subject.entity_class).to be Spec::ScopedBook }
372
- end
373
-
374
- context 'when initialized with entity_class: a String' do
375
- let(:entity_class) { 'Grimoire' }
376
- let(:constructor_options) do
377
- super()
378
- .tap { |hsh| hsh.delete(:name) }
379
- .merge(entity_class:)
380
- end
381
-
382
- it { expect(subject.entity_class).to be Grimoire }
383
- end
384
-
385
- context 'when initialized with entity_class: a scoped String' do
386
- let(:entity_class) { 'Spec::ScopedBook' }
387
- let(:constructor_options) do
388
- super()
389
- .tap { |hsh| hsh.delete(:name) }
390
- .merge(entity_class:)
391
- end
392
-
393
- it { expect(subject.entity_class).to be Spec::ScopedBook }
394
- end
395
-
396
- context 'when initialized with name: a String' do
397
- let(:name) { 'books' }
398
- let(:constructor_options) do
399
- super().merge(name:)
400
- end
401
- let(:expected) { options[:default_entity_class] || Book }
402
-
403
- it { expect(subject.entity_class).to be expected }
404
-
405
- context 'when initialized with entity_class: value' do
406
- let(:entity_class) { Grimoire }
407
- let(:constructor_options) do
408
- super()
409
- .tap { |hsh| hsh.delete(:name) }
410
- .merge(entity_class:)
411
- end
412
-
413
- it { expect(subject.entity_class).to be Grimoire }
414
- end
415
-
416
- context 'when initialized with qualified_name: value' do
417
- let(:qualified_name) { 'spec/scoped_books' }
418
- let(:constructor_options) do
419
- super().merge(qualified_name:)
420
- end
421
- let(:expected) do
422
- options[:default_entity_class] || Spec::ScopedBook
423
- end
424
-
425
- it { expect(subject.entity_class).to be expected }
426
-
427
- context 'when initialized with entity_class: value' do
428
- let(:entity_class) { Grimoire }
429
- let(:constructor_options) do
430
- super()
431
- .tap { |hsh| hsh.delete(:name) }
432
- .merge(entity_class:)
433
- end
434
-
435
- it { expect(subject.entity_class).to be Grimoire }
436
- end
437
- end
438
- end
439
-
440
- context 'when initialized with name: a Symbol' do
441
- let(:name) { 'books' }
442
- let(:constructor_options) do
443
- super().merge(name:)
444
- end
445
- let(:expected) { options[:default_entity_class] || Book }
446
-
447
- it { expect(subject.entity_class).to be expected }
448
-
449
- context 'when initialized with entity_class: value' do
450
- let(:entity_class) { Grimoire }
451
- let(:constructor_options) do
452
- super()
453
- .tap { |hsh| hsh.delete(:name) }
454
- .merge(entity_class:)
455
- end
456
-
457
- it { expect(subject.entity_class).to be Grimoire }
458
- end
459
-
460
- context 'when initialized with qualified_name: value' do
461
- let(:qualified_name) { 'spec/scoped_books' }
462
- let(:constructor_options) do
463
- super().merge(qualified_name:)
464
- end
465
- let(:expected) do
466
- options[:default_entity_class] || Spec::ScopedBook
467
- end
468
-
469
- it { expect(subject.entity_class).to be expected }
470
-
471
- context 'when initialized with entity_class: value' do
472
- let(:entity_class) { Grimoire }
473
- let(:constructor_options) do
474
- super()
475
- .tap { |hsh| hsh.delete(:name) }
476
- .merge(entity_class:)
477
- end
478
-
479
- it { expect(subject.entity_class).to be Grimoire }
480
- end
481
- end
482
- end
483
-
484
- context 'when initialized with qualified_name: a String' do
485
- let(:qualified_name) { 'spec/scoped_books' }
486
- let(:constructor_options) do
487
- super().merge(qualified_name:)
488
- end
489
- let(:expected) do
490
- options[:default_entity_class] || Spec::ScopedBook
491
- end
492
-
493
- it { expect(subject.entity_class).to be expected }
494
-
495
- context 'when initialized with entity_class: value' do
496
- let(:entity_class) { Grimoire }
497
- let(:constructor_options) do
498
- super()
499
- .tap { |hsh| hsh.delete(:name) }
500
- .merge(entity_class:)
501
- end
502
-
503
- it { expect(subject.entity_class).to be Grimoire }
504
- end
505
- end
506
-
507
- context 'when initialized with qualified_name: a Symbol' do
508
- let(:qualified_name) { :'spec/scoped_books' }
509
- let(:constructor_options) do
510
- super().merge(qualified_name:)
511
- end
512
- let(:expected) do
513
- options[:default_entity_class] || Spec::ScopedBook
514
- end
515
-
516
- it { expect(subject.entity_class).to be expected }
517
-
518
- context 'when initialized with entity_class: value' do
519
- let(:entity_class) { Grimoire }
520
- let(:constructor_options) do
521
- super()
522
- .tap { |hsh| hsh.delete(:name) }
523
- .merge(entity_class:)
524
- end
525
-
526
- it { expect(subject.entity_class).to be Grimoire }
527
- end
528
- end
529
- end
530
-
531
- describe '#plural_name' do
532
- include_examples 'should define reader', :plural_name
533
-
534
- context 'when initialized with entity_class: a Class' do
535
- let(:entity_class) { Grimoire }
536
- let(:constructor_options) do
537
- super()
538
- .tap { |hsh| hsh.delete(:name) }
539
- .merge(entity_class:)
540
- end
541
-
542
- it { expect(subject.plural_name).to be == 'grimoires' }
543
-
544
- context 'when initialized with plural_name: value' do
545
- let(:plural_name) { 'books' }
546
- let(:constructor_options) do
547
- super().merge(plural_name:)
548
- end
549
-
550
- it { expect(subject.plural_name).to be == plural_name }
551
- end
552
- end
553
-
554
- context 'when initialized with entity_class: a scoped Class' do
555
- let(:entity_class) { Spec::ScopedBook }
556
- let(:constructor_options) do
557
- super()
558
- .tap { |hsh| hsh.delete(:name) }
559
- .merge(entity_class:)
560
- end
561
-
562
- it { expect(subject.plural_name).to be == 'scoped_books' }
563
-
564
- context 'when initialized with plural_name: value' do
565
- let(:plural_name) { 'books' }
566
- let(:constructor_options) do
567
- super().merge(plural_name:)
568
- end
569
-
570
- it { expect(subject.plural_name).to be == plural_name }
571
- end
572
- end
573
-
574
- context 'when initialized with entity_class: a String' do
575
- let(:entity_class) { 'Grimoire' }
576
- let(:constructor_options) do
577
- super()
578
- .tap { |hsh| hsh.delete(:name) }
579
- .merge(entity_class:)
580
- end
581
-
582
- it { expect(subject.plural_name).to be == 'grimoires' }
583
-
584
- context 'when initialized with plural_name: value' do
585
- let(:plural_name) { 'books' }
586
- let(:constructor_options) do
587
- super().merge(plural_name:)
588
- end
589
-
590
- it { expect(subject.plural_name).to be == plural_name }
591
- end
592
- end
593
-
594
- context 'when initialized with entity_class: a scoped String' do
595
- let(:entity_class) { 'Spec::ScopedBook' }
596
- let(:constructor_options) do
597
- super()
598
- .tap { |hsh| hsh.delete(:name) }
599
- .merge(entity_class:)
600
- end
601
-
602
- it { expect(subject.plural_name).to be == 'scoped_books' }
603
-
604
- context 'when initialized with plural_name: value' do
605
- let(:plural_name) { 'books' }
606
- let(:constructor_options) do
607
- super().merge(plural_name:)
608
- end
609
-
610
- it { expect(subject.plural_name).to be == plural_name }
611
- end
612
- end
613
-
614
- context 'when initialized with name: a String' do
615
- let(:name) { 'grimoires' }
616
- let(:constructor_options) do
617
- super().merge(name:)
618
- end
619
-
620
- it { expect(subject.plural_name).to be == 'grimoires' }
621
-
622
- context 'when initialized with plural_name: value' do
623
- let(:plural_name) { 'books' }
624
- let(:constructor_options) do
625
- super().merge(plural_name:)
626
- end
627
-
628
- it { expect(subject.plural_name).to be == plural_name }
629
- end
630
- end
631
-
632
- context 'when initialized with name: a Symbol' do
633
- let(:name) { :grimoires }
634
- let(:constructor_options) do
635
- super().merge(name:)
636
- end
637
-
638
- it { expect(subject.plural_name).to be == 'grimoires' }
639
-
640
- context 'when initialized with plural_name: value' do
641
- let(:plural_name) { 'books' }
642
- let(:constructor_options) do
643
- super().merge(plural_name:)
644
- end
645
-
646
- it { expect(subject.plural_name).to be == plural_name }
647
- end
648
- end
649
- end
650
-
651
- describe '#singular_name' do
652
- include_examples 'should define reader', :singular_name
653
-
654
- context 'when initialized with entity_class: a Class' do
655
- let(:entity_class) { Grimoire }
656
- let(:constructor_options) do
657
- super()
658
- .tap { |hsh| hsh.delete(:name) }
659
- .merge(entity_class:)
660
- end
661
-
662
- it { expect(subject.singular_name).to be == 'grimoire' }
663
-
664
- context 'when initialized with singular_name: value' do
665
- let(:singular_name) { 'book' }
666
- let(:constructor_options) do
667
- super().merge(singular_name:)
668
- end
669
-
670
- it { expect(subject.singular_name).to be == singular_name }
671
- end
672
- end
673
-
674
- context 'when initialized with entity_class: a scoped Class' do
675
- let(:entity_class) { Spec::ScopedBook }
676
- let(:constructor_options) do
677
- super()
678
- .tap { |hsh| hsh.delete(:name) }
679
- .merge(entity_class:)
680
- end
681
-
682
- it { expect(subject.singular_name).to be == 'scoped_book' }
683
-
684
- context 'when initialized with singular_name: value' do
685
- let(:singular_name) { 'book' }
686
- let(:constructor_options) do
687
- super().merge(singular_name:)
688
- end
689
-
690
- it { expect(subject.singular_name).to be == singular_name }
691
- end
692
- end
693
-
694
- context 'when initialized with entity_class: a String' do
695
- let(:entity_class) { 'Grimoire' }
696
- let(:constructor_options) do
697
- super()
698
- .tap { |hsh| hsh.delete(:name) }
699
- .merge(entity_class:)
700
- end
701
-
702
- it { expect(subject.singular_name).to be == 'grimoire' }
703
-
704
- context 'when initialized with singular_name: value' do
705
- let(:singular_name) { 'book' }
706
- let(:constructor_options) do
707
- super().merge(singular_name:)
708
- end
709
-
710
- it { expect(subject.singular_name).to be == singular_name }
711
- end
712
- end
713
-
714
- context 'when initialized with entity_class: a scoped String' do
715
- let(:entity_class) { 'Spec::ScopedBook' }
716
- let(:constructor_options) do
717
- super()
718
- .tap { |hsh| hsh.delete(:name) }
719
- .merge(entity_class:)
720
- end
721
-
722
- it { expect(subject.singular_name).to be == 'scoped_book' }
723
-
724
- context 'when initialized with singular_name: value' do
725
- let(:singular_name) { 'book' }
726
- let(:constructor_options) do
727
- super().merge(singular_name:)
728
- end
729
-
730
- it { expect(subject.singular_name).to be == singular_name }
731
- end
732
- end
733
-
734
- context 'when initialized with name: a String' do
735
- let(:name) { 'grimoires' }
736
- let(:constructor_options) do
737
- super().merge(name:)
738
- end
739
-
740
- it { expect(subject.singular_name).to be == 'grimoire' }
741
-
742
- context 'when initialized with singular_name: value' do
743
- let(:singular_name) { 'book' }
744
- let(:constructor_options) do
745
- super().merge(singular_name:)
746
- end
747
-
748
- it { expect(subject.singular_name).to be == singular_name }
749
- end
750
- end
751
-
752
- context 'when initialized with name: a Symbol' do
753
- let(:name) { :grimoires }
754
- let(:constructor_options) do
755
- super().merge(name:)
756
- end
757
-
758
- it { expect(subject.singular_name).to be == 'grimoire' }
759
-
760
- context 'when initialized with singular_name: value' do
761
- let(:singular_name) { 'book' }
762
- let(:constructor_options) do
763
- super().merge(singular_name:)
764
- end
765
-
766
- it { expect(subject.singular_name).to be == singular_name }
767
- end
768
- end
769
- end
770
-
771
- describe '#name' do
772
- include_examples 'should define reader', :name
773
-
774
- context 'when initialized with entity_class: a Class' do
775
- let(:entity_class) { Grimoire }
776
- let(:constructor_options) do
777
- super()
778
- .tap { |hsh| hsh.delete(:name) }
779
- .merge(entity_class:)
780
- end
781
-
782
- it { expect(subject.name).to be == 'grimoires' }
783
-
784
- context 'when initialized with name: value' do
785
- let(:name) { 'books' }
786
- let(:constructor_options) do
787
- super().merge(name:)
788
- end
789
-
790
- it { expect(subject.name).to be == name }
791
- end
792
- end
793
-
794
- context 'when initialized with entity_class: a scoped Class' do
795
- let(:entity_class) { Spec::ScopedBook }
796
- let(:constructor_options) do
797
- super()
798
- .tap { |hsh| hsh.delete(:name) }
799
- .merge(entity_class:)
800
- end
801
-
802
- it { expect(subject.name).to be == 'scoped_books' }
803
-
804
- context 'when initialized with name: value' do
805
- let(:name) { 'books' }
806
- let(:constructor_options) do
807
- super().merge(name:)
808
- end
809
-
810
- it { expect(subject.name).to be == name }
811
- end
812
- end
813
-
814
- context 'when initialized with entity_class: a String' do
815
- let(:entity_class) { 'Grimoire' }
816
- let(:constructor_options) do
817
- super()
818
- .tap { |hsh| hsh.delete(:name) }
819
- .merge(entity_class:)
820
- end
821
-
822
- it { expect(subject.name).to be == 'grimoires' }
823
-
824
- context 'when initialized with name: value' do
825
- let(:name) { 'books' }
826
- let(:constructor_options) do
827
- super().merge(name:)
828
- end
829
-
830
- it { expect(subject.name).to be == name }
831
- end
832
- end
833
-
834
- context 'when initialized with entity_class: a scoped String' do
835
- let(:entity_class) { 'Spec::ScopedBook' }
836
- let(:constructor_options) do
837
- super()
838
- .tap { |hsh| hsh.delete(:name) }
839
- .merge(entity_class:)
840
- end
841
-
842
- it { expect(subject.name).to be == 'scoped_books' }
843
-
844
- context 'when initialized with name: value' do
845
- let(:name) { 'books' }
846
- let(:constructor_options) do
847
- super().merge(name:)
848
- end
849
-
850
- it { expect(subject.name).to be == name }
851
- end
852
- end
853
-
854
- context 'when initialized with name: a String' do
855
- let(:name) { 'books' }
856
- let(:constructor_options) do
857
- super().merge(name:)
858
- end
859
-
860
- it { expect(subject.name).to be == name }
861
- end
862
-
863
- context 'when initialized with name: a Symbol' do
864
- let(:name) { :books }
865
- let(:constructor_options) do
866
- super().merge(name:)
867
- end
868
-
869
- it { expect(subject.name).to be == name.to_s }
870
- end
871
- end
872
-
873
- describe '#options' do
874
- include_examples 'should define reader', :options, -> { {} }
875
-
876
- context 'when initialized with entity_class: value' do
877
- let(:entity_class) { Grimoire }
878
- let(:constructor_options) do
879
- super()
880
- .tap { |hsh| hsh.delete(:name) }
881
- .merge(entity_class:)
882
- end
883
-
884
- it { expect(subject.options).to be == {} }
885
- end
886
-
887
- context 'when initialized with singular_name: value' do
888
- let(:singular_name) { 'book' }
889
- let(:constructor_options) do
890
- super().merge(singular_name:)
891
- end
892
-
893
- it { expect(subject.options).to be == {} }
894
- end
895
-
896
- context 'when initialized with name: value' do
897
- let(:name) { 'books' }
898
- let(:constructor_options) do
899
- super().merge(name:)
900
- end
901
-
902
- it { expect(subject.options).to be == {} }
903
- end
904
-
905
- context 'when initialized with qualified_name: value' do
906
- let(:qualified_name) { 'spec/scoped_books' }
907
- let(:constructor_options) do
908
- super().merge(qualified_name:)
909
- end
910
-
911
- it { expect(subject.options).to be == {} }
912
- end
913
-
914
- context 'when initialized with options' do
915
- let(:options) { { custom_option: 'custom value' } }
916
- let(:constructor_options) do
917
- super().merge(options)
918
- end
919
-
920
- it { expect(subject.options).to be == options }
921
- end
922
- end
923
-
924
- describe '#qualified_name' do
925
- include_examples 'should define reader', :qualified_name
926
-
927
- context 'when initialized with entity_class: a Class' do
928
- let(:entity_class) { Grimoire }
929
- let(:constructor_options) do
930
- super()
931
- .tap { |hsh| hsh.delete(:name) }
932
- .merge(entity_class:)
933
- end
934
-
935
- it { expect(subject.qualified_name).to be == 'grimoires' }
936
-
937
- context 'when initialized with qualified_name: value' do
938
- let(:qualified_name) { 'path/to/books' }
939
- let(:constructor_options) do
940
- super().merge(qualified_name:)
941
- end
942
-
943
- it { expect(subject.qualified_name).to be == qualified_name }
944
- end
945
- end
946
-
947
- context 'when initialized with entity_class: a scoped Class' do
948
- let(:entity_class) { Spec::ScopedBook }
949
- let(:constructor_options) do
950
- super()
951
- .tap { |hsh| hsh.delete(:name) }
952
- .merge(entity_class:)
953
- end
954
-
955
- it { expect(subject.qualified_name).to be == 'spec/scoped_books' }
956
-
957
- context 'when initialized with qualified_name: value' do
958
- let(:qualified_name) { 'path/to/books' }
959
- let(:constructor_options) do
960
- super().merge(qualified_name:)
961
- end
962
-
963
- it { expect(subject.qualified_name).to be == qualified_name }
964
- end
965
- end
966
-
967
- context 'when initialized with entity_class: a String' do
968
- let(:entity_class) { 'Grimoire' }
969
- let(:constructor_options) do
970
- super()
971
- .tap { |hsh| hsh.delete(:name) }
972
- .merge(entity_class:)
973
- end
974
-
975
- it { expect(subject.qualified_name).to be == 'grimoires' }
976
-
977
- context 'when initialized with qualified_name: value' do
978
- let(:qualified_name) { 'path/to/books' }
979
- let(:constructor_options) do
980
- super().merge(qualified_name:)
981
- end
982
-
983
- it { expect(subject.qualified_name).to be == qualified_name }
984
- end
985
- end
986
-
987
- context 'when initialized with entity_class: a scoped String' do
988
- let(:entity_class) { 'Spec::ScopedBook' }
989
- let(:constructor_options) do
990
- super()
991
- .tap { |hsh| hsh.delete(:name) }
992
- .merge(entity_class:)
993
- end
994
-
995
- it { expect(subject.qualified_name).to be == 'spec/scoped_books' }
996
-
997
- context 'when initialized with qualified_name: value' do
998
- let(:qualified_name) { 'path/to/books' }
999
- let(:constructor_options) do
1000
- super().merge(qualified_name:)
1001
- end
1002
-
1003
- it { expect(subject.qualified_name).to be == qualified_name }
1004
- end
1005
- end
1006
-
1007
- context 'when initialized with name: a String' do
1008
- let(:name) { 'books' }
1009
- let(:constructor_options) do
1010
- super().merge(name:)
1011
- end
1012
-
1013
- it { expect(subject.qualified_name).to be == name }
1014
-
1015
- context 'when initialized with qualified_name: value' do
1016
- let(:qualified_name) { 'path/to/books' }
1017
- let(:constructor_options) do
1018
- super().merge(qualified_name:)
1019
- end
1020
-
1021
- it { expect(subject.qualified_name).to be == qualified_name }
1022
- end
1023
- end
1024
-
1025
- context 'when initialized with name: a Symbol' do
1026
- let(:name) { :books }
1027
- let(:constructor_options) do
1028
- super().merge(name:)
1029
- end
1030
-
1031
- it { expect(subject.qualified_name).to be == name.to_s }
1032
-
1033
- context 'when initialized with qualified_name: value' do
1034
- let(:qualified_name) { 'path/to/books' }
1035
- let(:constructor_options) do
1036
- super().merge(qualified_name:)
1037
- end
1038
-
1039
- it { expect(subject.qualified_name).to be == qualified_name }
1040
- end
1041
- end
1042
-
1043
- context 'when initialized with qualified_name: a String' do
1044
- let(:qualified_name) { 'path/to/books' }
1045
- let(:constructor_options) do
1046
- super().merge(qualified_name:)
1047
- end
1048
-
1049
- it { expect(subject.qualified_name).to be == qualified_name }
1050
- end
1051
-
1052
- context 'when initialized with qualified_name: a Symbol' do
1053
- let(:qualified_name) { :'path/to/books' }
1054
- let(:constructor_options) do
1055
- super().merge(qualified_name:)
1056
- end
1057
-
1058
- it { expect(subject.qualified_name).to be == qualified_name.to_s }
1059
- end
1060
- end
1061
- end
1062
- end
1063
-
1064
- # Contract validating a Relation's cardinality properties.
1065
- module ShouldDefineCardinalityContract
1066
- extend RSpec::SleepingKingStudios::Contract
1067
-
1068
- # @!method apply(example_group)
1069
- # Adds the contract to the example group.
1070
- #
1071
- # @param example_group [RSpec::Core::ExampleGroup] the example group to
1072
- # which the contract is applied.
1073
- contract do
1074
- describe '.new' do
1075
- describe 'with plural: an Object' do
1076
- let(:constructor_options) do
1077
- super().merge(plural: Object.new.freeze)
1078
- end
1079
- let(:error_message) do
1080
- 'plural must be true or false'
1081
- end
1082
-
1083
- it 'should raise an exception' do
1084
- expect { described_class.new(**constructor_options) }
1085
- .to raise_error ArgumentError, error_message
1086
- end
1087
- end
1088
-
1089
- describe 'with singular: an Object' do
1090
- let(:constructor_options) do
1091
- super().merge(singular: Object.new.freeze)
1092
- end
1093
- let(:error_message) do
1094
- 'singular must be true or false'
1095
- end
1096
-
1097
- it 'should raise an exception' do
1098
- expect { described_class.new(**constructor_options) }
1099
- .to raise_error ArgumentError, error_message
1100
- end
1101
- end
1102
-
1103
- describe 'with singular: nil and plural: value' do
1104
- let(:constructor_options) do
1105
- super().merge(plural: true, singular: nil)
1106
- end
1107
-
1108
- it 'should not raise an exception' do
1109
- expect { described_class.new(**constructor_options) }
1110
- .not_to raise_error
1111
- end
1112
- end
1113
-
1114
- describe 'with singular: value and plural: nil' do
1115
- let(:constructor_options) do
1116
- super().merge(plural: nil, singular: true)
1117
- end
1118
-
1119
- it 'should not raise an exception' do
1120
- expect { described_class.new(**constructor_options) }
1121
- .not_to raise_error
1122
- end
1123
- end
1124
-
1125
- describe 'with singular: value and plural: value' do
1126
- let(:constructor_options) do
1127
- super().merge(singular: true, plural: false)
1128
- end
1129
- let(:error_message) do
1130
- 'ambiguous cardinality: initialized with parameters ' \
1131
- 'plural: false and singular: true'
1132
- end
1133
-
1134
- it 'should raise an exception' do
1135
- expect { described_class.new(**constructor_options) }
1136
- .to raise_error ArgumentError, error_message
1137
- end
1138
- end
1139
- end
1140
-
1141
- describe '#plural?' do
1142
- include_examples 'should define predicate', :plural?, true
1143
-
1144
- context 'when initialized with plural: false' do
1145
- let(:constructor_options) { super().merge(plural: false) }
1146
-
1147
- it { expect(subject.plural?).to be false }
1148
- end
1149
-
1150
- context 'when initialized with plural: true' do
1151
- let(:constructor_options) { super().merge(plural: true) }
1152
-
1153
- it { expect(subject.plural?).to be true }
1154
- end
1155
-
1156
- context 'when initialized with singular: false' do
1157
- let(:constructor_options) { super().merge(singular: false) }
1158
-
1159
- it { expect(subject.plural?).to be true }
1160
- end
1161
-
1162
- context 'when initialized with singular: true' do
1163
- let(:constructor_options) { super().merge(singular: true) }
1164
-
1165
- it { expect(subject.plural?).to be false }
1166
- end
1167
- end
1168
-
1169
- describe '#singular?' do
1170
- include_examples 'should define predicate', :singular?, false
1171
-
1172
- context 'when initialized with plural: false' do
1173
- let(:constructor_options) { super().merge(plural: false) }
1174
-
1175
- it { expect(subject.singular?).to be true }
1176
- end
1177
-
1178
- context 'when initialized with plural: true' do
1179
- let(:constructor_options) { super().merge(plural: true) }
1180
-
1181
- it { expect(subject.singular?).to be false }
1182
- end
1183
-
1184
- context 'when initialized with singular: false' do
1185
- let(:constructor_options) { super().merge(singular: false) }
1186
-
1187
- it { expect(subject.singular?).to be false }
1188
- end
1189
-
1190
- context 'when initialized with singular: true' do
1191
- let(:constructor_options) { super().merge(singular: true) }
1192
-
1193
- it { expect(subject.singular?).to be true }
1194
- end
1195
- end
1196
- end
1197
- end
1198
-
1199
- # Contract validating a Relation's primary key properties.
1200
- module ShouldDefinePrimaryKeysContract
1201
- extend RSpec::SleepingKingStudios::Contract
1202
-
1203
- # @!method apply(example_group)
1204
- # Adds the contract to the example group.
1205
- #
1206
- # @param example_group [RSpec::Core::ExampleGroup] the example group to
1207
- # which the contract is applied.
1208
- contract do
1209
- describe '#primary_key_name' do
1210
- let(:expected_primary_key_name) do
1211
- return super() if defined?(super())
1212
-
1213
- constructor_options.fetch(:primary_key_name, 'id')
1214
- end
1215
-
1216
- include_examples 'should define reader',
1217
- :primary_key_name,
1218
- -> { expected_primary_key_name }
1219
-
1220
- context 'when initialized with primary_key_name: a String' do
1221
- let(:primary_key_name) { 'uuid' }
1222
- let(:constructor_options) do
1223
- super().merge(primary_key_name:)
1224
- end
1225
-
1226
- it { expect(subject.primary_key_name).to be == primary_key_name }
1227
- end
1228
-
1229
- context 'when initialized with primary_key_name: a Symbol' do
1230
- let(:primary_key_name) { :uuid }
1231
- let(:constructor_options) do
1232
- super().merge(primary_key_name:)
1233
- end
1234
-
1235
- it 'should set the primary key name' do
1236
- expect(subject.primary_key_name).to be == primary_key_name.to_s
1237
- end
1238
- end
1239
- end
1240
-
1241
- describe '#primary_key_type' do
1242
- let(:expected_primary_key_type) do
1243
- return super() if defined?(super())
1244
-
1245
- constructor_options.fetch(:primary_key_type, Integer)
1246
- end
1247
-
1248
- include_examples 'should define reader',
1249
- :primary_key_type,
1250
- -> { expected_primary_key_type }
1251
-
1252
- context 'when initialized with primary_key_type: value' do
1253
- let(:primary_key_type) { String }
1254
- let(:constructor_options) do
1255
- super().merge(primary_key_type:)
1256
- end
1257
-
1258
- it { expect(subject.primary_key_type).to be == primary_key_type }
1259
- end
1260
- end
1261
- end
1262
- end
1263
- end
1264
- end