interaktor 0.5.1 → 0.6.0.pre

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.
data/spec/support/lint.rb CHANGED
@@ -13,7 +13,7 @@ RSpec.shared_examples "lint" do |interaktor_class|
13
13
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class)
14
14
 
15
15
  expect {
16
- interaktor.call(baz: "wadus")
16
+ interaktor.call(foo: "bar")
17
17
  }.to raise_error(Interaktor::Error::UnknownAttributeError)
18
18
  end
19
19
 
@@ -133,464 +133,412 @@ RSpec.shared_examples "lint" do |interaktor_class|
133
133
  end
134
134
  end
135
135
 
136
- describe "#required_input_attributes" do
137
- it "returns the attributes" do
138
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
139
- input do
140
- required(:foo)
141
- required(:bar)
142
- optional(:baz)
143
- end
136
+ describe "input attributes" do
137
+ it "accepts an attribute definition block" do
138
+ interaktor = FakeInteraktor.build_interaktor("MyCoolFoo", type: interaktor_class) do
139
+ input { attribute :foo }
144
140
  end
145
141
 
146
- expect(interaktor.required_input_attributes).to contain_exactly(:foo, :bar)
147
- end
148
-
149
- it "returns empty array when not defined" do
150
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class)
142
+ result = interaktor.call(foo: "bar")
151
143
 
152
- expect(interaktor.required_input_attributes).to be_empty
144
+ expect(result.success?).to be true
145
+ expect { result.foo }.to raise_error(NoMethodError)
153
146
  end
154
- end
155
147
 
156
- describe "#optional_input_attributes" do
157
- it "returns the attributes" do
148
+ it "raises an exception when the attribute is required and not provided" do
158
149
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
159
150
  input do
160
- required(:foo)
161
- required(:bar)
162
- optional(:baz)
151
+ attribute :foo
152
+ validates :foo, presence: true
163
153
  end
164
154
  end
165
155
 
166
- expect(interaktor.optional_input_attributes).to contain_exactly(:baz)
167
- end
168
-
169
- it "returns empty array when not defined" do
170
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class)
171
-
172
- expect(interaktor.optional_input_attributes).to be_empty
156
+ expect {
157
+ interaktor.call!
158
+ }.to raise_error do |error|
159
+ expect(error).to be_an Interaktor::Error::AttributeValidationError
160
+ expect(error.validation_errors).to eq(
161
+ foo: ["can't be blank"]
162
+ )
163
+ end
173
164
  end
174
- end
175
165
 
176
- describe "#input_attributes" do
177
- it "returns both required and optional attributes" do
166
+ it "raises an exception for unknown provided attributes" do
178
167
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
179
- input do
180
- required(:foo)
181
- required(:bar)
182
- optional(:baz)
183
- end
168
+ input { attribute :foo }
184
169
  end
185
170
 
186
- expect(interaktor.input_attributes).to contain_exactly(:foo, :bar, :baz)
171
+ expect {
172
+ interaktor.call!(foo: "baz", bar: "unexpected")
173
+ }.to raise_error do |error|
174
+ expect(error).to be_an Interaktor::Error::UnknownAttributeError
175
+ expect(error.attribute).to eq "bar"
176
+ end
187
177
  end
188
- end
189
178
 
190
- describe "#required_success_attributes" do
191
- it "returns the attributes" do
179
+ it "allows provided optional attributes" do
192
180
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
193
- success do
194
- required(:foo)
195
- required(:bar)
196
- optional(:baz)
197
- end
181
+ input { attribute :foo }
198
182
  end
199
183
 
200
- expect(interaktor.required_success_attributes).to contain_exactly(:foo, :bar)
201
- end
184
+ result = interaktor.call(foo: "bar")
202
185
 
203
- it "returns empty array when not defined" do
204
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class)
205
-
206
- expect(interaktor.required_success_attributes).to be_empty
186
+ expect(result.success?).to be true
187
+ expect { result.foo }.to raise_error(NoMethodError)
207
188
  end
208
- end
209
189
 
210
- describe "#optional_success_attributes" do
211
- it "returns the attributes" do
190
+ it "allows missing optional attributes" do
212
191
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
213
- success do
214
- required(:foo)
215
- required(:bar)
216
- optional(:baz)
217
- end
192
+ input { attribute :foo }
218
193
  end
219
194
 
220
- expect(interaktor.optional_success_attributes).to contain_exactly(:baz)
221
- end
222
-
223
- it "returns empty array when not defined" do
224
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class)
195
+ result = interaktor.call
225
196
 
