cuprum-collections 0.3.0 → 0.4.0

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