cuprum-collections 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/DEVELOPMENT.md +2 -2
- data/README.md +13 -11
- data/lib/cuprum/collections/association.rb +256 -0
- data/lib/cuprum/collections/associations/belongs_to.rb +32 -0
- data/lib/cuprum/collections/associations/has_many.rb +23 -0
- data/lib/cuprum/collections/associations/has_one.rb +23 -0
- data/lib/cuprum/collections/associations.rb +10 -0
- data/lib/cuprum/collections/basic/collection.rb +39 -74
- data/lib/cuprum/collections/basic/commands/find_many.rb +1 -1
- data/lib/cuprum/collections/basic/commands/find_matching.rb +1 -1
- data/lib/cuprum/collections/basic/repository.rb +9 -33
- data/lib/cuprum/collections/basic.rb +1 -0
- data/lib/cuprum/collections/collection.rb +154 -0
- data/lib/cuprum/collections/commands/associations/find_many.rb +161 -0
- data/lib/cuprum/collections/commands/associations/require_many.rb +48 -0
- data/lib/cuprum/collections/commands/associations.rb +13 -0
- data/lib/cuprum/collections/commands/find_one_matching.rb +1 -1
- data/lib/cuprum/collections/commands.rb +1 -0
- data/lib/cuprum/collections/errors/abstract_find_error.rb +1 -1
- data/lib/cuprum/collections/relation.rb +401 -0
- data/lib/cuprum/collections/repository.rb +71 -4
- data/lib/cuprum/collections/resource.rb +65 -0
- data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +2137 -0
- data/lib/cuprum/collections/rspec/contracts/basic/command_contracts.rb +484 -0
- data/lib/cuprum/collections/rspec/contracts/basic.rb +11 -0
- data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +429 -0
- data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +1462 -0
- data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +1093 -0
- data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +1381 -0
- data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +605 -0
- data/lib/cuprum/collections/rspec/contracts.rb +23 -0
- data/lib/cuprum/collections/rspec/fixtures.rb +85 -82
- data/lib/cuprum/collections/rspec.rb +4 -1
- data/lib/cuprum/collections/version.rb +1 -1
- data/lib/cuprum/collections.rb +9 -4
- metadata +23 -19
- data/lib/cuprum/collections/base.rb +0 -11
- data/lib/cuprum/collections/basic/rspec/command_contract.rb +0 -392
- data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +0 -168
- data/lib/cuprum/collections/rspec/build_one_command_contract.rb +0 -93
- data/lib/cuprum/collections/rspec/collection_contract.rb +0 -190
- data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +0 -108
- data/lib/cuprum/collections/rspec/find_many_command_contract.rb +0 -407
- data/lib/cuprum/collections/rspec/find_matching_command_contract.rb +0 -194
- data/lib/cuprum/collections/rspec/find_one_command_contract.rb +0 -157
- data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +0 -84
- data/lib/cuprum/collections/rspec/query_builder_contract.rb +0 -92
- data/lib/cuprum/collections/rspec/query_contract.rb +0 -650
- data/lib/cuprum/collections/rspec/querying_contract.rb +0 -298
- data/lib/cuprum/collections/rspec/repository_contract.rb +0 -235
- data/lib/cuprum/collections/rspec/update_one_command_contract.rb +0 -80
- 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
|