226
- expect(interaktor.optional_success_attributes).to be_empty
197
+ expect(result.success?).to be true
198
+ expect { result.foo }.to raise_error(NoMethodError)
227
199
  end
228
- end
229
200
 
230
- describe "#success_attributes" do
231
- it "returns both required and optional attributes" do
201
+ it "creates attribute getters" do
232
202
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
233
- success do
234
- required(:foo)
235
- required(:bar)
236
- optional(:baz)
237
- end
238
- end
239
-
240
- expect(interaktor.success_attributes).to contain_exactly(:foo, :bar, :baz)
241
- end
242
- end
203
+ input { attribute :foo }
243
204
 
244
- describe "#required_failure_attributes" do
245
- it "returns the attributes" do
246
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
247
- failure do
248
- required(:foo)
249
- required(:bar)
250
- optional(:baz)
205
+ def call
206
+ foo
251
207
  end
252
208
  end
253
209
 
254
- expect(interaktor.required_failure_attributes).to contain_exactly(:foo, :bar)
255
- end
210
+ result = interaktor.call(foo: "bar")
256
211
 
257
- it "returns empty array when not defined" do
258
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class)
259
-
260
- expect(interaktor.required_failure_attributes).to be_empty
212
+ expect(result.success?).to be true
213
+ expect { result.foo }.to raise_error(NoMethodError)
214
+ expect { result.bar }.to raise_error(NoMethodError)
261
215
  end
262
- end
263
216
 
264
- describe "#optional_failure_attributes" do
265
- it "returns the attributes" do
266
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
267
- failure do
268
- required(:foo)
269
- required(:bar)
270
- optional(:baz)
217
+ it "disallows specifically disallowed attribute names" do
218
+ expect {
219
+ FakeInteraktor.build_interaktor(type: interaktor_class) do
220
+ # 'errors' is one because it's the accessor for the ActiveModel::Errors
221
+ input { attribute :errors }
271
222
  end
272
- end
273
-
274
- expect(interaktor.optional_failure_attributes).to contain_exactly(:baz)
223
+ }.to raise_error(ArgumentError, /disallowed attribute name/i)
275
224
  end
276
225
 
277
- it "returns empty array when not defined" do
278
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class)
279
-
280
- expect(interaktor.optional_failure_attributes).to be_empty
281
- end
282
- end
283
-
284
- describe "#failure_attributes" do
285
- it "returns both required and optional attributes" do
286
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
287
- failure do
288
- required(:foo)
289
- required(:bar)
290
- optional(:baz)
226
+ it "raises an exception when input block is provided more than once" do
227
+ expect {
228
+ FakeInteraktor.build_interaktor(type: interaktor_class) do
229
+ input { attribute :foo }
230
+ input { attribute :bar }
291
231
  end
292
- end
293
-
294
- expect(interaktor.failure_attributes).to contain_exactly(:foo, :bar, :baz)
232
+ }.to raise_error "Input block already defined"
295
233
  end
296
234
  end
297
235
 
298
- describe "input attributes" do
299
- it "accepts a schema object" do
236
+ describe "success attributes" do
237
+ it "accepts an attribute definition block" do
300
238
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
301
- input(Dry::Schema.Params { required(:bar).filled(:string) })
302
- end
239
+ success { attribute :foo }
303
240
 
304
- expect(interaktor.input_schema).to be_a Dry::Schema::Params
305
- expect(interaktor.required_input_attributes).to contain_exactly(:bar)
306
-
307
- result = interaktor.call(bar: "baz")
308
-
309
- expect(result.success?).to be true
310
- expect { result.bar }.to raise_error(NoMethodError)
311
- end
312
-
313
- it "accepts a schema definition block" do
314
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
315
- input { required(:bar).filled(:string) }
241
+ def call
242
+ success!(foo: "bar")
243
+ end
316
244
  end
317
245
 
318
- expect(interaktor.input_schema).to be_a Dry::Schema::Params
319
- expect(interaktor.required_input_attributes).to contain_exactly(:bar)
320
-
321
- result = interaktor.call(bar: "baz")
246
+ result = interaktor.call
322
247
 
323
248
  expect(result.success?).to be true
324
- expect { result.bar }.to raise_error(NoMethodError)
249
+ expect(result.foo).to eq "bar"
325
250
  end
326
251
 
327
252
  it "raises an exception when the attribute is required and not provided" do
328
253
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
329
- input { required(:bar).filled(:string) }
254
+ success do
255
+ attribute :foo
256
+ validates :foo, presence: true
257
+ end
258
+
259
+ def call
260
+ success!
261
+ end
330
262
  end
331
263
 
