cuprum-rails 0.1.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 +7 -0
- data/CHANGELOG.md +98 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/DEVELOPMENT.md +28 -0
- data/LICENSE +22 -0
- data/README.md +1045 -0
- data/lib/cuprum/rails/action.rb +45 -0
- data/lib/cuprum/rails/actions/create.rb +49 -0
- data/lib/cuprum/rails/actions/destroy.rb +22 -0
- data/lib/cuprum/rails/actions/edit.rb +22 -0
- data/lib/cuprum/rails/actions/index.rb +55 -0
- data/lib/cuprum/rails/actions/new.rb +19 -0
- data/lib/cuprum/rails/actions/resource_action.rb +75 -0
- data/lib/cuprum/rails/actions/show.rb +22 -0
- data/lib/cuprum/rails/actions/update.rb +59 -0
- data/lib/cuprum/rails/actions.rb +16 -0
- data/lib/cuprum/rails/collection.rb +115 -0
- data/lib/cuprum/rails/command.rb +137 -0
- data/lib/cuprum/rails/commands/assign_one.rb +66 -0
- data/lib/cuprum/rails/commands/build_one.rb +55 -0
- data/lib/cuprum/rails/commands/destroy_one.rb +43 -0
- data/lib/cuprum/rails/commands/find_many.rb +60 -0
- data/lib/cuprum/rails/commands/find_matching.rb +121 -0
- data/lib/cuprum/rails/commands/find_one.rb +50 -0
- data/lib/cuprum/rails/commands/insert_one.rb +41 -0
- data/lib/cuprum/rails/commands/update_one.rb +49 -0
- data/lib/cuprum/rails/commands/validate_one.rb +68 -0
- data/lib/cuprum/rails/commands.rb +18 -0
- data/lib/cuprum/rails/controller.rb +50 -0
- data/lib/cuprum/rails/controller_action.rb +121 -0
- data/lib/cuprum/rails/controllers/class_methods/actions.rb +57 -0
- data/lib/cuprum/rails/controllers/class_methods/configuration.rb +64 -0
- data/lib/cuprum/rails/controllers/class_methods/validations.rb +30 -0
- data/lib/cuprum/rails/controllers/class_methods.rb +15 -0
- data/lib/cuprum/rails/controllers/configuration.rb +53 -0
- data/lib/cuprum/rails/controllers.rb +10 -0
- data/lib/cuprum/rails/errors/missing_parameters.rb +33 -0
- data/lib/cuprum/rails/errors/missing_primary_key.rb +46 -0
- data/lib/cuprum/rails/errors/undefined_permitted_attributes.rb +34 -0
- data/lib/cuprum/rails/errors.rb +8 -0
- data/lib/cuprum/rails/map_errors.rb +44 -0
- data/lib/cuprum/rails/query.rb +77 -0
- data/lib/cuprum/rails/query_builder.rb +78 -0
- data/lib/cuprum/rails/repository.rb +44 -0
- data/lib/cuprum/rails/request.rb +105 -0
- data/lib/cuprum/rails/resource.rb +145 -0
- data/lib/cuprum/rails/responders/actions.rb +73 -0
- data/lib/cuprum/rails/responders/html/plural_resource.rb +62 -0
- data/lib/cuprum/rails/responders/html/singular_resource.rb +59 -0
- data/lib/cuprum/rails/responders/html.rb +11 -0
- data/lib/cuprum/rails/responders/html_responder.rb +129 -0
- data/lib/cuprum/rails/responders/json/resource.rb +60 -0
- data/lib/cuprum/rails/responders/json.rb +10 -0
- data/lib/cuprum/rails/responders/json_responder.rb +122 -0
- data/lib/cuprum/rails/responders/matching.rb +145 -0
- data/lib/cuprum/rails/responders/serialization.rb +36 -0
- data/lib/cuprum/rails/responders.rb +15 -0
- data/lib/cuprum/rails/responses/html/redirect_response.rb +29 -0
- data/lib/cuprum/rails/responses/html/render_response.rb +52 -0
- data/lib/cuprum/rails/responses/html.rb +11 -0
- data/lib/cuprum/rails/responses/json_response.rb +29 -0
- data/lib/cuprum/rails/responses.rb +11 -0
- data/lib/cuprum/rails/routes.rb +166 -0
- data/lib/cuprum/rails/routing/plural_routes.rb +26 -0
- data/lib/cuprum/rails/routing/singular_routes.rb +24 -0
- data/lib/cuprum/rails/routing.rb +11 -0
- data/lib/cuprum/rails/rspec/command_contract.rb +460 -0
- data/lib/cuprum/rails/rspec/define_route_contract.rb +84 -0
- data/lib/cuprum/rails/rspec.rb +8 -0
- data/lib/cuprum/rails/serializers/json/active_record_serializer.rb +24 -0
- data/lib/cuprum/rails/serializers/json/array_serializer.rb +40 -0
- data/lib/cuprum/rails/serializers/json/attributes_serializer.rb +217 -0
- data/lib/cuprum/rails/serializers/json/error_serializer.rb +24 -0
- data/lib/cuprum/rails/serializers/json/hash_serializer.rb +44 -0
- data/lib/cuprum/rails/serializers/json/identity_serializer.rb +21 -0
- data/lib/cuprum/rails/serializers/json/serializer.rb +66 -0
- data/lib/cuprum/rails/serializers/json.rb +40 -0
- data/lib/cuprum/rails/serializers.rb +10 -0
- data/lib/cuprum/rails/version.rb +59 -0
- data/lib/cuprum/rails.rb +31 -0
- metadata +286 -0
@@ -0,0 +1,460 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/rspec'
|
4
|
+
|
5
|
+
require 'support/book'
|
6
|
+
require 'support/tome'
|
7
|
+
|
8
|
+
module Cuprum::Rails::RSpec
|
9
|
+
# Contract validating the behavior of a Rails command implementation.
|
10
|
+
COMMAND_CONTRACT = lambda do
|
11
|
+
describe '.subclass' do
|
12
|
+
let(:subclass) { described_class.subclass }
|
13
|
+
let(:constructor_options) do
|
14
|
+
{
|
15
|
+
record_class: Book,
|
16
|
+
optional_key: 'optional value'
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should define the class method' do
|
21
|
+
expect(described_class)
|
22
|
+
.to respond_to(:subclass)
|
23
|
+
.with(0).arguments
|
24
|
+
.and_any_keywords
|
25
|
+
end
|
26
|
+
|
27
|
+
it { expect(subclass).to be_a Class }
|
28
|
+
|
29
|
+
it { expect(subclass).to be < described_class }
|
30
|
+
|
31
|
+
it 'should define the constructor' do
|
32
|
+
expect(subclass)
|
33
|
+
.to respond_to(:new)
|
34
|
+
.with(0).arguments
|
35
|
+
.and_any_keywords
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return the record class' do
|
39
|
+
expect(subclass.new(**constructor_options).record_class)
|
40
|
+
.to be record_class
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return the options' do
|
44
|
+
expect(subclass.new(**constructor_options).options)
|
45
|
+
.to be == { optional_key: 'optional value' }
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'with options' do
|
49
|
+
let(:default_options) do
|
50
|
+
{
|
51
|
+
record_class: Book,
|
52
|
+
custom_key: 'custom value'
|
53
|
+
}
|
54
|
+
end
|
55
|
+
let(:constructor_options) do
|
56
|
+
{
|
57
|
+
optional_key: 'optional value'
|
58
|
+
}
|
59
|
+
end
|
60
|
+
let(:subclass) { described_class.subclass(**default_options) }
|
61
|
+
|
62
|
+
it { expect(subclass).to be_a Class }
|
63
|
+
|
64
|
+
it { expect(subclass).to be < described_class }
|
65
|
+
|
66
|
+
it 'should define the constructor' do
|
67
|
+
expect(subclass)
|
68
|
+
.to respond_to(:new)
|
69
|
+
.with(0).arguments
|
70
|
+
.and_any_keywords
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should return the record class' do
|
74
|
+
expect(subclass.new(**constructor_options).record_class)
|
75
|
+
.to be record_class
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should return the options' do
|
79
|
+
expect(subclass.new(**constructor_options).options)
|
80
|
+
.to be == {
|
81
|
+
custom_key: 'custom value',
|
82
|
+
optional_key: 'optional value'
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#collection_name' do
|
89
|
+
let(:expected) { record_class.name.underscore.pluralize }
|
90
|
+
|
91
|
+
include_examples 'should define reader',
|
92
|
+
:collection_name,
|
93
|
+
-> { be == expected }
|
94
|
+
|
95
|
+
context 'when initialized with collection_name: string' do
|
96
|
+
let(:collection_name) { 'books' }
|
97
|
+
let(:constructor_options) do
|
98
|
+
super().merge(collection_name: collection_name)
|
99
|
+
end
|
100
|
+
|
101
|
+
it { expect(command.collection_name).to be == collection_name }
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when initialized with collection_name: symbol' do
|
105
|
+
let(:collection_name) { :books }
|
106
|
+
let(:constructor_options) do
|
107
|
+
super().merge(collection_name: collection_name)
|
108
|
+
end
|
109
|
+
|
110
|
+
it { expect(command.collection_name).to be == collection_name.to_s }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#member_name' do
|
115
|
+
def tools
|
116
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
117
|
+
end
|
118
|
+
|
119
|
+
include_examples 'should have reader',
|
120
|
+
:member_name,
|
121
|
+
-> { record_class.name.underscore }
|
122
|
+
|
123
|
+
context 'when initialized with collection_name: value' do
|
124
|
+
let(:collection_name) { :books }
|
125
|
+
|
126
|
+
it 'should return the singular collection name' do
|
127
|
+
expect(command.member_name)
|
128
|
+
.to be == tools.str.singularize(collection_name.to_s)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when initialized with member_name: string' do
|
133
|
+
let(:member_name) { 'tome' }
|
134
|
+
let(:constructor_options) { super().merge(member_name: member_name) }
|
135
|
+
|
136
|
+
it 'should return the singular collection name' do
|
137
|
+
expect(command.member_name).to be member_name
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when initialized with member_name: symbol' do
|
142
|
+
let(:member_name) { :tome }
|
143
|
+
let(:constructor_options) { super().merge(member_name: member_name) }
|
144
|
+
|
145
|
+
it 'should return the singular collection name' do
|
146
|
+
expect(command.member_name).to be == member_name.to_s
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#options' do
|
152
|
+
let(:expected_options) do
|
153
|
+
defined?(super()) ? super() : constructor_options
|
154
|
+
end
|
155
|
+
|
156
|
+
include_examples 'should define reader',
|
157
|
+
:options,
|
158
|
+
-> { be == expected_options }
|
159
|
+
|
160
|
+
context 'when initialized with options' do
|
161
|
+
let(:constructor_options) { super().merge({ key: 'value' }) }
|
162
|
+
let(:expected_options) { super().merge({ key: 'value' }) }
|
163
|
+
|
164
|
+
it { expect(command.options).to be == expected_options }
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#primary_key_name' do
|
169
|
+
include_examples 'should define reader', :primary_key_name, :id
|
170
|
+
|
171
|
+
context 'with a record class with custom primary key' do
|
172
|
+
let(:record_class) { Tome }
|
173
|
+
|
174
|
+
include_examples 'should define reader', :primary_key_name, :uuid
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '#primary_key_type' do
|
179
|
+
include_examples 'should define reader', :primary_key_type, Integer
|
180
|
+
|
181
|
+
context 'with a record class with custom primary key' do
|
182
|
+
let(:record_class) { Tome }
|
183
|
+
|
184
|
+
include_examples 'should define reader', :primary_key_type, String
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#record_class' do
|
189
|
+
include_examples 'should define reader',
|
190
|
+
:record_class,
|
191
|
+
-> { record_class }
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#validate_entity' do
|
195
|
+
let(:expected_error) do
|
196
|
+
type = record_class
|
197
|
+
contract = Stannum::Contracts::ParametersContract.new do
|
198
|
+
keyword :entity, type
|
199
|
+
end
|
200
|
+
errors = contract.errors_for(
|
201
|
+
{
|
202
|
+
arguments: [],
|
203
|
+
block: nil,
|
204
|
+
keywords: { entity: nil }
|
205
|
+
}
|
206
|
+
)
|
207
|
+
|
208
|
+
Cuprum::Collections::Errors::InvalidParameters.new(
|
209
|
+
command: command,
|
210
|
+
errors: errors
|
211
|
+
)
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should define the private method' do
|
215
|
+
expect(command)
|
216
|
+
.to respond_to(:validate_entity, true)
|
217
|
+
.with(1).argument
|
218
|
+
end
|
219
|
+
|
220
|
+
describe 'with nil' do
|
221
|
+
it 'should return a failing result' do
|
222
|
+
expect(command.send(:validate_entity, nil))
|
223
|
+
.to be_a_failing_result
|
224
|
+
.with_error(expected_error)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe 'with an Object' do
|
229
|
+
it 'should return a failing result' do
|
230
|
+
expect(command.send(:validate_entity, Object.new.freeze))
|
231
|
+
.to be_a_failing_result
|
232
|
+
.with_error(expected_error)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe 'with an invalid record instance' do
|
237
|
+
it 'should return a failing result' do
|
238
|
+
expect(command.send(:validate_entity, Tome.new))
|
239
|
+
.to be_a_failing_result
|
240
|
+
.with_error(expected_error)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe 'with a valid record instance' do
|
245
|
+
it 'should not return a result' do
|
246
|
+
expect(command.send(:validate_entity, Book.new))
|
247
|
+
.not_to be_a_result
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe '#validate_primary_key' do
|
253
|
+
let(:primary_key_type) { Integer }
|
254
|
+
let(:expected_error) do
|
255
|
+
type = primary_key_type
|
256
|
+
contract = Stannum::Contracts::ParametersContract.new do
|
257
|
+
keyword :primary_key, type
|
258
|
+
end
|
259
|
+
errors = contract.errors_for(
|
260
|
+
{
|
261
|
+
arguments: [],
|
262
|
+
block: nil,
|
263
|
+
keywords: { primary_key: nil }
|
264
|
+
}
|
265
|
+
)
|
266
|
+
|
267
|
+
Cuprum::Collections::Errors::InvalidParameters.new(
|
268
|
+
command: command,
|
269
|
+
errors: errors
|
270
|
+
)
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should define the private method' do
|
274
|
+
expect(command)
|
275
|
+
.to respond_to(:validate_primary_key, true)
|
276
|
+
.with(1).argument
|
277
|
+
end
|
278
|
+
|
279
|
+
describe 'with nil' do
|
280
|
+
it 'should return a failing result' do
|
281
|
+
expect(command.send(:validate_primary_key, nil))
|
282
|
+
.to be_a_failing_result
|
283
|
+
.with_error(expected_error)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe 'with an Object' do
|
288
|
+
it 'should return a failing result' do
|
289
|
+
expect(command.send(:validate_primary_key, Object.new.freeze))
|
290
|
+
.to be_a_failing_result
|
291
|
+
.with_error(expected_error)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe 'with a String' do
|
296
|
+
it 'should return a failing result' do
|
297
|
+
expect(command.send(:validate_primary_key, '12345'))
|
298
|
+
.to be_a_failing_result
|
299
|
+
.with_error(expected_error)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
describe 'with an Integer' do
|
304
|
+
it 'should not return a result' do
|
305
|
+
expect(command.send(:validate_primary_key, 12_345)).not_to be_a_result
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context 'with a record class with custom primary key' do
|
310
|
+
let(:record_class) { Tome }
|
311
|
+
let(:primary_key_type) { String }
|
312
|
+
|
313
|
+
describe 'with an Integer' do
|
314
|
+
it 'should return a failing result' do
|
315
|
+
expect(command.send(:validate_primary_key, 12_345))
|
316
|
+
.to be_a_failing_result
|
317
|
+
.with_error(expected_error)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
describe 'with a String' do
|
322
|
+
it 'should not return a result' do
|
323
|
+
expect(command.send(:validate_primary_key, '12345'))
|
324
|
+
.not_to be_a_result
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe '#validate_primary_keys' do
|
331
|
+
let(:primary_keys) { nil }
|
332
|
+
let(:primary_key_type) { Integer }
|
333
|
+
let(:expected_error) do
|
334
|
+
type = primary_key_type
|
335
|
+
contract = Stannum::Contracts::ParametersContract.new do
|
336
|
+
keyword :primary_keys,
|
337
|
+
Stannum::Constraints::Types::ArrayType.new(item_type: type)
|
338
|
+
end
|
339
|
+
errors = contract.errors_for(
|
340
|
+
{
|
341
|
+
arguments: [],
|
342
|
+
block: nil,
|
343
|
+
keywords: { primary_keys: primary_keys }
|
344
|
+
}
|
345
|
+
)
|
346
|
+
|
347
|
+
Cuprum::Collections::Errors::InvalidParameters.new(
|
348
|
+
command: command,
|
349
|
+
errors: errors
|
350
|
+
)
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'should define the private method' do
|
354
|
+
expect(command)
|
355
|
+
.to respond_to(:validate_primary_keys, true)
|
356
|
+
.with(1).argument
|
357
|
+
end
|
358
|
+
|
359
|
+
describe 'with nil' do
|
360
|
+
it 'should return a failing result' do
|
361
|
+
expect(command.send(:validate_primary_keys, nil))
|
362
|
+
.to be_a_failing_result
|
363
|
+
.with_error(expected_error)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
describe 'with an Object' do
|
368
|
+
it 'should return a failing result' do
|
369
|
+
expect(command.send(:validate_primary_keys, Object.new.freeze))
|
370
|
+
.to be_a_failing_result
|
371
|
+
.with_error(expected_error)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
describe 'with a String' do
|
376
|
+
it 'should return a failing result' do
|
377
|
+
expect(command.send(:validate_primary_keys, '12345'))
|
378
|
+
.to be_a_failing_result
|
379
|
+
.with_error(expected_error)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
describe 'with an Integer' do
|
384
|
+
it 'should return a failing result' do
|
385
|
+
expect(command.send(:validate_primary_keys, 12_345))
|
386
|
+
.to be_a_failing_result
|
387
|
+
.with_error(expected_error)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe 'with an empty Array' do
|
392
|
+
it 'should not return a result' do
|
393
|
+
expect(command.send(:validate_primary_keys, []))
|
394
|
+
.not_to be_a_result
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
describe 'with an Array with nil values' do
|
399
|
+
let(:primary_keys) { Array.new(3, nil) }
|
400
|
+
|
401
|
+
it 'should return a failing result' do
|
402
|
+
expect(command.send(:validate_primary_keys, primary_keys))
|
403
|
+
.to be_a_failing_result
|
404
|
+
.with_error(expected_error)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
describe 'with an Array with Object values' do
|
409
|
+
let(:primary_keys) { Array.new(3) { Object.new.freeze } }
|
410
|
+
|
411
|
+
it 'should return a failing result' do
|
412
|
+
expect(command.send(:validate_primary_keys, primary_keys))
|
413
|
+
.to be_a_failing_result
|
414
|
+
.with_error(expected_error)
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
describe 'with an Array with String values' do
|
419
|
+
let(:primary_keys) { %w[ichi ni san] }
|
420
|
+
|
421
|
+
it 'should return a failing result' do
|
422
|
+
expect(command.send(:validate_primary_keys, primary_keys))
|
423
|
+
.to be_a_failing_result
|
424
|
+
.with_error(expected_error)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
describe 'with an Array with Integer values' do
|
429
|
+
it 'should not return a result' do
|
430
|
+
expect(command.send(:validate_primary_keys, [0, 1, 2]))
|
431
|
+
.not_to be_a_result
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
context 'with a record class with custom primary key' do
|
436
|
+
let(:record_class) { Tome }
|
437
|
+
let(:primary_key_type) { String }
|
438
|
+
|
439
|
+
describe 'with an Array with String values' do
|
440
|
+
let(:primary_keys) { %w[ichi ni san] }
|
441
|
+
|
442
|
+
it 'should not return a result' do
|
443
|
+
expect(command.send(:validate_primary_keys, primary_keys))
|
444
|
+
.not_to be_a_result
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
describe 'with an Array with Integer values' do
|
449
|
+
let(:primary_keys) { [0, 1, 2] }
|
450
|
+
|
451
|
+
it 'should return a failing result' do
|
452
|
+
expect(command.send(:validate_primary_keys, primary_keys))
|
453
|
+
.to be_a_failing_result
|
454
|
+
.with_error(expected_error)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/rspec'
|
4
|
+
|
5
|
+
module Cuprum::Rails::RSpec
|
6
|
+
# Contract asserting that a Routes object defines the given route.
|
7
|
+
DEFINE_ROUTE_CONTRACT = lambda \
|
8
|
+
do |action_name:, path:, member_action: false, wildcards: {}|
|
9
|
+
describe "##{action_name}_path" do
|
10
|
+
let(:method_name) { "#{action_name}_path" }
|
11
|
+
let(:expected) do
|
12
|
+
next path unless member_action
|
13
|
+
|
14
|
+
primary_key_name = entity.class.primary_key
|
15
|
+
primary_key_value = entity[primary_key_name]
|
16
|
+
|
17
|
+
path.sub(':id', primary_key_value.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
define_method(:route_helper) do
|
21
|
+
scoped = wildcards.empty? ? routes : routes.with_wildcards(wildcards)
|
22
|
+
|
23
|
+
if member_action
|
24
|
+
scoped.send(method_name, entity)
|
25
|
+
else
|
26
|
+
scoped.send(method_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should define the helper method' do
|
31
|
+
if member_action
|
32
|
+
expect(routes).to respond_to(method_name).with(1).argument
|
33
|
+
else
|
34
|
+
expect(routes).to respond_to(method_name).with(0).arguments
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return the route path' do
|
39
|
+
expect(route_helper).to be == expected
|
40
|
+
end
|
41
|
+
|
42
|
+
if member_action
|
43
|
+
describe 'when the entity is nil' do
|
44
|
+
let(:entity) { nil }
|
45
|
+
let(:error_message) { 'missing wildcard :id' }
|
46
|
+
|
47
|
+
it 'should raise an exception' do
|
48
|
+
expect { route_helper }
|
49
|
+
.to raise_error(
|
50
|
+
described_class::MissingWildcardError,
|
51
|
+
error_message
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
wildcards.each do |key, _|
|
58
|
+
wildcard = key.to_s.end_with?('_id') ? key.intern : :"#{key}_id"
|
59
|
+
|
60
|
+
describe "when the #{wildcard.inspect} wildcard is undefined" do
|
61
|
+
let(:error_message) { "missing wildcard #{wildcard.inspect}" }
|
62
|
+
|
63
|
+
define_method(:route_helper) do
|
64
|
+
scoped = routes.with_wildcards(wildcards.except(key))
|
65
|
+
|
66
|
+
if member_action
|
67
|
+
scoped.send(method_name, entity)
|
68
|
+
else
|
69
|
+
scoped.send(method_name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should raise an exception' do
|
74
|
+
expect { route_helper }
|
75
|
+
.to raise_error(
|
76
|
+
described_class::MissingWildcardError,
|
77
|
+
error_message
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/serializers/json'
|
4
|
+
require 'cuprum/rails/serializers/json/serializer'
|
5
|
+
|
6
|
+
module Cuprum::Rails::Serializers::Json
|
7
|
+
# Converts ActiveRecord record to JSON using the #as_json method.
|
8
|
+
class ActiveRecordSerializer < Cuprum::Rails::Serializers::Json::Serializer
|
9
|
+
# Converts the ActiveRecord record to JSON.
|
10
|
+
#
|
11
|
+
# Calls and returns the #as_json method of the record.
|
12
|
+
#
|
13
|
+
# @param record [ActiveRecord::Base] The record to convert to JSON.
|
14
|
+
#
|
15
|
+
# @return [Hash] a JSON-compatible representation of the record.
|
16
|
+
def call(record, **_)
|
17
|
+
unless record.is_a?(ActiveRecord::Base)
|
18
|
+
raise ArgumentError, 'object must be an ActiveRecord record'
|
19
|
+
end
|
20
|
+
|
21
|
+
record.as_json
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rails/serializers/json'
|
4
|
+
require 'cuprum/rails/serializers/json/serializer'
|
5
|
+
|
6
|
+
module Cuprum::Rails::Serializers::Json
|
7
|
+
# Converts Array data structures to JSON based on configured serializers.
|
8
|
+
class ArraySerializer < Cuprum::Rails::Serializers::Json::Serializer
|
9
|
+
# Converts the array to JSON using the given serializers.
|
10
|
+
#
|
11
|
+
# First, #call finds the best serializer from the :serializers Hash for each
|
12
|
+
# item in the Array. This is done by walking up the object class's ancestors
|
13
|
+
# to find the closest ancestor which is a key in the :serializers Hash. The
|
14
|
+
# corresponding value is then called with the object, and the results are
|
15
|
+
# combined into a new Array and returned.
|
16
|
+
#
|
17
|
+
# @param array [Array] The array to convert to JSON.
|
18
|
+
# @param serializers [Hash<Class, #call>] The serializers for different
|
19
|
+
# object types.
|
20
|
+
#
|
21
|
+
# @return [Array] a JSON-compatible representation of the array.
|
22
|
+
#
|
23
|
+
# @raise UndefinedSerializerError if there is no matching serializer for
|
24
|
+
# any of the items in the array.
|
25
|
+
def call(array, serializers:)
|
26
|
+
raise ArgumentError, 'object must be an Array' unless array.is_a?(Array)
|
27
|
+
|
28
|
+
array.map { |item| super(item, serializers: serializers) }
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def handle_recursion!(_object)
|
34
|
+
# Call serializes the items, not the array. Because the context changes,
|
35
|
+
# we don't need to check for recursion (unless the Array contains itself,
|
36
|
+
# in which case here there be dragons).
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|