active_interaction 3.8.0 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +187 -0
- data/CONTRIBUTING.md +1 -1
- data/README.md +93 -107
- data/lib/active_interaction.rb +1 -7
- data/lib/active_interaction/base.rb +23 -26
- data/lib/active_interaction/concerns/active_modelable.rb +1 -3
- data/lib/active_interaction/concerns/active_recordable.rb +1 -6
- data/lib/active_interaction/concerns/hashable.rb +0 -1
- data/lib/active_interaction/concerns/missable.rb +0 -1
- data/lib/active_interaction/concerns/runnable.rb +15 -25
- data/lib/active_interaction/errors.rb +6 -13
- data/lib/active_interaction/filter.rb +51 -37
- data/lib/active_interaction/filter_column.rb +0 -3
- data/lib/active_interaction/filters/abstract_date_time_filter.rb +34 -36
- data/lib/active_interaction/filters/abstract_numeric_filter.rb +27 -17
- data/lib/active_interaction/filters/array_filter.rb +57 -36
- data/lib/active_interaction/filters/boolean_filter.rb +26 -12
- data/lib/active_interaction/filters/date_filter.rb +1 -2
- data/lib/active_interaction/filters/date_time_filter.rb +1 -2
- data/lib/active_interaction/filters/decimal_filter.rb +10 -28
- data/lib/active_interaction/filters/file_filter.rb +6 -5
- data/lib/active_interaction/filters/float_filter.rb +1 -2
- data/lib/active_interaction/filters/hash_filter.rb +37 -27
- data/lib/active_interaction/filters/integer_filter.rb +7 -8
- data/lib/active_interaction/filters/interface_filter.rb +48 -14
- data/lib/active_interaction/filters/object_filter.rb +23 -50
- data/lib/active_interaction/filters/record_filter.rb +10 -35
- data/lib/active_interaction/filters/string_filter.rb +21 -12
- data/lib/active_interaction/filters/symbol_filter.rb +13 -7
- data/lib/active_interaction/filters/time_filter.rb +24 -19
- data/lib/active_interaction/grouped_input.rb +0 -3
- data/lib/active_interaction/inputs.rb +95 -0
- data/lib/active_interaction/modules/validation.rb +9 -12
- data/lib/active_interaction/version.rb +1 -3
- data/spec/active_interaction/base_spec.rb +22 -35
- data/spec/active_interaction/concerns/active_modelable_spec.rb +0 -2
- data/spec/active_interaction/concerns/active_recordable_spec.rb +0 -2
- data/spec/active_interaction/concerns/hashable_spec.rb +0 -2
- data/spec/active_interaction/concerns/missable_spec.rb +0 -2
- data/spec/active_interaction/concerns/runnable_spec.rb +26 -12
- data/spec/active_interaction/errors_spec.rb +4 -25
- data/spec/active_interaction/filter_column_spec.rb +0 -2
- data/spec/active_interaction/filter_spec.rb +0 -2
- data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +1 -3
- data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +1 -3
- data/spec/active_interaction/filters/array_filter_spec.rb +41 -15
- data/spec/active_interaction/filters/boolean_filter_spec.rb +58 -4
- data/spec/active_interaction/filters/date_filter_spec.rb +43 -3
- data/spec/active_interaction/filters/date_time_filter_spec.rb +43 -3
- data/spec/active_interaction/filters/decimal_filter_spec.rb +57 -3
- data/spec/active_interaction/filters/file_filter_spec.rb +1 -3
- data/spec/active_interaction/filters/float_filter_spec.rb +60 -4
- data/spec/active_interaction/filters/hash_filter_spec.rb +19 -9
- data/spec/active_interaction/filters/integer_filter_spec.rb +49 -7
- data/spec/active_interaction/filters/interface_filter_spec.rb +397 -24
- data/spec/active_interaction/filters/object_filter_spec.rb +23 -59
- data/spec/active_interaction/filters/record_filter_spec.rb +23 -49
- data/spec/active_interaction/filters/string_filter_spec.rb +15 -3
- data/spec/active_interaction/filters/symbol_filter_spec.rb +15 -3
- data/spec/active_interaction/filters/time_filter_spec.rb +65 -3
- data/spec/active_interaction/grouped_input_spec.rb +0 -2
- data/spec/active_interaction/i18n_spec.rb +3 -7
- data/spec/active_interaction/{modules/input_processor_spec.rb → inputs_spec.rb} +3 -5
- data/spec/active_interaction/integration/array_interaction_spec.rb +18 -22
- data/spec/active_interaction/integration/boolean_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/date_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/date_time_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/file_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/float_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/hash_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/integer_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/interface_interaction_spec.rb +1 -3
- data/spec/active_interaction/integration/object_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/string_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/symbol_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/time_interaction_spec.rb +14 -18
- data/spec/active_interaction/modules/validation_spec.rb +1 -3
- data/spec/spec_helper.rb +2 -6
- data/spec/support/concerns.rb +0 -2
- data/spec/support/filters.rb +13 -9
- data/spec/support/interactions.rb +22 -14
- metadata +81 -57
- data/lib/active_interaction/backports.rb +0 -59
- data/lib/active_interaction/filters/abstract_filter.rb +0 -19
- data/lib/active_interaction/modules/input_processor.rb +0 -52
- data/spec/active_interaction/filters/abstract_filter_spec.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65047712d1df9c67700202a27f83054c30fccbdf3d7bf7e0478c01e5bea07fc8
|
4
|
+
data.tar.gz: b39bb6c7d8784cf842eb266e3955fdbc1082c5a4f96c30bdcbdd10074294ea6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ca04e342b3b82a29724e113600ca12bebdc303de3c66c51299fc490cd8686e3a062c77498ccd53e33f02a9dc0e05dc5a44ee26be911af6e59bfcca1b2d41d65
|
7
|
+
data.tar.gz: a09744ecbd57a5c69ee845235942c2f2063bfb70f509a9bd6384f45690a35218e6c48c632b2388701f910746614b43b040803329e5310e24ea291267eddd3234
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,182 @@
|
|
1
|
+
# [4.0.1][] (2021-05-26)
|
2
|
+
|
3
|
+
## Fix
|
4
|
+
|
5
|
+
- Fix regression of filter name relaxing.
|
6
|
+
- [#495][] - Fix time filter ignoring time zones
|
7
|
+
|
8
|
+
# [4.0.0][] (2021-01-10)
|
9
|
+
|
10
|
+
## Changed
|
11
|
+
|
12
|
+
- drop support for Ruby < 2.5, added support for Ruby 3.0
|
13
|
+
- drop support for Rails < 5.0, added support for Rails 6.1
|
14
|
+
- [#398][] - Predicate methods have been removed.
|
15
|
+
([how to upgrade](#predicate-methods))
|
16
|
+
- [#412][] - Filters will now treat blank string values as `nil`
|
17
|
+
(except `string` and `symbol`). ([how to upgrade](#blank-values-treated-as-nil-for-filters))
|
18
|
+
- [#392][] - Integer parsing now defaults the base to 10.
|
19
|
+
([how to upgrade](#integer-parsing-base-now-10))
|
20
|
+
- The `inputs` method now returns an `ActiveInteraction::Input` instead of a
|
21
|
+
hash. The `ActiveInteraction::Input` class still responds to all hash methods.
|
22
|
+
- The `object` and `record` filters now only accept an instance of the correct
|
23
|
+
class type or a subclass of the correct class. They no longer allow you to
|
24
|
+
check for included modules. ([how to upgrade](#object-and-record-filter-changes))
|
25
|
+
- The `interface` filter will now look for an ancestor of the value passed
|
26
|
+
based on the name of the interface or the value passed in the `from` option.
|
27
|
+
- The `InvalidClassError` has been replaced by `InvalidNameError`.
|
28
|
+
- When introspecting an array filter, the inner filter is referenced by :'0'
|
29
|
+
instead of the singularized version of the array filter name.
|
30
|
+
|
31
|
+
## Added
|
32
|
+
|
33
|
+
- Implicit coercion of types are now supported in filters (e.g. to_str, to_int,
|
34
|
+
etc).
|
35
|
+
- The `interface` and `record` filters, when used as an inner filter for an
|
36
|
+
`array`, will have their `from/class` option set to a singularized version of
|
37
|
+
the `array` filter name.
|
38
|
+
|
39
|
+
## Upgrading
|
40
|
+
|
41
|
+
### Predicate Methods
|
42
|
+
|
43
|
+
We've removed the predicate methods that were automatically generated for each
|
44
|
+
input. They would return true if an input was not `nil`. They can be manually
|
45
|
+
replaced with that same check.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
# v3.8
|
49
|
+
class Example < ActiveInteraction::Base
|
50
|
+
string :first_name
|
51
|
+
|
52
|
+
validates :first_name,
|
53
|
+
presence: true,
|
54
|
+
if: :first_name?
|
55
|
+
|
56
|
+
def execute
|
57
|
+
# ...
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# v4.0
|
62
|
+
class Example < ActiveInteraction::Base
|
63
|
+
string :first_name
|
64
|
+
|
65
|
+
validates :first_name,
|
66
|
+
presence: true,
|
67
|
+
unless: 'first_name.nil?'
|
68
|
+
|
69
|
+
def execute
|
70
|
+
# ...
|
71
|
+
end
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
## Blank Values Treated As `nil` For Filters
|
76
|
+
|
77
|
+
In an effort to improve form support, strings that are `blank?` will
|
78
|
+
be converted into `nil` for all filters except `string` and `symbol`.
|
79
|
+
Previously, blank strings would have cased `:invalid_type` errors but
|
80
|
+
they'll now cause a `:missing` error which should be more form
|
81
|
+
friendly. If the filter has a default, the blank string will cause
|
82
|
+
the default to be used.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class Example < ActiveInteraction::Base
|
86
|
+
integer :i
|
87
|
+
boolean :b, default: false
|
88
|
+
|
89
|
+
def execute
|
90
|
+
[i, b]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# v3.8
|
95
|
+
Example.run(i: '', b: '').errors.details
|
96
|
+
=> {:i=>[{:error=>:invalid_type, :type=>"integer"}], :b=>[{:error=>:invalid_type, :type=>"boolean"}]}
|
97
|
+
|
98
|
+
# v4.0
|
99
|
+
Example.run(i: '', b: '').errors.details
|
100
|
+
=> {:i=>[{:error=>:missing}]}
|
101
|
+
|
102
|
+
# v3.8
|
103
|
+
Example.run(i: 0, b: '').errors.details
|
104
|
+
=> {:b=>[{:error=>:invalid_type, :type=>"boolean"}]}
|
105
|
+
|
106
|
+
# v4.0
|
107
|
+
Example.run(i: 0, b: '').errors.details
|
108
|
+
=> {}
|
109
|
+
|
110
|
+
Example.run(i: 0, b: '').result
|
111
|
+
=> [0, false] # the default is used for `:b`
|
112
|
+
```
|
113
|
+
|
114
|
+
### Integer Parsing Base Now 10
|
115
|
+
|
116
|
+
Integers are parsed using `Integer`. By default this meant that when
|
117
|
+
strings were parsed, radix indicators (0, 0b, and 0x) were honored. Now
|
118
|
+
we're defaulting the base to `10`. This means all strings will be parsed
|
119
|
+
as though they are base 10.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
class Example < ActiveInteraction::Base
|
123
|
+
integer :x
|
124
|
+
|
125
|
+
def execute
|
126
|
+
x
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# v3.8
|
131
|
+
Example.run!(x: '010')
|
132
|
+
# => 8
|
133
|
+
|
134
|
+
# v4.0
|
135
|
+
Example.run!(x: '010')
|
136
|
+
# => 10
|
137
|
+
```
|
138
|
+
|
139
|
+
If you want the old behavior that respected the radix you can pass `0`
|
140
|
+
as the base.
|
141
|
+
|
142
|
+
```diff
|
143
|
+
- integer :x
|
144
|
+
+ integer :x, base: 0
|
145
|
+
```
|
146
|
+
|
147
|
+
With that change, we can see the radix is respected again.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
# v4.0.0
|
151
|
+
Example.run!(x: '010')
|
152
|
+
# => 8
|
153
|
+
```
|
154
|
+
|
155
|
+
### Object and Record Filter Changes
|
156
|
+
|
157
|
+
The `object` and `record` filters used to be able to check for included modules
|
158
|
+
in addition to a class type. This has been removed. If you want any object that
|
159
|
+
has a particular module included, you'll need to use the newly expanded
|
160
|
+
`interface` filter.
|
161
|
+
|
162
|
+
# [3.8.3][] (2020-04-22)
|
163
|
+
|
164
|
+
## Fixed
|
165
|
+
|
166
|
+
- [486][] `valid?` returns true if block not called and error added in execute around callback.
|
167
|
+
|
168
|
+
# [3.8.2][] (2020-04-22)
|
169
|
+
|
170
|
+
## Fixed
|
171
|
+
|
172
|
+
- [479][] Composed interactions that throw errors now show a complete backtrace instead of ending at the `run!` of the outermost interaction.
|
173
|
+
|
174
|
+
# [3.8.1][] (2020-04-04)
|
175
|
+
|
176
|
+
## Fixed
|
177
|
+
|
178
|
+
- The implementation for providing a failing interaction on `InvalidInteractionError` was a breaking API change. It now works without breaking the API.
|
179
|
+
|
1
180
|
# [3.8.0][] (2020-02-28)
|
2
181
|
|
3
182
|
## Added
|
@@ -759,6 +938,10 @@ Example.run
|
|
759
938
|
|
760
939
|
- Initial release.
|
761
940
|
|
941
|
+
[4.0.0]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.3...v4.0.0
|
942
|
+
[3.8.3]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.2...v3.8.3
|
943
|
+
[3.8.2]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.1...v3.8.2
|
944
|
+
[3.8.1]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.0...v3.8.1
|
762
945
|
[3.8.0]: https://github.com/AaronLasseigne/active_interaction/compare/v3.7.1...v3.8.0
|
763
946
|
[3.7.1]: https://github.com/AaronLasseigne/active_interaction/compare/v3.7.0...v3.7.1
|
764
947
|
[3.7.0]: https://github.com/AaronLasseigne/active_interaction/compare/v3.6.2...v3.7.0
|
@@ -956,3 +1139,7 @@ Example.run
|
|
956
1139
|
[#457]: https://github.com/AaronLasseigne/active_interaction/issues/457
|
957
1140
|
[#477]: https://github.com/AaronLasseigne/active_interaction/issues/477
|
958
1141
|
[#476]: https://github.com/AaronLasseigne/active_interaction/issues/476
|
1142
|
+
[#479]: https://github.com/AaronLasseigne/active_interaction/issues/479
|
1143
|
+
[#486]: https://github.com/AaronLasseigne/active_interaction/issues/486
|
1144
|
+
[#392]: https://github.com/AaronLasseigne/active_interaction/issues/392
|
1145
|
+
[#398]: https://github.com/AaronLasseigne/active_interaction/issues/398
|
data/CONTRIBUTING.md
CHANGED
@@ -10,4 +10,4 @@
|
|
10
10
|
|
11
11
|
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
12
|
|
13
|
-
[fork]: https://github.com/
|
13
|
+
[fork]: https://github.com/AaronLasseigne/active_interaction/fork
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ ActiveInteraction manages application-specific business logic.
|
|
4
4
|
It's an implementation of the command pattern in Ruby.
|
5
5
|
|
6
6
|
[![Version](https://img.shields.io/gem/v/active_interaction.svg?style=flat-square)](https://rubygems.org/gems/active_interaction)
|
7
|
-
[![
|
7
|
+
[![Test](https://img.shields.io/github/workflow/status/AaronLasseigne/active_interaction/Test?label=Test&style=flat-square)](https://github.com/AaronLasseigne/active_interaction/actions?query=workflow%3ATest)
|
8
8
|
[![Coverage](https://img.shields.io/coveralls/github/AaronLasseigne/active_interaction.svg?style=flat-square)](https://coveralls.io/r/orgsync/active_interaction)
|
9
9
|
[![Climate](https://img.shields.io/codeclimate/maintainability/orgsync/active_interaction.svg?style=flat-square)](https://codeclimate.com/github/orgsync/active_interaction)
|
10
10
|
|
@@ -55,7 +55,6 @@ handles your verbs.
|
|
55
55
|
- [Forms](#forms)
|
56
56
|
- [Grouped inputs](#grouped-inputs)
|
57
57
|
- [Optional inputs](#optional-inputs)
|
58
|
-
- [Predicates](#predicates)
|
59
58
|
- [Translations](#translations)
|
60
59
|
- [Credits](#credits)
|
61
60
|
|
@@ -66,23 +65,19 @@ handles your verbs.
|
|
66
65
|
Add it to your Gemfile:
|
67
66
|
|
68
67
|
``` rb
|
69
|
-
gem 'active_interaction', '~>
|
68
|
+
gem 'active_interaction', '~> 4.0'
|
70
69
|
```
|
71
70
|
|
72
71
|
Or install it manually:
|
73
72
|
|
74
73
|
``` sh
|
75
|
-
$ gem install active_interaction --version '~>
|
74
|
+
$ gem install active_interaction --version '~> 4.0'
|
76
75
|
```
|
77
76
|
|
78
77
|
This project uses [Semantic Versioning][]. Check out [GitHub releases][] for a
|
79
78
|
detailed list of changes. For help upgrading to version 2, please read [the
|
80
79
|
announcement post][].
|
81
80
|
|
82
|
-
ActiveInteraction works with Ruby 2.0 through 2.6 and ActiveModel 4.0 through
|
83
|
-
6.0. If you want to use ActiveInteraction with an older version of Ruby or
|
84
|
-
ActiveModel, use ActiveInteraction < 3.0.0.
|
85
|
-
|
86
81
|
## Basic usage
|
87
82
|
|
88
83
|
To define an interaction, create a subclass of `ActiveInteraction::Base`. Then
|
@@ -241,7 +236,8 @@ ArrayInteraction.run!(toppings: [:cheese, 'pepperoni'])
|
|
241
236
|
# => 2
|
242
237
|
```
|
243
238
|
|
244
|
-
Use a block to constrain the types of elements an array can contain.
|
239
|
+
Use a block to constrain the types of elements an array can contain. Note that
|
240
|
+
you can only have one filter inside an array block, and it must not have a name.
|
245
241
|
|
246
242
|
``` rb
|
247
243
|
array :birthdays do
|
@@ -249,19 +245,29 @@ array :birthdays do
|
|
249
245
|
end
|
250
246
|
```
|
251
247
|
|
252
|
-
|
253
|
-
|
248
|
+
For `interface`, `object`, and `record` filters, the name of the array filter
|
249
|
+
will be singularized and used to determine the type of value passed. In the
|
250
|
+
example below, the objects passed would need to be of type `Cow`.
|
254
251
|
|
255
252
|
``` rb
|
256
253
|
array :cows do
|
257
|
-
object
|
254
|
+
object
|
255
|
+
end
|
256
|
+
```
|
257
|
+
|
258
|
+
You can override this by passing the necessary information to the inner filter.
|
259
|
+
|
260
|
+
```ruby
|
261
|
+
array :managers do
|
262
|
+
object class: People
|
258
263
|
end
|
259
264
|
```
|
260
265
|
|
261
266
|
### Boolean
|
262
267
|
|
263
|
-
Boolean filters convert the strings `"1"` and `"
|
264
|
-
`true`. They also convert `"0"` and `"
|
268
|
+
Boolean filters convert the strings `"1"`, `"true"`, and `"on"`
|
269
|
+
(case-insensitive) into `true`. They also convert `"0"`, `"false"`, and `"off"`
|
270
|
+
into `false`. Blank strings will be treated as `nil`.
|
265
271
|
|
266
272
|
``` rb
|
267
273
|
class BooleanInteraction < ActiveInteraction::Base
|
@@ -353,8 +359,45 @@ hash :stuff,
|
|
353
359
|
|
354
360
|
### Interface
|
355
361
|
|
356
|
-
Interface filters allow you to specify
|
357
|
-
|
362
|
+
Interface filters allow you to specify an interface that the passed value must
|
363
|
+
meet in order to pass. The name of the interface is used to look for a constant
|
364
|
+
inside the ancestor listing for the passed value. This allows for a variety of
|
365
|
+
checks depending on what's passed. Class instances are checked for an included
|
366
|
+
module or an inherited ancestor class. Classes are checked for an extended
|
367
|
+
module or an inherited ancestor class. Modules are checked for an extended
|
368
|
+
module.
|
369
|
+
|
370
|
+
``` rb
|
371
|
+
class InterfaceInteraction < ActiveInteraction::Base
|
372
|
+
interface :exception
|
373
|
+
|
374
|
+
def execute
|
375
|
+
exception
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
InterfaceInteraction.run!(exception: Exception)
|
380
|
+
# ActiveInteraction::InvalidInteractionError: Exception is not a valid interface
|
381
|
+
InterfaceInteraction.run!(exception: NameError) # a subclass of Exception
|
382
|
+
# => NameError
|
383
|
+
```
|
384
|
+
|
385
|
+
You can use `:from` to specify a class or module. This would be the equivalent
|
386
|
+
of what's above.
|
387
|
+
|
388
|
+
```rb
|
389
|
+
class InterfaceInteraction < ActiveInteraction::Base
|
390
|
+
interface :error,
|
391
|
+
from: Exception
|
392
|
+
|
393
|
+
def execute
|
394
|
+
error
|
395
|
+
end
|
396
|
+
end
|
397
|
+
```
|
398
|
+
|
399
|
+
You can also create an anonymous interface on the fly by passing the `methods`
|
400
|
+
option.
|
358
401
|
|
359
402
|
``` rb
|
360
403
|
class InterfaceInteraction < ActiveInteraction::Base
|
@@ -378,30 +421,10 @@ InterfaceInteraction.run!(serializer: JSON)
|
|
378
421
|
# => "{\"is_json\":true}"
|
379
422
|
```
|
380
423
|
|
381
|
-
NOTE: The `methods` option is optional.
|
382
|
-
|
383
|
-
```rb
|
384
|
-
class InterfaceInteraction < ActiveInteraction::Base
|
385
|
-
interface :anything
|
386
|
-
|
387
|
-
def execute
|
388
|
-
anything.class
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
require 'json'
|
393
|
-
|
394
|
-
InterfaceInteraction.run!(anything: Hash.new)
|
395
|
-
# => Hash
|
396
|
-
InterfaceInteraction.run!
|
397
|
-
# => NilClass
|
398
|
-
```
|
399
|
-
|
400
424
|
### Object
|
401
425
|
|
402
|
-
Object filters allow you to require an instance of a particular class
|
403
|
-
|
404
|
-
it also works with classes that have mixed modules in with `include`.
|
426
|
+
Object filters allow you to require an instance of a particular class or one of
|
427
|
+
its subclasses.
|
405
428
|
|
406
429
|
``` rb
|
407
430
|
class Cow
|
@@ -438,8 +461,8 @@ object :dolly3,
|
|
438
461
|
```
|
439
462
|
|
440
463
|
If you have value objects or you would like to build one object from another,
|
441
|
-
you can use the `converter` option. It is only called if the value provided
|
442
|
-
not
|
464
|
+
you can use the `converter` option. It is only called if the value provided is
|
465
|
+
not an instance of the class or one of its subclasses. The `converter` option
|
443
466
|
accepts a symbol that specifies a class method on the object class or a proc.
|
444
467
|
Both will be passed the value and any errors thrown inside the converter will
|
445
468
|
cause the value to be considered invalid. Any returned value that is not the
|
@@ -466,13 +489,13 @@ ObjectInteraction.run!(ip_address: 1)
|
|
466
489
|
|
467
490
|
### Record
|
468
491
|
|
469
|
-
Record filters allow you to require an instance of a particular class or
|
470
|
-
that can be used to locate an instance of the
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
492
|
+
Record filters allow you to require an instance of a particular class (or one
|
493
|
+
of its subclasses) or a value that can be used to locate an instance of the
|
494
|
+
object. If the value does not match, it will call `find` on the class of the
|
495
|
+
record. This is particularly useful when working with ActiveRecord objects.
|
496
|
+
Like an object filter, the class is derived from the name passed but can be
|
497
|
+
specified with the `class` option. The value given to the `default` option will
|
498
|
+
also be found.
|
476
499
|
|
477
500
|
``` rb
|
478
501
|
class RecordInteraction < ActiveInteraction::Base
|
@@ -542,9 +565,10 @@ SymbolInteraction.run!(method: :object_id)
|
|
542
565
|
### Dates and times
|
543
566
|
|
544
567
|
Filters that work with dates and times behave similarly. By default, they all
|
545
|
-
convert strings into their expected data types using `.parse`.
|
546
|
-
`format` option, they will instead
|
547
|
-
formats won't work with `DateTime`
|
568
|
+
convert strings into their expected data types using `.parse`. Blank strings
|
569
|
+
will be treated as `nil`. If you give the `format` option, they will instead
|
570
|
+
convert strings using `.strptime`. Note that formats won't work with `DateTime`
|
571
|
+
and `Time` filters if a time zone is set.
|
548
572
|
|
549
573
|
#### Date
|
550
574
|
|
@@ -618,7 +642,8 @@ time :start,
|
|
618
642
|
### Numbers
|
619
643
|
|
620
644
|
All numeric filters accept numeric input. They will also convert strings using
|
621
|
-
the appropriate method from `Kernel` (like `.Float`).
|
645
|
+
the appropriate method from `Kernel` (like `.Float`). Blank strings will be
|
646
|
+
treated as `nil`.
|
622
647
|
|
623
648
|
#### Decimal
|
624
649
|
|
@@ -679,24 +704,27 @@ IntegerInteraction.run!(limit: 10)
|
|
679
704
|
```
|
680
705
|
|
681
706
|
When a `String` is passed into an `integer` input, the value will be coerced.
|
682
|
-
|
683
|
-
|
684
|
-
|
707
|
+
A default base of `10` is used though it may be overridden with the `base` option.
|
708
|
+
If a base of `0` is provided, the coercion will respect radix indicators present
|
709
|
+
in the string.
|
685
710
|
|
686
711
|
``` rb
|
687
712
|
class IntegerInteraction < ActiveInteraction::Base
|
688
|
-
integer :limit1
|
689
|
-
integer :limit2
|
713
|
+
integer :limit1
|
714
|
+
integer :limit2, base: 8
|
715
|
+
integer :limit3, base: 0
|
690
716
|
|
691
717
|
def execute
|
692
|
-
[limit1, limit2]
|
718
|
+
[limit1, limit2, limit3]
|
693
719
|
end
|
694
720
|
end
|
695
721
|
|
696
|
-
IntegerInteraction.run!(limit1:
|
697
|
-
# => [
|
698
|
-
IntegerInteraction.run!(limit1: "
|
699
|
-
#
|
722
|
+
IntegerInteraction.run!(limit1: 71, limit2: 71, limit3: 71)
|
723
|
+
# => [71, 71, 71]
|
724
|
+
IntegerInteraction.run!(limit1: "071", limit2: "071", limit3: "0x71")
|
725
|
+
# => [71, 57, 113]
|
726
|
+
IntegerInteraction.run!(limit1: "08", limit2: "08", limit3: "08")
|
727
|
+
ActiveInteraction::InvalidInteractionError: Limit2 is not a valid integer, Limit3 is not a valid integer
|
700
728
|
```
|
701
729
|
|
702
730
|
## Rails
|
@@ -940,10 +968,6 @@ The interaction that updates accounts is more complicated than the others. It
|
|
940
968
|
requires an account to update, but the other inputs are optional. If they're
|
941
969
|
missing, it'll ignore those attributes. If they're present, it'll update them.
|
942
970
|
|
943
|
-
ActiveInteraction generates predicate methods (like `#first_name?`) for your
|
944
|
-
inputs. They will return `false` if the input is `nil` and `true` otherwise.
|
945
|
-
Skip to [the predicates section](#predicates) for more information about them.
|
946
|
-
|
947
971
|
``` rb
|
948
972
|
class UpdateAccount < ActiveInteraction::Base
|
949
973
|
object :account
|
@@ -953,14 +977,14 @@ class UpdateAccount < ActiveInteraction::Base
|
|
953
977
|
|
954
978
|
validates :first_name,
|
955
979
|
presence: true,
|
956
|
-
|
980
|
+
unless: 'first_name.nil?'
|
957
981
|
validates :last_name,
|
958
982
|
presence: true,
|
959
|
-
|
983
|
+
unless: 'last_name.nil?'
|
960
984
|
|
961
985
|
def execute
|
962
|
-
account.first_name = first_name if first_name?
|
963
|
-
account.last_name = last_name if last_name?
|
986
|
+
account.first_name = first_name if first_name.present?
|
987
|
+
account.last_name = last_name if last_name.present?
|
964
988
|
|
965
989
|
unless account.save
|
966
990
|
errors.merge!(account.errors)
|
@@ -1177,9 +1201,6 @@ def execute
|
|
1177
1201
|
end
|
1178
1202
|
```
|
1179
1203
|
|
1180
|
-
These types of errors will become standard with Rails 5. ActiveInteraction's
|
1181
|
-
implementation is based off of [active_model-errors_details][].
|
1182
|
-
|
1183
1204
|
ActiveInteraction also supports merging errors. This is useful if you want to
|
1184
1205
|
delegate validation to some other object. For example, if you have an
|
1185
1206
|
interaction that updates a record, you might want that record to validate
|
@@ -1375,41 +1396,6 @@ UpdateUser.run!(user: user, birthday: nil)
|
|
1375
1396
|
UpdateUser.run!(user: user, birthday: Date.new(2000, 1, 2))
|
1376
1397
|
```
|
1377
1398
|
|
1378
|
-
### Predicates
|
1379
|
-
|
1380
|
-
ActiveInteraction creates a predicate method for every input defined by a
|
1381
|
-
filter. So if you have an input called `foo`, there will be a predicate method
|
1382
|
-
called `#foo?`. That method will tell you if the input was given (that is, if
|
1383
|
-
it was not `nil`).
|
1384
|
-
|
1385
|
-
``` rb
|
1386
|
-
class SayHello < ActiveInteraction::Base
|
1387
|
-
string :name,
|
1388
|
-
default: nil
|
1389
|
-
|
1390
|
-
def execute
|
1391
|
-
if name?
|
1392
|
-
"Hello, #{name}!"
|
1393
|
-
else
|
1394
|
-
"Howdy, stranger!"
|
1395
|
-
end
|
1396
|
-
end
|
1397
|
-
end
|
1398
|
-
|
1399
|
-
SayHello.run!(name: nil)
|
1400
|
-
# => "Howdy, stranger!"
|
1401
|
-
SayHello.run!(name: 'Taylor')
|
1402
|
-
# => "Hello, Taylor!"
|
1403
|
-
```
|
1404
|
-
|
1405
|
-
This can be confusing for boolean inputs. If you have some boolean input `foo`,
|
1406
|
-
then the actual value of that input is available through `foo`. The associated
|
1407
|
-
predicate method, `#foo?`, will tell you if that value is not `nil`. So it will
|
1408
|
-
only be `false` if the input is optional and happens to be `nil`.
|
1409
|
-
|
1410
|
-
See [the optional inputs section][] for help on determining if an input was
|
1411
|
-
present in the input hash instead of just `nil`.
|
1412
|
-
|
1413
1399
|
### Translations
|
1414
1400
|
|
1415
1401
|
ActiveInteraction is i18n aware out of the box! All you have to do is add
|