332
264
  expect {
333
265
  interaktor.call!
334
- }.to raise_error(
335
- an_instance_of(Interaktor::Error::AttributeSchemaValidationError).and(
336
- having_attributes(
337
- interaktor: interaktor,
338
- validation_errors: {bar: ["is missing"]}
339
- )
266
+ }.to raise_error do |error|
267
+ expect(error).to be_an Interaktor::Error::AttributeValidationError
268
+ expect(error.validation_errors).to eq(
269
+ foo: ["can't be blank"]
340
270
  )
341
- )
271
+ end
342
272
  end
343
273
 
344
274
  it "raises an exception for unknown provided attributes" do
345
275
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
346
- input { required(:bar).filled(:string) }
276
+ success { attribute :foo }
277
+
278
+ def call
279
+ success!(baz: "wadus")
280
+ end
347
281
  end
348
282
 
349
283
  expect {
350
- interaktor.call!(bar: "baz", foo: "unexpected")
351
- }.to raise_error Interaktor::Error::UnknownAttributeError
352
- end
353
-
354
- it "allows provided optional attributes" do
355
- interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
356
- input { optional(:bar).filled(:string) }
284
+ interaktor.call
285
+ }.to raise_error do |error|
286
+ expect(error).to be_an Interaktor::Error::UnknownAttributeError
287
+ expect(error.attribute).to eq "baz"
357
288
  end
358
-
359
- expect(interaktor.optional_input_attributes).to contain_exactly(:bar)
360
-
361
- result = interaktor.call(bar: "baz")
362
-
363
- expect(result.success?).to be true
364
- expect { result.bar }.to raise_error(NoMethodError)
365
289
  end
366
290
 
367
- it "allows missing optional attributes" do
291
+ it "allows success with no attributes" do
368
292
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
369
- input { optional(:bar).filled(:string) }
293
+ def call
294
+ success!
295
+ end
370
296
  end
371
297
 
372
- expect(interaktor.optional_input_attributes).to contain_exactly(:bar)
373
-
374
298
  result = interaktor.call
375
299
 
376
300
  expect(result.success?).to be true
377
- expect { result.bar }.to raise_error(NoMethodError)
301
+ expect(result.early_return?).to be true
378
302
  end
379
303
 
380
- it "creates attribute getters" do
304
+ it "allows provided optional attributes" do
381
305
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
382
- input do
383
- required(:foo).filled(:string)
384
- optional(:bar).filled(:string)
385
- end
306
+ success { attribute :foo }
386
307
 
387
308
  def call
388
- foo
389
- bar
309
+ success!(foo: "bar")
390
310
  end
391
311
  end
392
312
 
393
- result = interaktor.call(foo: "bar", bar: "baz")
313
+ result = interaktor.call
394
314
 
395
315
  expect(result.success?).to be true
396
- expect { result.foo }.to raise_error(NoMethodError)
397
- expect { result.bar }.to raise_error(NoMethodError)
316
+ expect(result.foo).to eq "bar"
398
317
  end
399
- end
400
318
 
401
- describe "success attributes" do
402
- it "accepts a schema object" do
319
+ it "allows missing optional attributes" do
403
320
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
404
- success(Dry::Schema.Params { required(:bar).filled(:string) })
321
+ success { attribute :foo }
405
322
 
406
323
  def call
407
- success!(bar: "baz")
324
+ success!
408
325
  end
409
326
  end
410
327
 
411
- expect(interaktor.success_schema).to be_a Dry::Schema::Params
412
- expect(interaktor.required_success_attributes).to contain_exactly(:bar)
413
-
414
328
  result = interaktor.call
415
329
 
416
330
  expect(result.success?).to be true
417
- expect(result.bar).to eq "baz"
331
+ expect(result.foo).to be nil
418
332
  end
419
333
 
420
- it "accepts a schema definition block" do
334
+ it "raises an exception when attributes are provided but none are defined" do
421
335
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
422
- success { required(:bar).filled(:string) }
423
-
424
336
  def call
425
- success!(bar: "baz")
337
+ success!(foo: "bar")
426
338
  end
427
339
  end
428
340
 
429
- expect(interaktor.success_schema).to be_a Dry::Schema::Params
430
- expect(interaktor.required_success_attributes).to contain_exactly(:bar)
431
-
432
- result = interaktor.call
433
-
434
- expect(result.success?).to be true
435
- expect(result.bar).to eq "baz"
341
+ expect {
342
+ interaktor.call
343
+ }.to raise_error do |error|
344
+ expect(error).to be_a Interaktor::Error::UnknownAttributeError
345
+ expect(error.attribute).to eq "foo"
346
+ end
436
347
  end
