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