interactor_support 1.0.1 → 1.0.2
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 +4 -0
- data/README.md +399 -4
- data/lib/interactor_support/concerns/transformable.rb +14 -5
- data/lib/interactor_support/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9389f81b3832c245eac6c1f850a1b55c6baaebbc01be44eccd8d4f31c45bc731
|
|
4
|
+
data.tar.gz: c3ee7cd401d9d744e51208bc9763cb417e25410e4e2797bb51676aece17ffeec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 67218c44b1b89e1173abba43d298742eaa2bf59d7a884c5e65017c855f80a4ace05a2423232325395085f8e70c9d7f981e6ef39d267368e9eaf7c2c32fb7e57e
|
|
7
|
+
data.tar.gz: 0c8ff1bac440c0cd7f07d4e3f9463109986ce92240aaa5725e5d405f21c62040d6ea7509e1de2b951184db39cef977c181f01c73ed69895e599b67dda093628c
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Make your **Rails interactors** clean, powerful, and less error-prone!
|
|
|
28
28
|
Add to your Gemfile:
|
|
29
29
|
|
|
30
30
|
```sh
|
|
31
|
-
|
|
31
|
+
gem 'interactor_support', '~> 1.0', '>= 1.0.1'
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Or install manually:
|
|
@@ -84,7 +84,7 @@ class UpdateTodoTitle
|
|
|
84
84
|
include Interactor
|
|
85
85
|
include InteractorSupport
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
required :todo_id, :title
|
|
88
88
|
transform :title, with: :strip
|
|
89
89
|
find_by :todo, query: { id: :todo_id }, required: true
|
|
90
90
|
update :todo, attributes: { title: :title }
|
|
@@ -110,7 +110,7 @@ class CompleteTodo
|
|
|
110
110
|
include InteractorSupport
|
|
111
111
|
|
|
112
112
|
transaction
|
|
113
|
-
|
|
113
|
+
required :todo_id
|
|
114
114
|
find_by :todo, query: { id: :todo_id }, required: true
|
|
115
115
|
|
|
116
116
|
update :todo, attributes: {
|
|
@@ -133,7 +133,7 @@ class CompleteTodo
|
|
|
133
133
|
include InteractorSupport
|
|
134
134
|
|
|
135
135
|
transaction
|
|
136
|
-
|
|
136
|
+
required :todo
|
|
137
137
|
skip if: -> { todo.completed? }
|
|
138
138
|
update :todo, attributes: { completed: true, completed_at: -> { Time.current } }
|
|
139
139
|
end
|
|
@@ -235,10 +235,53 @@ find_where :post, where: { user_id: :user_id }, context_key: :user_posts
|
|
|
235
235
|
|
|
236
236
|
Provides `transform` to **sanitize and normalize inputs**.
|
|
237
237
|
|
|
238
|
+
```rb
|
|
239
|
+
# any method that the attribute responds to will work
|
|
240
|
+
transform :title, with: :strip
|
|
241
|
+
|
|
242
|
+
# You can chain transformers on an attribute
|
|
243
|
+
# show_the_thing == "1" => "1".to_i.positive? => true
|
|
244
|
+
transform :show_the_thing, with: [:to_i, :positive?]
|
|
245
|
+
|
|
246
|
+
# transforming a string to a boolean using a lambda, eg: "true" => true
|
|
247
|
+
transform :my_param, with: -> (val) { ActiveModel::Type::Boolean.new.cast(val) }
|
|
248
|
+
|
|
249
|
+
# added in 1.0.2
|
|
250
|
+
# mixing symbols and keys. eg: " True " => true
|
|
251
|
+
transform :my_param, with: [
|
|
252
|
+
:strip,
|
|
253
|
+
:downcase,
|
|
254
|
+
-> (val) { ActiveModel::Type::Boolean.new.cast(val) }
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
|
|
238
259
|
#### 🔹 **`InteractorSupport::Concerns::Skippable`**
|
|
239
260
|
|
|
240
261
|
Allows an interactor to **skip execution** if a condition is met.
|
|
241
262
|
|
|
263
|
+
```rb
|
|
264
|
+
# skips execution
|
|
265
|
+
skip if: true
|
|
266
|
+
# skips execution when a lambda is passed
|
|
267
|
+
skip if: -> { true }
|
|
268
|
+
# using a method
|
|
269
|
+
skip if: :some_method?
|
|
270
|
+
# using a context variable
|
|
271
|
+
skip if: :condition
|
|
272
|
+
|
|
273
|
+
# Using `unless`
|
|
274
|
+
|
|
275
|
+
# skips execution
|
|
276
|
+
skip unless: false
|
|
277
|
+
# skips execution when a lambda is passed
|
|
278
|
+
skip unless: -> { false }
|
|
279
|
+
# using a method
|
|
280
|
+
skip unless: :some_method?
|
|
281
|
+
# using a context variable
|
|
282
|
+
skip unless: :condition
|
|
283
|
+
```
|
|
284
|
+
|
|
242
285
|
#### 🔹 **`InteractorSupport::Validations`**
|
|
243
286
|
|
|
244
287
|
Provides **automatic input validation** before execution. This includes `ActiveModel::Validations` and
|
|
@@ -274,6 +317,358 @@ If any validation fails, context.fail!(errors: errors.full_messages) will automa
|
|
|
274
317
|
|
|
275
318
|
Provides structured, validated request objects based on **ActiveModel**.
|
|
276
319
|
|
|
320
|
+
For now, here's the specs:
|
|
321
|
+
|
|
322
|
+
```rb
|
|
323
|
+
class GenreRequest
|
|
324
|
+
include InteractorSupport::RequestObject
|
|
325
|
+
|
|
326
|
+
attribute :title, transform: :strip
|
|
327
|
+
attribute :description, transform: :strip
|
|
328
|
+
|
|
329
|
+
validates :title, :description, presence: true
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
class LocationRequest
|
|
333
|
+
include InteractorSupport::RequestObject
|
|
334
|
+
|
|
335
|
+
attribute :city, transform: [:downcase, :strip]
|
|
336
|
+
attribute :country_code, transform: [:strip, :upcase]
|
|
337
|
+
attribute :state_code, transform: [:strip, :upcase]
|
|
338
|
+
attribute :postal_code, transform: [:strip, :clean_postal_code]
|
|
339
|
+
attribute :address, transform: :strip
|
|
340
|
+
|
|
341
|
+
validates :city, :postal_code, :address, presence: true
|
|
342
|
+
validates :country_code, :state_code, presence: true, length: { is: 2 }
|
|
343
|
+
|
|
344
|
+
def clean_postal_code(value)
|
|
345
|
+
value.to_s.gsub(/\D/, '')
|
|
346
|
+
value.first(5)
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
class AuthorRequest
|
|
351
|
+
include InteractorSupport::RequestObject
|
|
352
|
+
|
|
353
|
+
attribute :name, transform: :strip
|
|
354
|
+
attribute :email, transform: [:strip, :downcase]
|
|
355
|
+
attribute :age, transform: :to_i
|
|
356
|
+
attribute :location, type: LocationRequest
|
|
357
|
+
validates_format_of :email, with: URI::MailTo::EMAIL_REGEXP
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
class PostRequest
|
|
361
|
+
include InteractorSupport::RequestObject
|
|
362
|
+
|
|
363
|
+
attribute :user_id
|
|
364
|
+
attribute :title, transform: :strip
|
|
365
|
+
attribute :content, transform: :strip
|
|
366
|
+
attribute :genre, type: GenreRequest
|
|
367
|
+
attribute :authors, type: AuthorRequest, array: true
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
RSpec.describe(InteractorSupport::RequestObject) do
|
|
371
|
+
describe 'attribute transformation' do
|
|
372
|
+
before do
|
|
373
|
+
InteractorSupport.configure do |config|
|
|
374
|
+
config.request_object_behavior = :returns_self
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
context 'when using a single transform' do
|
|
378
|
+
it 'strips the value for a symbol transform' do
|
|
379
|
+
genre = GenreRequest.new(title: ' Science Fiction ', description: ' A genre of speculative fiction ')
|
|
380
|
+
expect(genre.title).to(eq('Science Fiction'))
|
|
381
|
+
expect(genre.description).to(eq('A genre of speculative fiction'))
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
context 'when using an array of transforms' do
|
|
386
|
+
it 'applies all transform methods in order' do
|
|
387
|
+
buyer = LocationRequest.new(
|
|
388
|
+
city: ' New York ',
|
|
389
|
+
country_code: ' us ',
|
|
390
|
+
state_code: ' ny ',
|
|
391
|
+
postal_code: ' 10001-5432 ',
|
|
392
|
+
address: ' 123 Main St. ',
|
|
393
|
+
)
|
|
394
|
+
expect(buyer.city).to(eq('new york'))
|
|
395
|
+
expect(buyer.country_code).to(eq('US'))
|
|
396
|
+
expect(buyer.state_code).to(eq('NY'))
|
|
397
|
+
expect(buyer.postal_code).to(eq('10001'))
|
|
398
|
+
expect(buyer.address).to(eq('123 Main St.'))
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
context 'when the value does not respond to a transform method' do
|
|
403
|
+
it 'raises and argument error if the transform method is not defined' do
|
|
404
|
+
class DummyRequest
|
|
405
|
+
include InteractorSupport::RequestObject
|
|
406
|
+
attribute :number, transform: :strip
|
|
407
|
+
validates :number, presence: true
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
expect { DummyRequest.new(number: 1234) }.to(raise_error(ArgumentError))
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
describe 'nesting request objects and array support' do
|
|
416
|
+
before do
|
|
417
|
+
InteractorSupport.configure do |config|
|
|
418
|
+
config.request_object_behavior = :returns_self
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
context 'when using a type without array' do
|
|
422
|
+
it "wraps the given hash in the type's new instance" do
|
|
423
|
+
post = PostRequest.new(
|
|
424
|
+
user_id: 1,
|
|
425
|
+
title: ' My First Post ',
|
|
426
|
+
content: ' This is the content of my first post ',
|
|
427
|
+
genre: { title: ' Science Fiction ', description: ' A genre of speculative fiction ' },
|
|
428
|
+
authors: [
|
|
429
|
+
{
|
|
430
|
+
name: ' John Doe ',
|
|
431
|
+
email: 'me@mail.com',
|
|
432
|
+
age: ' 25 ',
|
|
433
|
+
location: {
|
|
434
|
+
city: ' New York ',
|
|
435
|
+
country_code: ' us ',
|
|
436
|
+
state_code: ' ny ',
|
|
437
|
+
postal_code: ' 10001-5432 ',
|
|
438
|
+
address: ' 123 Main St. ',
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
name: ' Jane Doe ',
|
|
443
|
+
email: 'you@mail.com',
|
|
444
|
+
age: ' 25 ',
|
|
445
|
+
location: {
|
|
446
|
+
city: ' Los Angeles ',
|
|
447
|
+
country_code: ' us ',
|
|
448
|
+
state_code: ' ca ',
|
|
449
|
+
postal_code: ' 90001 ',
|
|
450
|
+
address: ' 456 Elm St. ',
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
expect(post).to(be_valid)
|
|
457
|
+
expect(post.user_id).to(eq(1))
|
|
458
|
+
expect(post.title).to(eq('My First Post'))
|
|
459
|
+
expect(post.content).to(eq('This is the content of my first post'))
|
|
460
|
+
expect(post.genre).to(be_a(GenreRequest))
|
|
461
|
+
expect(post.genre.title).to(eq('Science Fiction'))
|
|
462
|
+
expect(post.genre.description).to(eq('A genre of speculative fiction'))
|
|
463
|
+
expect(post.authors).to(be_an(Array))
|
|
464
|
+
expect(post.authors.size).to(eq(2))
|
|
465
|
+
post.authors.each do |author|
|
|
466
|
+
expect(author).to(be_a(AuthorRequest))
|
|
467
|
+
expect(author).to(be_valid)
|
|
468
|
+
expect(author.location).to(be_a(LocationRequest))
|
|
469
|
+
expect(author.location).to(be_valid)
|
|
470
|
+
expect(author.location.city).to(be_in(['new york', 'los angeles']))
|
|
471
|
+
expect(author.location.country_code).to(eq('US'))
|
|
472
|
+
expect(author.location.state_code).to(be_in(['NY', 'CA']))
|
|
473
|
+
expect(author.location.postal_code).to(be_in(['10001', '90001']))
|
|
474
|
+
expect(author.location.address).to(be_in(['123 Main St.', '456 Elm St.']))
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
describe 'to_context' do
|
|
481
|
+
before do
|
|
482
|
+
InteractorSupport.configure do |config|
|
|
483
|
+
config.request_object_behavior = :returns_self
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
it 'returns a struct and includes nested attributes' do
|
|
487
|
+
context = PostRequest.new(
|
|
488
|
+
user_id: 1,
|
|
489
|
+
title: ' My First Post ',
|
|
490
|
+
content: ' This is the content of my first post ',
|
|
491
|
+
genre: { title: ' Science Fiction ', description: ' A genre of speculative fiction ' },
|
|
492
|
+
authors: [
|
|
493
|
+
{
|
|
494
|
+
name: ' John Doe ',
|
|
495
|
+
email: 'a@b.com',
|
|
496
|
+
age: ' 25 ',
|
|
497
|
+
location: {
|
|
498
|
+
city: ' New York ',
|
|
499
|
+
country_code: ' us ',
|
|
500
|
+
state_code: ' ny ',
|
|
501
|
+
postal_code: ' 10001-5432 ',
|
|
502
|
+
address: ' 123 Main St. ',
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
],
|
|
506
|
+
).to_context
|
|
507
|
+
|
|
508
|
+
expect(context).to(be_a(Hash))
|
|
509
|
+
expect(context[:user_id]).to(eq(1))
|
|
510
|
+
expect(context[:title]).to(eq('My First Post'))
|
|
511
|
+
expect(context[:content]).to(eq('This is the content of my first post'))
|
|
512
|
+
expect(context[:genre]).to(be_a(Hash))
|
|
513
|
+
expect(context.dig(:genre, :title)).to(eq('Science Fiction'))
|
|
514
|
+
expect(context.dig(:genre, :description)).to(eq('A genre of speculative fiction'))
|
|
515
|
+
expect(context[:authors]).to(be_an(Array))
|
|
516
|
+
expect(context[:authors].size).to(eq(1))
|
|
517
|
+
author = context[:authors].first
|
|
518
|
+
expect(author).to(be_a(Hash))
|
|
519
|
+
expect(author[:name]).to(eq('John Doe'))
|
|
520
|
+
expect(author[:email]).to(eq('a@b.com'))
|
|
521
|
+
expect(author[:age]).to(eq(25))
|
|
522
|
+
expect(author[:location]).to(be_a(Hash))
|
|
523
|
+
expect(author[:location][:city]).to(eq('new york'))
|
|
524
|
+
expect(author[:location][:country_code]).to(eq('US'))
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
describe 'configured request object behavior' do
|
|
529
|
+
it 'returns a context hash with symbol keys when configured to do so' do
|
|
530
|
+
InteractorSupport.configure do |config|
|
|
531
|
+
config.request_object_behavior = :returns_context
|
|
532
|
+
config.request_object_key_type = :symbol
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
context = PostRequest.new(
|
|
536
|
+
user_id: 1,
|
|
537
|
+
title: ' My First Post ',
|
|
538
|
+
content: ' This is the content of my first post ',
|
|
539
|
+
genre: { title: ' Science Fiction ', description: ' A genre of speculative fiction ' },
|
|
540
|
+
authors: [
|
|
541
|
+
{
|
|
542
|
+
name: ' John Doe ',
|
|
543
|
+
email: 'j@j.com',
|
|
544
|
+
age: ' 25 ',
|
|
545
|
+
location: {
|
|
546
|
+
city: ' New York ',
|
|
547
|
+
country_code: ' us ',
|
|
548
|
+
state_code: ' ny ',
|
|
549
|
+
postal_code: ' 10001-5432 ',
|
|
550
|
+
address: ' 123 Main St. ',
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
],
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
expect(context).to(be_a(Hash))
|
|
557
|
+
expect(context[:user_id]).to(eq(1))
|
|
558
|
+
expect(context[:title]).to(eq('My First Post'))
|
|
559
|
+
expect(context[:content]).to(eq('This is the content of my first post'))
|
|
560
|
+
expect(context[:genre]).to(be_a(Hash))
|
|
561
|
+
expect(context.dig(:genre, :title)).to(eq('Science Fiction'))
|
|
562
|
+
expect(context.dig(:genre, :description)).to(eq('A genre of speculative fiction'))
|
|
563
|
+
expect(context[:authors]).to(be_an(Array))
|
|
564
|
+
expect(context[:authors].size).to(eq(1))
|
|
565
|
+
author = context[:authors].first
|
|
566
|
+
expect(author).to(be_a(Hash))
|
|
567
|
+
expect(author[:name]).to(eq('John Doe'))
|
|
568
|
+
expect(author[:email]).to(eq('j@j.com'))
|
|
569
|
+
expect(author[:age]).to(eq(25))
|
|
570
|
+
expect(author[:location]).to(be_a(Hash))
|
|
571
|
+
expect(author[:location][:city]).to(eq('new york'))
|
|
572
|
+
expect(author[:location][:country_code]).to(eq('US'))
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
it 'returns a context hash with string keys when configured to do so' do
|
|
576
|
+
InteractorSupport.configure do |config|
|
|
577
|
+
config.request_object_behavior = :returns_context
|
|
578
|
+
config.request_object_key_type = :string
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
post = PostRequest.new(
|
|
582
|
+
user_id: 1,
|
|
583
|
+
title: ' My First Post ',
|
|
584
|
+
content: ' This is the content of my first post ',
|
|
585
|
+
genre: { title: ' Science Fiction ', description: ' A genre of speculative fiction ' },
|
|
586
|
+
authors: [
|
|
587
|
+
{
|
|
588
|
+
name: ' John Doe ',
|
|
589
|
+
email: 'j@j.com',
|
|
590
|
+
age: ' 25 ',
|
|
591
|
+
location: {
|
|
592
|
+
city: ' New York ',
|
|
593
|
+
country_code: ' us ',
|
|
594
|
+
state_code: ' ny ',
|
|
595
|
+
postal_code: ' 10001-5432 ',
|
|
596
|
+
address: ' 123 Main St. ',
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
],
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
context = post
|
|
603
|
+
expect(context).to(be_a(Hash))
|
|
604
|
+
expect(context['user_id']).to(eq(1))
|
|
605
|
+
expect(context['title']).to(eq('My First Post'))
|
|
606
|
+
expect(context['content']).to(eq('This is the content of my first post'))
|
|
607
|
+
expect(context['genre']).to(be_a(Hash))
|
|
608
|
+
expect(context.dig('genre', 'title')).to(eq('Science Fiction'))
|
|
609
|
+
expect(context.dig('genre', 'description')).to(eq('A genre of speculative fiction'))
|
|
610
|
+
expect(context['authors']).to(be_an(Array))
|
|
611
|
+
expect(context['authors'].size).to(eq(1))
|
|
612
|
+
author = context['authors'].first
|
|
613
|
+
expect(author).to(be_a(Hash))
|
|
614
|
+
expect(author['name']).to(eq('John Doe'))
|
|
615
|
+
expect(author['email']).to(eq('j@j.com'))
|
|
616
|
+
expect(author['age']).to(eq(25))
|
|
617
|
+
expect(author['location']).to(be_a(Hash))
|
|
618
|
+
expect(author['location']['city']).to(eq('new york'))
|
|
619
|
+
expect(author['location']['country_code']).to(eq('US'))
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
it 'returns a context struct when configured to do so' do
|
|
623
|
+
InteractorSupport.configure do |config|
|
|
624
|
+
config.request_object_behavior = :returns_context
|
|
625
|
+
config.request_object_key_type = :struct
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
post = PostRequest.new(
|
|
629
|
+
user_id: 1,
|
|
630
|
+
title: ' My First Post ',
|
|
631
|
+
content: ' This is the content of my first post ',
|
|
632
|
+
genre: { title: ' Science Fiction ', description: ' A genre of speculative fiction ' },
|
|
633
|
+
authors: [
|
|
634
|
+
{
|
|
635
|
+
name: ' John Doe ',
|
|
636
|
+
email: 'j@j.com',
|
|
637
|
+
age: ' 25 ',
|
|
638
|
+
location: {
|
|
639
|
+
city: ' New York ',
|
|
640
|
+
country_code: ' us ',
|
|
641
|
+
state_code: ' ny ',
|
|
642
|
+
postal_code: ' 10001-5432 ',
|
|
643
|
+
address: ' 123 Main St. ',
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
],
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
context = post
|
|
650
|
+
expect(context).to(be_a(Struct))
|
|
651
|
+
expect(context.user_id).to(eq(1))
|
|
652
|
+
expect(context.title).to(eq('My First Post'))
|
|
653
|
+
expect(context.content).to(eq('This is the content of my first post'))
|
|
654
|
+
expect(context.genre).to(be_a(Struct))
|
|
655
|
+
expect(context.genre.title).to(eq('Science Fiction'))
|
|
656
|
+
expect(context.genre.description).to(eq('A genre of speculative fiction'))
|
|
657
|
+
expect(context.authors).to(be_an(Array))
|
|
658
|
+
expect(context.authors.size).to(eq(1))
|
|
659
|
+
author = context.authors.first
|
|
660
|
+
expect(author).to(be_a(Struct))
|
|
661
|
+
expect(author.name).to(eq('John Doe'))
|
|
662
|
+
expect(author.email).to(eq('j@j.com'))
|
|
663
|
+
expect(author.age).to(eq(25))
|
|
664
|
+
expect(author.location).to(be_a(Struct))
|
|
665
|
+
expect(author.location.city).to(eq('new york'))
|
|
666
|
+
expect(author.location.country_code).to(eq('US'))
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
```
|
|
671
|
+
|
|
277
672
|
## 🤝 **Contributing**
|
|
278
673
|
|
|
279
674
|
Pull requests are welcome on [GitHub](https://github.com/charliemitchell/interactor_support).
|
|
@@ -42,11 +42,20 @@ module InteractorSupport
|
|
|
42
42
|
context.fail!(errors: ["#{key} failed to transform: #{e.message}"])
|
|
43
43
|
end
|
|
44
44
|
elsif with.is_a?(Array)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
with.each do |method|
|
|
46
|
+
if method.is_a?(Proc)
|
|
47
|
+
begin
|
|
48
|
+
context[key] = context.instance_exec(&method)
|
|
49
|
+
rescue => e
|
|
50
|
+
context.fail!(errors: ["#{key} failed to transform: #{e.message}"])
|
|
51
|
+
end
|
|
52
|
+
else
|
|
53
|
+
context.fail!(
|
|
54
|
+
errors: ["#{key} does not respond to all transforms"],
|
|
55
|
+
) unless context[key].respond_to?(method)
|
|
56
|
+
|
|
57
|
+
context[key] = context[key].send(method)
|
|
58
|
+
end
|
|
50
59
|
end
|
|
51
60
|
elsif with.is_a?(Symbol) && context[key].respond_to?(with)
|
|
52
61
|
context[key] = context[key].send(with)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: interactor_support
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Charlie Mitchell
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-03-
|
|
11
|
+
date: 2025-03-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email:
|