437
348
 
438
- it "raises an exception when the attribute is required and not provided" do
349
+ it "raises an exception when the correct attributes are not provided because #success! is not called" do
439
350
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
440
- success { required(:bar).filled(:string) }
351
+ success { attribute :foo }
441
352
 
442
353
  def call
443
- success!
354
+ # do nothing and 'succeed' implicitly
444
355
  end
445
356
  end
446
357
 
447
- expect {
448
- interaktor.call
449
- }.to raise_error(
450
- an_instance_of(Interaktor::Error::AttributeSchemaValidationError).and(
451
- having_attributes(
452
- interaktor: interaktor,
453
- validation_errors: {bar: ["is missing"]}
454
- )
455
- )
456
- )
358
+ expect { interaktor.call }.to raise_error Interaktor::Error::MissingExplicitSuccessError
457
359
  end
458
360
 
459
- it "raises an exception for unknown provided attributes" do
361
+ it "does not create getters for failure attributes" do
460
362
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
461
- success { required(:bar).filled(:string) }
363
+ success { attribute :foo }
364
+ failure { attribute :baz }
462
365
 
463
366
  def call
464
- success!(bar: "baz", foo: "wadus")
367
+ success!(foo: "bar")
465
368
  end
466
369
  end
467
370
 
371
+ result = interaktor.call
372
+
373
+ expect(result.success?).to be true
374
+ expect(result.foo).to eq "bar"
375
+ expect { result.baz }.to raise_error NoMethodError
376
+ end
377
+
378
+ it "disallows specifically disallowed attribute names" do
468
379
  expect {
469
- interaktor.call
470
- }.to raise_error Interaktor::Error::UnknownAttributeError
380
+ FakeInteraktor.build_interaktor(type: interaktor_class) do
381
+ # 'errors' is one because it's the accessor for the ActiveModel::Errors
382
+ success { attribute :errors }
383
+ end
384
+ }.to raise_error(ArgumentError, /disallowed attribute name/i)
471
385
  end
472
386
 
473
- it "allows missing optional attributes" do
387
+ it "raises an exception when success block is provided more than once" do
388
+ expect {
389
+ FakeInteraktor.build_interaktor(type: interaktor_class) do
390
+ success { attribute :foo }
391
+ success { attribute :bar }
392
+ end
393
+ }.to raise_error "Success block already defined"
394
+ end
395
+ end
396
+
397
+ describe "failure attributes" do
398
+ it "accepts an attribute definition block" do
474
399
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
475
- success { optional(:bar).filled(:string) }
400
+ failure { attribute :foo }
476
401
 
477
402
  def call
478
- success!
403
+ fail!(foo: "bar")
479
404
  end
480
405
  end
481
406
 
482
- expect(interaktor.optional_success_attributes).to contain_exactly(:bar)
483
-
484
407
  result = interaktor.call
485
408
 
486
- expect(result.success?).to be true
487
- expect(result.bar).to be nil
409
+ expect(result.failure?).to be true
410
+ expect(result.foo).to eq "bar"
488
411
  end
489
412
 
490
- it "raises an exception when the correct attributes are not provided because #success! is not called" do
413
+ it "raises an exception when the attribute is required and not provided" do
491
414
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
492
- success { required(:bar).filled(:string) }
415
+ failure do
416
+ attribute :foo
417
+ validates :foo, presence: true
418
+ end
493
419
 
494
420
  def call
495
- # do nothing and succeed implicitly
421
+ fail!
496
422
  end
497
423
  end
498
424
 
