active_interaction 5.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cfed756a5463384a07d694ba40f14067dce231d2618af2f16e6fd429e31b97f
4
- data.tar.gz: eb3b185d234762dec1799fbaa6e8acf290a47e0940b24c3da529f11172e6fde5
3
+ metadata.gz: c740eef14e1c0bca42f4bbb5b3718c879bc3af038f40953a60a53007611916e5
4
+ data.tar.gz: b0a3738aa38869c7be559d72f23e958d0f9e66c0f490652bd8a92e1ef449e48e
5
5
  SHA512:
6
- metadata.gz: b2ce2d6ef28bc84e2cc614dd9e6dde57c14a92efcafe706e8cb532b1c0fa9c192db8548771b94198236f3ab3ec6baa9633c2625c3f8b73cbcc1291752078be6c
7
- data.tar.gz: 3f5f3c15059c19c7fec77256a260fc67f98444ab5dba48048f2797a441a348f7deea31b7b558e0b1af334ffd8a6e1685756745ecebdc87ee658dafc42f8043c4
6
+ metadata.gz: f998483eb21ec13a43dcf3c7b6805f7865b3dd7b4d8fbc9846263338d676c41c7991a602dd3a82e13a9b93a027cbeccd5648a87fef688964124935d38d9ef6c4
7
+ data.tar.gz: 4669a1e76a427af4a62415f242bfdc3fa45f7a63c5a43de704b7849639841f365e83168b5c1db68ab067ca2104f8f7ec580baa487e5caa6035196607033c79f8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # [5.1.0][] (2022-07-28)
2
+
3
+ ## Added
4
+
5
+ - Limit dependencies to the minimum requirements.
6
+
7
+ ## Fixed
8
+
9
+ - [#536][] - `compose` accepts `Inputs`.
10
+ - [#537][] - Arrays with nested filters returned the wrong value.
11
+
1
12
  # [5.0.0][] (2022-06-24)
2
13
 
3
14
  ## Changed
@@ -1101,6 +1112,7 @@ Example.run
1101
1112
 
1102
1113
  - Initial release.
1103
1114
 
1115
+ [5.1.0]: https://github.com/AaronLasseigne/active_interaction/compare/v5.0.0...v5.1.0
1104
1116
  [5.0.0]: https://github.com/AaronLasseigne/active_interaction/compare/v4.1.0...v5.0.0
1105
1117
  [4.1.0]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.6...v4.1.0
1106
1118
  [4.0.6]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.5...v4.0.6
@@ -1325,3 +1337,5 @@ Example.run
1325
1337
  [#515]: https://github.com/AaronLasseigne/active_interaction/issues/515
1326
1338
  [#518]: https://github.com/AaronLasseigne/active_interaction/issues/518
1327
1339
  [#503]: https://github.com/AaronLasseigne/active_interaction/issues/503
1340
+ [#536]: https://github.com/AaronLasseigne/active_interaction/issues/536
1341
+ [#537]: https://github.com/AaronLasseigne/active_interaction/issues/537
data/CONTRIBUTING.md CHANGED
@@ -1,13 +1,21 @@
1
- # Steps
1
+ # Contributing
2
+
3
+ Bug fixes and optimizations are welcome.
4
+ For optimizations please provide some reproducable proof of the improvement.
5
+
6
+ For features please open a [discussion][] and we can make sure the feature fits with the gem before working on it.
7
+
8
+ ## Steps
2
9
 
3
10
  1. [Fork][] the repo.
4
11
  2. Add a breaking test for your change.
5
12
  3. Make the tests pass.
6
13
  4. Push your fork.
7
- 5. Submit a pull request.
14
+ 5. Submit a pull request against the `next` branch.
8
15
 
9
- # Code Style
16
+ ## Code Style
10
17
 
11
18
  Running the tests using `rake` (with no args) will also check for style issues in the code. Ideally all submissions would pass these checks. If the code style is causing issues (particularly the method or class size) we can work with you to correct it. Don't let it stop you from contributing.
12
19
 
13
20
  [fork]: https://github.com/AaronLasseigne/active_interaction/fork
21
+ [discussion]: https://github.com/AaronLasseigne/active_interaction/discussions/categories/ideas
data/README.md CHANGED
@@ -17,23 +17,25 @@ handles your verbs.
17
17
  - [Basic usage](#basic-usage)
18
18
  - [Validations](#validations)
19
19
  - [Filters](#filters)
20
- - [Array](#array)
21
- - [Boolean](#boolean)
22
- - [File](#file)
23
- - [Hash](#hash)
24
- - [Interface](#interface)
25
- - [Object](#object)
26
- - [Record](#record)
27
- - [String](#string)
28
- - [Symbol](#symbol)
29
- - [Dates and times](#dates-and-times)
30
- - [Date](#date)
31
- - [DateTime](#datetime)
32
- - [Time](#time)
33
- - [Numbers](#numbers)
34
- - [Decimal](#decimal)
35
- - [Float](#float)
36
- - [Integer](#integer)
20
+ - [Basic Filters](#basic-filters)
21
+ - [Array](#array)
22
+ - [Boolean](#boolean)
23
+ - [File](#file)
24
+ - [Hash](#hash)
25
+ - [String](#string)
26
+ - [Symbol](#symbol)
27
+ - [Dates and times](#dates-and-times)
28
+ - [Date](#date)
29
+ - [DateTime](#datetime)
30
+ - [Time](#time)
31
+ - [Numbers](#numbers)
32
+ - [Decimal](#decimal)
33
+ - [Float](#float)
34
+ - [Integer](#integer)
35
+ - [Advanced Filters](#advanced-filters)
36
+ - [Interface](#interface)
37
+ - [Object](#object)
38
+ - [Record](#record)
37
39
  - [Rails](#rails)
38
40
  - [Setup](#setup)
39
41
  - [Controller](#controller)
@@ -63,13 +65,13 @@ handles your verbs.
63
65
  Add it to your Gemfile:
64
66
 
65
67
  ``` rb
66
- gem 'active_interaction', '~> 5.0'
68
+ gem 'active_interaction', '~> 5.1'
67
69
  ```
68
70
 
69
71
  Or install it manually:
70
72
 
71
73
  ``` sh
72
- $ gem install active_interaction --version '~> 5.0'
74
+ $ gem install active_interaction --version '~> 5.1'
73
75
  ```
74
76
 
75
77
  This project uses [Semantic Versioning][]. Check out [GitHub releases][] for a
@@ -213,7 +215,9 @@ alternatives that can be reasonably coerced. Typically the coercions come from
213
215
  Rails, so `"1"` can be interpreted as the boolean value `true`, the string
214
216
  `"1"`, or the number `1`.
215
217
 
216
- ### Array
218
+ ### Basic Filters
219
+
220
+ #### Array
217
221
 
218
222
  In addition to accepting arrays, array inputs will convert
219
223
  `ActiveRecord::Relation`s into arrays.
@@ -286,7 +290,7 @@ With `:index_errors` set to `false` the error would have been:
286
290
  {:favorite_numbers=>[{:error=>:invalid_type, :type=>"array"}]}
287
291
  ```
288
292
 
289
- ### Boolean
293
+ #### Boolean
290
294
 
291
295
  Boolean filters convert the strings `"1"`, `"true"`, and `"on"`
292
296
  (case-insensitive) into `true`. They also convert `"0"`, `"false"`, and `"off"`
@@ -307,7 +311,7 @@ BooleanInteraction.run!(kool_aid: true)
307
311
  # => "Oh yeah!"
308
312
  ```
309
313
 
310
- ### File
314
+ #### File
311
315
 
312
316
  File filters also accept `TempFile`s and anything that responds to `#rewind`.
313
317
  That means that you can pass the `params` from uploading files via forms in
@@ -328,7 +332,7 @@ FileInteraction.run!(readme: File.open('README.md'))
328
332
  # => 21563
329
333
  ```
330
334
 
331
- ### Hash
335
+ #### Hash
332
336
 
333
337
  Hash filters accept hashes. The expected value types are given by passing a
334
338
  block and nesting other filters. You can have any number of filters inside a
@@ -380,166 +384,7 @@ hash :stuff,
380
384
  strip: false
381
385
  ```
382
386
 
383
- ### Interface
384
-
385
- Interface filters allow you to specify an interface that the passed value must
386
- meet in order to pass. The name of the interface is used to look for a constant
387
- inside the ancestor listing for the passed value. This allows for a variety of
388
- checks depending on what's passed. Class instances are checked for an included
389
- module or an inherited ancestor class. Classes are checked for an extended
390
- module or an inherited ancestor class. Modules are checked for an extended
391
- module.
392
-
393
- ``` rb
394
- class InterfaceInteraction < ActiveInteraction::Base
395
- interface :exception
396
-
397
- def execute
398
- exception
399
- end
400
- end
401
-
402
- InterfaceInteraction.run!(exception: Exception)
403
- # ActiveInteraction::InvalidInteractionError: Exception is not a valid interface
404
- InterfaceInteraction.run!(exception: NameError) # a subclass of Exception
405
- # => NameError
406
- ```
407
-
408
- You can use `:from` to specify a class or module. This would be the equivalent
409
- of what's above.
410
-
411
- ```rb
412
- class InterfaceInteraction < ActiveInteraction::Base
413
- interface :error,
414
- from: Exception
415
-
416
- def execute
417
- error
418
- end
419
- end
420
- ```
421
-
422
- You can also create an anonymous interface on the fly by passing the `methods`
423
- option.
424
-
425
- ``` rb
426
- class InterfaceInteraction < ActiveInteraction::Base
427
- interface :serializer,
428
- methods: %i[dump load]
429
-
430
- def execute
431
- input = '{ "is_json" : true }'
432
- object = serializer.load(input)
433
- output = serializer.dump(object)
434
-
435
- output
436
- end
437
- end
438
-
439
- require 'json'
440
-
441
- InterfaceInteraction.run!(serializer: Object.new)
442
- # ActiveInteraction::InvalidInteractionError: Serializer is not a valid interface
443
- InterfaceInteraction.run!(serializer: JSON)
444
- # => "{\"is_json\":true}"
445
- ```
446
-
447
- ### Object
448
-
449
- Object filters allow you to require an instance of a particular class or one of
450
- its subclasses.
451
-
452
- ``` rb
453
- class Cow
454
- def moo
455
- 'Moo!'
456
- end
457
- end
458
-
459
- class ObjectInteraction < ActiveInteraction::Base
460
- object :cow
461
-
462
- def execute
463
- cow.moo
464
- end
465
- end
466
-
467
- ObjectInteraction.run!(cow: Object.new)
468
- # ActiveInteraction::InvalidInteractionError: Cow is not a valid object
469
- ObjectInteraction.run!(cow: Cow.new)
470
- # => "Moo!"
471
- ```
472
-
473
- The class name is automatically determined by the filter name. If your filter
474
- name is different than your class name, use the `class` option. It can be
475
- either the class, a string, or a symbol.
476
-
477
- ``` rb
478
- object :dolly1,
479
- class: Sheep
480
- object :dolly2,
481
- class: 'Sheep'
482
- object :dolly3,
483
- class: :Sheep
484
- ```
485
-
486
- If you have value objects or you would like to build one object from another,
487
- you can use the `converter` option. It is only called if the value provided is
488
- not an instance of the class or one of its subclasses. The `converter` option
489
- accepts a symbol that specifies a class method on the object class or a proc.
490
- Both will be passed the value and any errors thrown inside the converter will
491
- cause the value to be considered invalid. Any returned value that is not the
492
- correct class will also be treated as invalid. Any `default` that is not an
493
- instance of the class or subclass and is not `nil` will also be converted.
494
-
495
- ``` rb
496
- class ObjectInteraction < ActiveInteraction::Base
497
- object :ip_address,
498
- class: IPAddr,
499
- converter: :new
500
-
501
- def execute
502
- ip_address
503
- end
504
- end
505
-
506
- ObjectInteraction.run!(ip_address: '192.168.1.1')
507
- # #<IPAddr: IPv4:192.168.1.1/255.255.255.255>
508
-
509
- ObjectInteraction.run!(ip_address: 1)
510
- # ActiveInteraction::InvalidInteractionError: Ip address is not a valid object
511
- ```
512
-
513
- ### Record
514
-
515
- Record filters allow you to require an instance of a particular class (or one
516
- of its subclasses) or a value that can be used to locate an instance of the
517
- object. If the value does not match, it will call `find` on the class of the
518
- record. This is particularly useful when working with ActiveRecord objects.
519
- Like an object filter, the class is derived from the name passed but can be
520
- specified with the `class` option. Any `default` that is not an instance of the
521
- class or subclass and is not `nil` will also be found. Blank strings passed in
522
- will be treated as `nil`.
523
-
524
- ``` rb
525
- class RecordInteraction < ActiveInteraction::Base
526
- record :encoding
527
-
528
- def execute
529
- encoding
530
- end
531
- end
532
-
533
- > RecordInteraction.run!(encoding: Encoding::US_ASCII)
534
- => #<Encoding:US-ASCII>
535
-
536
- > RecordInteraction.run!(encoding: 'ascii')
537
- => #<Encoding:US-ASCII>
538
- ```
539
-
540
- A different method can be specified by providing a symbol to the `finder` option.
541
-
542
- ### String
387
+ #### String
543
388
 
544
389
  String filters define inputs that only accept strings.
545
390
 
@@ -566,7 +411,7 @@ string :comment,
566
411
  strip: false
567
412
  ```
568
413
 
569
- ### Symbol
414
+ #### Symbol
570
415
 
571
416
  Symbol filters define inputs that accept symbols. Strings will be converted
572
417
  into symbols.
@@ -586,7 +431,7 @@ SymbolInteraction.run!(method: :object_id)
586
431
  # => #<Proc:0x007fdc9ba94118>
587
432
  ```
588
433
 
589
- ### Dates and times
434
+ #### Dates and times
590
435
 
591
436
  Filters that work with dates and times behave similarly. By default, they all
592
437
  convert strings into their expected data types using `.parse`. Blank strings
@@ -594,7 +439,7 @@ will be treated as `nil`. If you give the `format` option, they will instead
594
439
  convert strings using `.strptime`. Note that formats won't work with `DateTime`
595
440
  and `Time` filters if a time zone is set.
596
441
 
597
- #### Date
442
+ ##### Date
598
443
 
599
444
  ``` rb
600
445
  class DateInteraction < ActiveInteraction::Base
@@ -616,7 +461,7 @@ date :birthday,
616
461
  format: '%Y-%m-%d'
617
462
  ```
618
463
 
619
- #### DateTime
464
+ ##### DateTime
620
465
 
621
466
  ``` rb
622
467
  class DateTimeInteraction < ActiveInteraction::Base
@@ -638,7 +483,7 @@ date_time :start,
638
483
  format: '%Y-%m-%dT%H:%M:%S'
639
484
  ```
640
485
 
641
- #### Time
486
+ ##### Time
642
487
 
643
488
  In addition to converting strings with `.parse` (or `.strptime`), time filters
644
489
  convert numbers with `.at`.
@@ -663,13 +508,13 @@ time :start,
663
508
  format: '%Y-%m-%dT%H:%M:%S'
664
509
  ```
665
510
 
666
- ### Numbers
511
+ #### Numbers
667
512
 
668
513
  All numeric filters accept numeric input. They will also convert strings using
669
514
  the appropriate method from `Kernel` (like `.Float`). Blank strings will be
670
515
  treated as `nil`.
671
516
 
672
- #### Decimal
517
+ ##### Decimal
673
518
 
674
519
  ``` rb
675
520
  class DecimalInteraction < ActiveInteraction::Base
@@ -693,7 +538,7 @@ decimal :dollars,
693
538
  digits: 2
694
539
  ```
695
540
 
696
- #### Float
541
+ ##### Float
697
542
 
698
543
  ``` rb
699
544
  class FloatInteraction < ActiveInteraction::Base
@@ -710,7 +555,7 @@ FloatInteraction.run!(x: 2.1)
710
555
  # => 4.41
711
556
  ```
712
557
 
713
- #### Integer
558
+ ##### Integer
714
559
 
715
560
  ``` rb
716
561
  class IntegerInteraction < ActiveInteraction::Base
@@ -751,6 +596,167 @@ IntegerInteraction.run!(limit1: "08", limit2: "08", limit3: "08")
751
596
  ActiveInteraction::InvalidInteractionError: Limit2 is not a valid integer, Limit3 is not a valid integer
752
597
  ```
753
598
 
599
+ ### Advanced Filters
600
+
601
+ #### Interface
602
+
603
+ Interface filters allow you to specify an interface that the passed value must
604
+ meet in order to pass. The name of the interface is used to look for a constant
605
+ inside the ancestor listing for the passed value. This allows for a variety of
606
+ checks depending on what's passed. Class instances are checked for an included
607
+ module or an inherited ancestor class. Classes are checked for an extended
608
+ module or an inherited ancestor class. Modules are checked for an extended
609
+ module.
610
+
611
+ ``` rb
612
+ class InterfaceInteraction < ActiveInteraction::Base
613
+ interface :exception
614
+
615
+ def execute
616
+ exception
617
+ end
618
+ end
619
+
620
+ InterfaceInteraction.run!(exception: Exception)
621
+ # ActiveInteraction::InvalidInteractionError: Exception is not a valid interface
622
+ InterfaceInteraction.run!(exception: NameError) # a subclass of Exception
623
+ # => NameError
624
+ ```
625
+
626
+ You can use `:from` to specify a class or module. This would be the equivalent
627
+ of what's above.
628
+
629
+ ```rb
630
+ class InterfaceInteraction < ActiveInteraction::Base
631
+ interface :error,
632
+ from: Exception
633
+
634
+ def execute
635
+ error
636
+ end
637
+ end
638
+ ```
639
+
640
+ You can also create an anonymous interface on the fly by passing the `methods`
641
+ option.
642
+
643
+ ``` rb
644
+ class InterfaceInteraction < ActiveInteraction::Base
645
+ interface :serializer,
646
+ methods: %i[dump load]
647
+
648
+ def execute
649
+ input = '{ "is_json" : true }'
650
+ object = serializer.load(input)
651
+ output = serializer.dump(object)
652
+
653
+ output
654
+ end
655
+ end
656
+
657
+ require 'json'
658
+
659
+ InterfaceInteraction.run!(serializer: Object.new)
660
+ # ActiveInteraction::InvalidInteractionError: Serializer is not a valid interface
661
+ InterfaceInteraction.run!(serializer: JSON)
662
+ # => "{\"is_json\":true}"
663
+ ```
664
+
665
+ #### Object
666
+
667
+ Object filters allow you to require an instance of a particular class or one of
668
+ its subclasses.
669
+
670
+ ``` rb
671
+ class Cow
672
+ def moo
673
+ 'Moo!'
674
+ end
675
+ end
676
+
677
+ class ObjectInteraction < ActiveInteraction::Base
678
+ object :cow
679
+
680
+ def execute
681
+ cow.moo
682
+ end
683
+ end
684
+
685
+ ObjectInteraction.run!(cow: Object.new)
686
+ # ActiveInteraction::InvalidInteractionError: Cow is not a valid object
687
+ ObjectInteraction.run!(cow: Cow.new)
688
+ # => "Moo!"
689
+ ```
690
+
691
+ The class name is automatically determined by the filter name. If your filter
692
+ name is different than your class name, use the `class` option. It can be
693
+ either the class, a string, or a symbol.
694
+
695
+ ``` rb
696
+ object :dolly1,
697
+ class: Sheep
698
+ object :dolly2,
699
+ class: 'Sheep'
700
+ object :dolly3,
701
+ class: :Sheep
702
+ ```
703
+
704
+ If you have value objects or you would like to build one object from another,
705
+ you can use the `converter` option. It is only called if the value provided is
706
+ not an instance of the class or one of its subclasses. The `converter` option
707
+ accepts a symbol that specifies a class method on the object class or a proc.
708
+ Both will be passed the value and any errors thrown inside the converter will
709
+ cause the value to be considered invalid. Any returned value that is not the
710
+ correct class will also be treated as invalid. Any `default` that is not an
711
+ instance of the class or subclass and is not `nil` will also be converted.
712
+
713
+ ``` rb
714
+ class ObjectInteraction < ActiveInteraction::Base
715
+ object :ip_address,
716
+ class: IPAddr,
717
+ converter: :new
718
+
719
+ def execute
720
+ ip_address
721
+ end
722
+ end
723
+
724
+ ObjectInteraction.run!(ip_address: '192.168.1.1')
725
+ # #<IPAddr: IPv4:192.168.1.1/255.255.255.255>
726
+
727
+ ObjectInteraction.run!(ip_address: 1)
728
+ # ActiveInteraction::InvalidInteractionError: Ip address is not a valid object
729
+ ```
730
+
731
+ #### Record
732
+
733
+ Record filters allow you to require an instance of a particular class (or one
734
+ of its subclasses) or a value that can be used to locate an instance of the
735
+ object. If the value does not match, it will call `find` on the class of the
736
+ record. This is particularly useful when working with ActiveRecord objects.
737
+ Like an object filter, the class is derived from the name passed but can be
738
+ specified with the `class` option. Any `default` that is not an instance of the
739
+ class or subclass and is not `nil` will also be found. Blank strings passed in
740
+ will be treated as `nil`.
741
+
742
+ ``` rb
743
+ class RecordInteraction < ActiveInteraction::Base
744
+ record :encoding
745
+
746
+ def execute
747
+ encoding
748
+ end
749
+ end
750
+
751
+ > RecordInteraction.run!(encoding: Encoding::US_ASCII)
752
+ => #<Encoding:US-ASCII>
753
+
754
+ > RecordInteraction.run!(encoding: 'ascii')
755
+ => #<Encoding:US-ASCII>
756
+ ```
757
+
758
+ A different method can be specified by providing a symbol to the `finder` option.
759
+
754
760
  ## Rails
755
761
 
756
762
  ActiveInteraction plays nicely with Rails. You can use interactions to handle
@@ -1492,13 +1498,13 @@ ActiveInteraction is licensed under [the MIT License][].
1492
1498
 
1493
1499
  [activeinteraction]: https://github.com/AaronLasseigne/active_interaction
1494
1500
  [API Documentation]: http://rubydoc.info/github/AaronLasseigne/active_interaction
1495
- [semantic versioning]: http://semver.org/spec/v2.0.0.html
1501
+ [Semantic Versioning]: http://semver.org/spec/v2.0.0.html
1496
1502
  [GitHub releases]: https://github.com/AaronLasseigne/active_interaction/releases
1497
1503
  [aaron lasseigne]: https://github.com/AaronLasseigne
1498
1504
  [taylor fausak]: https://github.com/tfausak
1499
1505
  [our contribution guidelines]: CONTRIBUTING.md
1500
1506
  [complete list of contributors]: https://github.com/AaronLasseigne/active_interaction/graphs/contributors
1501
- [the mit license]: LICENSE.md
1507
+ [the MIT License]: LICENSE.md
1502
1508
  [formtastic]: https://rubygems.org/gems/formtastic
1503
1509
  [simple_form]: https://rubygems.org/gems/simple_form
1504
1510
  [the filters section]: #filters
@@ -49,8 +49,10 @@ module ActiveInteraction
49
49
  children = []
50
50
 
51
51
  unless filters.empty?
52
- value.each do |item|
53
- children.push(filters[:'0'].process(item, context))
52
+ value.map! do |item|
53
+ result = filters[:'0'].process(item, context)
54
+ children.push(result)
55
+ result.value
54
56
  end
55
57
  end
56
58
 
@@ -60,11 +62,15 @@ module ActiveInteraction
60
62
  private
61
63
 
62
64
  def index_errors?
65
+ klass = 'ActiveRecord'.safe_constantize
66
+
63
67
  default =
64
- if ::ActiveRecord.respond_to?(:index_nested_attribute_errors)
65
- ::ActiveRecord.index_nested_attribute_errors # Moved to here in Rails 7.0
68
+ if !klass
69
+ false
70
+ elsif klass.respond_to?(:index_nested_attribute_errors)
71
+ klass.index_nested_attribute_errors # Moved to here in Rails 7.0
66
72
  else
67
- ::ActiveRecord::Base.index_nested_attribute_errors
73
+ klass::Base.index_nested_attribute_errors
68
74
  end
69
75
  options.fetch(:index_errors, default)
70
76
  end
@@ -175,10 +175,14 @@ module ActiveInteraction
175
175
  end
176
176
 
177
177
  def convert(inputs)
178
+ return inputs if inputs.is_a?(self.class)
178
179
  return inputs.stringify_keys if inputs.is_a?(Hash)
179
- return inputs.to_unsafe_h.stringify_keys if inputs.is_a?(ActionController::Parameters)
180
180
 
181
- raise ArgumentError, 'inputs must be a hash or ActionController::Parameters'
181
+ parameters = 'ActionController::Parameters'
182
+ klass = parameters.safe_constantize
183
+ return inputs.to_unsafe_h.stringify_keys if klass && inputs.is_a?(klass)
184
+
185
+ raise ArgumentError, 'inputs must be a hash, ActiveInteraction::Inputs, or ActionController::Parameters'
182
186
  end
183
187
 
184
188
  def assign_to_grouped_input!(inputs, key, index, value)
@@ -4,5 +4,5 @@ module ActiveInteraction
4
4
  # The version number.
5
5
  #
6
6
  # @return [Gem::Version]
7
- VERSION = Gem::Version.new('5.0.0')
7
+ VERSION = Gem::Version.new('5.1.0')
8
8
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_model'
4
- require 'active_record'
5
4
  require 'active_support/core_ext/hash/indifferent_access'
6
- require 'action_controller'
7
5
 
8
6
  # Manage application specific business logic.
9
7
  #
@@ -294,17 +294,28 @@ describe ActiveInteraction::Base do
294
294
  let(:z) { rand }
295
295
 
296
296
  context 'with valid composition' do
297
- before do
298
- inputs[:x] = x
299
- inputs[:z] = z
300
- end
297
+ context 'when inputs is a hash' do
298
+ let(:inputs) { { x: x, z: z } }
299
+
300
+ it 'is valid' do
301
+ expect(outcome).to be_valid
302
+ end
301
303
 
302
- it 'is valid' do
303
- expect(outcome).to be_valid
304
+ it 'returns the sum' do
305
+ expect(result).to eql x + z
306
+ end
304
307
  end
305
308
 
306
- it 'returns the sum' do
307
- expect(result).to eql x + z
309
+ context 'when inputs is an ActiveInteraction::Inputs' do
310
+ let(:inputs) { ActiveInteraction::Inputs.new({ x: x, z: z }, described_class.new) }
311
+
312
+ it 'is valid' do
313
+ expect(outcome).to be_valid
314
+ end
315
+
316
+ it 'returns the sum' do
317
+ expect(result).to eql x + z
318
+ end
308
319
  end
309
320
  end
310
321
 
@@ -123,10 +123,10 @@ describe ActiveInteraction::Errors do
123
123
  let(:other) { described_class.new(klass.new) }
124
124
 
125
125
  before do
126
- if ::ActiveRecord.respond_to?(:index_nested_attribute_errors)
127
- allow(::ActiveRecord).to receive(:index_nested_attribute_errors).and_return(true)
126
+ if ActiveRecord.respond_to?(:index_nested_attribute_errors)
127
+ allow(ActiveRecord).to receive(:index_nested_attribute_errors).and_return(true)
128
128
  else
129
- allow(::ActiveRecord::Base).to receive(:index_nested_attribute_errors).and_return(true)
129
+ allow(ActiveRecord::Base).to receive(:index_nested_attribute_errors).and_return(true)
130
130
  end
131
131
 
132
132
  other.add(:'array[0]')
@@ -66,6 +66,16 @@ describe ActiveInteraction::ArrayFilter, :filter do
66
66
  end
67
67
  end
68
68
 
69
+ context 'with a nested filter where the value transforms' do
70
+ let(:block) { proc { symbol } }
71
+ let(:name) { :test }
72
+ let(:value) { ['test'] }
73
+
74
+ it 'returns the transformed value' do
75
+ expect(result.value).to eql [:test]
76
+ end
77
+ end
78
+
69
79
  context 'with a nested filter' do
70
80
  let(:block) { proc { array } }
71
81
 
@@ -81,7 +91,7 @@ describe ActiveInteraction::ArrayFilter, :filter do
81
91
  expect(result.children.size).to be 2
82
92
  result.children.each do |child|
83
93
  expect(child).to be_an_instance_of ActiveInteraction::ArrayInput
84
- expect(child.value).to be child_value
94
+ expect(child.value).to eql child_value
85
95
  end
86
96
  end
87
97
 
@@ -136,10 +146,10 @@ describe ActiveInteraction::ArrayFilter, :filter do
136
146
 
137
147
  context 'when ActiveRecord.index_nested_attribute_errors is true' do
138
148
  before do
139
- if ::ActiveRecord.respond_to?(:index_nested_attribute_errors)
140
- allow(::ActiveRecord).to receive(:index_nested_attribute_errors).and_return(true)
149
+ if ActiveRecord.respond_to?(:index_nested_attribute_errors)
150
+ allow(ActiveRecord).to receive(:index_nested_attribute_errors).and_return(true)
141
151
  else
142
- allow(::ActiveRecord::Base).to receive(:index_nested_attribute_errors).and_return(true)
152
+ allow(ActiveRecord::Base).to receive(:index_nested_attribute_errors).and_return(true)
143
153
  end
144
154
  end
145
155
 
@@ -44,6 +44,14 @@ describe ActiveInteraction::Inputs do
44
44
  end
45
45
  end
46
46
 
47
+ context 'with ActiveInteraction::Inputs inputs' do
48
+ let(:args) { described_class.new({ key: :value }, base_class.new) }
49
+
50
+ it 'does not raise an error' do
51
+ expect { result }.to_not raise_error
52
+ end
53
+ end
54
+
47
55
  context 'with ActionController::Parameters inputs' do
48
56
  let(:args) { ::ActionController::Parameters.new }
49
57
 
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'RecordIntegration' do
4
+ it_behaves_like 'an interaction', :record, -> { Encoding::US_ASCII }, class: Encoding
5
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,7 @@ require 'i18n'
2
2
  I18n.config.enforce_available_locales = true if I18n.config.respond_to?(:enforce_available_locales)
3
3
 
4
4
  require 'active_interaction'
5
+ require 'active_record'
5
6
 
6
7
  Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
7
8
 
@@ -10,10 +11,10 @@ RSpec.configure do |config|
10
11
  config.filter_run_including :focus
11
12
 
12
13
  config.before(:suite) do
13
- if ::ActiveRecord.respond_to?(:index_nested_attribute_errors)
14
- ::ActiveRecord.index_nested_attribute_errors = false
14
+ if ActiveRecord.respond_to?(:index_nested_attribute_errors)
15
+ ActiveRecord.index_nested_attribute_errors = false
15
16
  else
16
- ::ActiveRecord::Base.index_nested_attribute_errors = false
17
+ ActiveRecord::Base.index_nested_attribute_errors = false
17
18
  end
18
19
  end
19
20
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_interaction
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Lasseigne
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-24 00:00:00.000000000 Z
12
+ date: 2022-07-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: rails
15
+ name: activemodel
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - ">="
@@ -31,6 +31,54 @@ dependencies:
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '8'
34
+ - !ruby/object:Gem::Dependency
35
+ name: activesupport
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '5.2'
41
+ - - "<"
42
+ - !ruby/object:Gem::Version
43
+ version: '8'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '5.2'
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: '8'
54
+ - !ruby/object:Gem::Dependency
55
+ name: actionpack
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: activerecord
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
34
82
  - !ruby/object:Gem::Dependency
35
83
  name: kramdown
36
84
  requirement: !ruby/object:Gem::Requirement
@@ -241,6 +289,7 @@ files:
241
289
  - spec/active_interaction/integration/integer_interaction_spec.rb
242
290
  - spec/active_interaction/integration/interface_interaction_spec.rb
243
291
  - spec/active_interaction/integration/object_interaction_spec.rb
292
+ - spec/active_interaction/integration/record_integration_spec.rb
244
293
  - spec/active_interaction/integration/string_interaction_spec.rb
245
294
  - spec/active_interaction/integration/symbol_interaction_spec.rb
246
295
  - spec/active_interaction/integration/time_interaction_spec.rb
@@ -318,6 +367,7 @@ test_files:
318
367
  - spec/active_interaction/integration/integer_interaction_spec.rb
319
368
  - spec/active_interaction/integration/interface_interaction_spec.rb
320
369
  - spec/active_interaction/integration/object_interaction_spec.rb
370
+ - spec/active_interaction/integration/record_integration_spec.rb
321
371
  - spec/active_interaction/integration/string_interaction_spec.rb
322
372
  - spec/active_interaction/integration/symbol_interaction_spec.rb
323
373
  - spec/active_interaction/integration/time_interaction_spec.rb