499
- expect { interaktor.call }.to(
500
- raise_error(
501
- an_instance_of(Interaktor::Error::MissingExplicitSuccessError).and(having_attributes(attributes: [:bar]))
425
+ expect {
426
+ interaktor.call!
427
+ }.to raise_error do |error|
428
+ expect(error).to be_an Interaktor::Error::AttributeValidationError
429
+ expect(error.validation_errors).to eq(
430
+ foo: ["can't be blank"]
502
431
  )
503
- )
432
+ end
504
433
  end
505
- end
506
434
 
507
- describe "failure attributes" do
508
- it "accepts a schema object" do
435
+ it "raises an exception for unknown provided attributes" do
509
436
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
510
- failure(Dry::Schema.Params { required(:bar).filled(:string) })
437
+ failure { attribute :foo }
511
438
 
512
439
  def call
513
- fail!(bar: "baz")
440
+ fail!(baz: "wadus")
514
441
  end
515
442
  end
516
443
 
517
- expect(interaktor.failure_schema).to be_a Dry::Schema::Params
518
- expect(interaktor.required_failure_attributes).to contain_exactly(:bar)
519
-
520
- result = interaktor.call
521
-
522
- expect(result.failure?).to be true
523
- expect(result.bar).to eq "baz"
444
+ expect {
445
+ interaktor.call
446
+ }.to raise_error do |error|
447
+ expect(error).to be_an Interaktor::Error::UnknownAttributeError
448
+ expect(error.attribute).to eq "baz"
449
+ end
524
450
  end
525
451
 
526
- it "accepts a schema definition block" do
452
+ it "allows failure with no attributes" do
527
453
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
528
- failure { required(:bar).filled(:string) }
529
-
530
454
  def call
531
- fail!(bar: "baz")
455
+ fail!
532
456
  end
533
457
  end
534
458
 
535
- expect(interaktor.failure_schema).to be_a Dry::Schema::Params
536
- expect(interaktor.required_failure_attributes).to contain_exactly(:bar)
537
-
538
459
  result = interaktor.call
539
460
 
540
461
  expect(result.failure?).to be true
541
- expect(result.bar).to eq "baz"
542
462
  end
543
463
 
544
- it "raises an exception when the attribute is required and not provided" do
464
+ it "raises an exception when attributes are provided but none are defined" do
545
465
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
546
- failure { required(:bar).filled(:string) }
547
-
548
466
  def call
549
- fail!
467
+ fail!(foo: "bar")
550
468
  end
551
469
  end
552
470
 
553
471
  expect {
554
472
  interaktor.call
555
- }.to raise_error(
556
- an_instance_of(Interaktor::Error::AttributeSchemaValidationError).and(
557
- having_attributes(
558
- interaktor: interaktor,
559
- validation_errors: {bar: ["is missing"]}
560
- )
561
- )
562
- )
473
+ }.to raise_error do |error|
474
+ expect(error).to be_a Interaktor::Error::UnknownAttributeError
475
+ expect(error.attribute).to eq "foo"
476
+ end
563
477
  end
564
478
 
565
- it "raises an exception for unknown provided attributes" do
479
+ it "allows provided optional attributes" do
566
480
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
567
- failure { required(:bar).filled(:string) }
481
+ failure { attribute :foo }
568
482
 
569
483
  def call
570
- fail!(bar: "baz", foo: "wadus")
484
+ fail!(foo: "bar")
571
485
  end
572
486
  end
573
487
 
574
- expect {
575
- interaktor.call
576
- }.to raise_error Interaktor::Error::UnknownAttributeError
488
+ result = interaktor.call
489
+
490
+ expect(result.failure?).to be true
491
+ expect(result.foo).to eq "bar"
577
492
  end
578
493
 
579
494
  it "allows missing optional attributes" do
580
495
  interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
581
- failure { optional(:bar).filled(:string) }
496
+ failure { attribute :foo }
582
497
 
583
498
  def call
584
499
  fail!
585
500
  end
586
501
  end
587
502
 
588
- expect(interaktor.optional_failure_attributes).to contain_exactly(:bar)
503
+ result = interaktor.call
504
+
505
+ expect(result.failure?).to be true
506
+ expect(result.foo).to be nil
507
+ end
508
+
509
+ it "does not create getters for success attributes" do
510
+ interaktor = FakeInteraktor.build_interaktor(type: interaktor_class) do
511
+ success { attribute :foo }
512
+ failure { attribute :baz }
513
+
514
+ def call
515
+ fail!(baz: "wadus")
516
+ end
517
+ end
589
518
 
590
519
  result = interaktor.call
591
520
 
592
521
  expect(result.failure?).to be true
593
- expect(result.bar).to be nil
522
+ expect(result.baz).to eq "wadus"
523
+ expect { result.foo }.to raise_error NoMethodError
524
+ end
525
+
526
+ it "disallows specifically disallowed attribute names" do
527
+ expect {
528
+ FakeInteraktor.build_interaktor(type: interaktor_class) do
529
+ # 'errors' is one because it's the accessor for the ActiveModel::Errors
530
+ failure { attribute :errors }
531
+ end
532
+ }.to raise_error(ArgumentError, /disallowed attribute name/i)
533
+ end
534
+
535
+ it "raises an exception when failure block is provided more than once" do
536
+ expect {
537
+ FakeInteraktor.build_interaktor(type: interaktor_class) do
538
+ failure { attribute :foo }
539
+ failure { attribute :bar }
540
+ end
541
+ }.to raise_error "Failure block already defined"
594
542
  end
595
543
  end
596
544
  end