active_interaction 3.8.3 → 4.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +193 -0
- data/README.md +97 -116
- data/lib/active_interaction.rb +2 -7
- data/lib/active_interaction/base.rb +44 -67
- 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 +6 -12
- data/lib/active_interaction/errors.rb +4 -19
- data/lib/active_interaction/filter.rb +66 -37
- data/lib/active_interaction/filter_column.rb +0 -3
- data/lib/active_interaction/filters/abstract_date_time_filter.rb +38 -36
- data/lib/active_interaction/filters/abstract_numeric_filter.rb +27 -17
- data/lib/active_interaction/filters/array_filter.rb +59 -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 +120 -0
- data/lib/active_interaction/modules/validation.rb +9 -21
- data/lib/active_interaction/version.rb +1 -3
- data/spec/active_interaction/base_spec.rb +38 -99
- 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 +9 -13
- 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 +62 -13
- 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} +35 -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 +1 -3
- 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 -12
- data/spec/support/concerns.rb +0 -2
- data/spec/support/filters.rb +13 -9
- data/spec/support/interactions.rb +22 -14
- metadata +92 -62
- 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: 24af31782cca3b666b2f211506cb3ca39e362ffcb665ae509bda892b13e65934
|
4
|
+
data.tar.gz: 3a139e271e9d19ac23cdea62a5bbe882889f50483647951289623b8f3aaaf97f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 574d84a7a67526dcb2b7f64ca885d6cccb3115612e731b4091bd1bb122446a88ce81ad791196c6bd33555122e9b2c8b07ac1924cecbe400f4d541906274fcd3c
|
7
|
+
data.tar.gz: 1260eae401d19342ef4b8e2ada334553e7b99672b3257ec9b5880d0c6566eb8dc86e8de9fc5c5a3d0ed37485f86fc88cdb3adc2abe6299ac60d049f1d0713474
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,184 @@
|
|
1
|
+
# [4.0.4][] (2021-07-03)
|
2
|
+
|
3
|
+
## Fix
|
4
|
+
|
5
|
+
- [#510][] - Hash parameters failed when working outside of Rails.
|
6
|
+
- [#511][] - Nested filters with options but no `:class` failed to have `:class` automatically added.
|
7
|
+
|
8
|
+
# [4.0.3][] (2021-06-24)
|
9
|
+
|
10
|
+
## Fix
|
11
|
+
|
12
|
+
- [#499][] - `given?` now recognizes multi-part date inputs by their primary key name
|
13
|
+
- [#493][] - `compose` now properly accepts `Inputs`
|
14
|
+
|
15
|
+
# [4.0.2][] (2021-06-22)
|
16
|
+
|
17
|
+
## Fix
|
18
|
+
|
19
|
+
- [#505][] - Nested Interface filters using the `:methods` option threw an error.
|
20
|
+
|
21
|
+
# [4.0.1][] (2021-05-26)
|
22
|
+
|
23
|
+
## Fix
|
24
|
+
|
25
|
+
- Fix regression of filter name relaxing.
|
26
|
+
- [#495][] - Fix time filter ignoring time zones
|
27
|
+
|
28
|
+
# [4.0.0][] (2021-01-10)
|
29
|
+
|
30
|
+
## Changed
|
31
|
+
|
32
|
+
- drop support for Ruby < 2.5, added support for Ruby 3.0
|
33
|
+
- drop support for Rails < 5.0, added support for Rails 6.1
|
34
|
+
- [#398][] - Predicate methods have been removed.
|
35
|
+
([how to upgrade](#predicate-methods))
|
36
|
+
- [#412][] - Filters will now treat blank string values as `nil`
|
37
|
+
(except `string` and `symbol`). ([how to upgrade](#blank-values-treated-as-nil-for-filters))
|
38
|
+
- [#392][] - Integer parsing now defaults the base to 10.
|
39
|
+
([how to upgrade](#integer-parsing-base-now-10))
|
40
|
+
- The `inputs` method now returns an `ActiveInteraction::Input` instead of a
|
41
|
+
hash. The `ActiveInteraction::Input` class still responds to all hash methods.
|
42
|
+
- The `object` and `record` filters now only accept an instance of the correct
|
43
|
+
class type or a subclass of the correct class. They no longer allow you to
|
44
|
+
check for included modules. ([how to upgrade](#object-and-record-filter-changes))
|
45
|
+
- The `interface` filter will now look for an ancestor of the value passed
|
46
|
+
based on the name of the interface or the value passed in the `from` option.
|
47
|
+
- The `InvalidClassError` has been replaced by `InvalidNameError`.
|
48
|
+
- When introspecting an array filter, the inner filter is referenced by :'0'
|
49
|
+
instead of the singularized version of the array filter name.
|
50
|
+
|
51
|
+
## Added
|
52
|
+
|
53
|
+
- Implicit coercion of types are now supported in filters (e.g. to_str, to_int,
|
54
|
+
etc).
|
55
|
+
- The `interface` and `record` filters, when used as an inner filter for an
|
56
|
+
`array`, will have their `from/class` option set to a singularized version of
|
57
|
+
the `array` filter name.
|
58
|
+
|
59
|
+
## Upgrading
|
60
|
+
|
61
|
+
### Predicate Methods
|
62
|
+
|
63
|
+
We've removed the predicate methods that were automatically generated for each
|
64
|
+
input. They would return true if an input was not `nil`. They can be manually
|
65
|
+
replaced with that same check.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# v3.8
|
69
|
+
class Example < ActiveInteraction::Base
|
70
|
+
string :first_name
|
71
|
+
|
72
|
+
validates :first_name,
|
73
|
+
presence: true,
|
74
|
+
if: :first_name?
|
75
|
+
|
76
|
+
def execute
|
77
|
+
# ...
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# v4.0
|
82
|
+
class Example < ActiveInteraction::Base
|
83
|
+
string :first_name
|
84
|
+
|
85
|
+
validates :first_name,
|
86
|
+
presence: true,
|
87
|
+
unless: -> { first_name.nil? }
|
88
|
+
|
89
|
+
def execute
|
90
|
+
# ...
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
## Blank Values Treated As `nil` For Filters
|
96
|
+
|
97
|
+
In an effort to improve form support, strings that are `blank?` will
|
98
|
+
be converted into `nil` for all filters except `string` and `symbol`.
|
99
|
+
Previously, blank strings would have cased `:invalid_type` errors but
|
100
|
+
they'll now cause a `:missing` error which should be more form
|
101
|
+
friendly. If the filter has a default, the blank string will cause
|
102
|
+
the default to be used.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class Example < ActiveInteraction::Base
|
106
|
+
integer :i
|
107
|
+
boolean :b, default: false
|
108
|
+
|
109
|
+
def execute
|
110
|
+
[i, b]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# v3.8
|
115
|
+
Example.run(i: '', b: '').errors.details
|
116
|
+
=> {:i=>[{:error=>:invalid_type, :type=>"integer"}], :b=>[{:error=>:invalid_type, :type=>"boolean"}]}
|
117
|
+
|
118
|
+
# v4.0
|
119
|
+
Example.run(i: '', b: '').errors.details
|
120
|
+
=> {:i=>[{:error=>:missing}]}
|
121
|
+
|
122
|
+
# v3.8
|
123
|
+
Example.run(i: 0, b: '').errors.details
|
124
|
+
=> {:b=>[{:error=>:invalid_type, :type=>"boolean"}]}
|
125
|
+
|
126
|
+
# v4.0
|
127
|
+
Example.run(i: 0, b: '').errors.details
|
128
|
+
=> {}
|
129
|
+
|
130
|
+
Example.run(i: 0, b: '').result
|
131
|
+
=> [0, false] # the default is used for `:b`
|
132
|
+
```
|
133
|
+
|
134
|
+
### Integer Parsing Base Now 10
|
135
|
+
|
136
|
+
Integers are parsed using `Integer`. By default this meant that when
|
137
|
+
strings were parsed, radix indicators (0, 0b, and 0x) were honored. Now
|
138
|
+
we're defaulting the base to `10`. This means all strings will be parsed
|
139
|
+
as though they are base 10.
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
class Example < ActiveInteraction::Base
|
143
|
+
integer :x
|
144
|
+
|
145
|
+
def execute
|
146
|
+
x
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# v3.8
|
151
|
+
Example.run!(x: '010')
|
152
|
+
# => 8
|
153
|
+
|
154
|
+
# v4.0
|
155
|
+
Example.run!(x: '010')
|
156
|
+
# => 10
|
157
|
+
```
|
158
|
+
|
159
|
+
If you want the old behavior that respected the radix you can pass `0`
|
160
|
+
as the base.
|
161
|
+
|
162
|
+
```diff
|
163
|
+
- integer :x
|
164
|
+
+ integer :x, base: 0
|
165
|
+
```
|
166
|
+
|
167
|
+
With that change, we can see the radix is respected again.
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
# v4.0.0
|
171
|
+
Example.run!(x: '010')
|
172
|
+
# => 8
|
173
|
+
```
|
174
|
+
|
175
|
+
### Object and Record Filter Changes
|
176
|
+
|
177
|
+
The `object` and `record` filters used to be able to check for included modules
|
178
|
+
in addition to a class type. This has been removed. If you want any object that
|
179
|
+
has a particular module included, you'll need to use the newly expanded
|
180
|
+
`interface` filter.
|
181
|
+
|
1
182
|
# [3.8.3][] (2020-04-22)
|
2
183
|
|
3
184
|
## Fixed
|
@@ -777,6 +958,11 @@ Example.run
|
|
777
958
|
|
778
959
|
- Initial release.
|
779
960
|
|
961
|
+
[4.0.4]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.3...v4.0.4
|
962
|
+
[4.0.3]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.2...v4.0.3
|
963
|
+
[4.0.2]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.1...v4.0.2
|
964
|
+
[4.0.1]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.0...v4.0.1
|
965
|
+
[4.0.0]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.3...v4.0.0
|
780
966
|
[3.8.3]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.2...v3.8.3
|
781
967
|
[3.8.2]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.1...v3.8.2
|
782
968
|
[3.8.1]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.0...v3.8.1
|
@@ -979,3 +1165,10 @@ Example.run
|
|
979
1165
|
[#476]: https://github.com/AaronLasseigne/active_interaction/issues/476
|
980
1166
|
[#479]: https://github.com/AaronLasseigne/active_interaction/issues/479
|
981
1167
|
[#486]: https://github.com/AaronLasseigne/active_interaction/issues/486
|
1168
|
+
[#392]: https://github.com/AaronLasseigne/active_interaction/issues/392
|
1169
|
+
[#398]: https://github.com/AaronLasseigne/active_interaction/issues/398
|
1170
|
+
[#495]: https://github.com/AaronLasseigne/active_interaction/issues/495
|
1171
|
+
[#505]: https://github.com/AaronLasseigne/active_interaction/issues/505
|
1172
|
+
[#499]: https://github.com/AaronLasseigne/active_interaction/issues/499
|
1173
|
+
[#493]: https://github.com/AaronLasseigne/active_interaction/issues/493
|
1174
|
+
[#510]: https://github.com/AaronLasseigne/active_interaction/issues/510
|
data/README.md
CHANGED
@@ -4,8 +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
|
-
[![
|
8
|
-
[![Coverage](https://img.shields.io/coveralls/github/AaronLasseigne/active_interaction.svg?style=flat-square)](https://coveralls.io/r/orgsync/active_interaction)
|
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)
|
9
8
|
[![Climate](https://img.shields.io/codeclimate/maintainability/orgsync/active_interaction.svg?style=flat-square)](https://codeclimate.com/github/orgsync/active_interaction)
|
10
9
|
|
11
10
|
---
|
@@ -55,34 +54,29 @@ handles your verbs.
|
|
55
54
|
- [Forms](#forms)
|
56
55
|
- [Grouped inputs](#grouped-inputs)
|
57
56
|
- [Optional inputs](#optional-inputs)
|
58
|
-
- [Predicates](#predicates)
|
59
57
|
- [Translations](#translations)
|
60
58
|
- [Credits](#credits)
|
61
59
|
|
62
|
-
[
|
60
|
+
[API Documentation][]
|
63
61
|
|
64
62
|
## Installation
|
65
63
|
|
66
64
|
Add it to your Gemfile:
|
67
65
|
|
68
66
|
``` rb
|
69
|
-
gem 'active_interaction', '~>
|
67
|
+
gem 'active_interaction', '~> 4.0'
|
70
68
|
```
|
71
69
|
|
72
70
|
Or install it manually:
|
73
71
|
|
74
72
|
``` sh
|
75
|
-
$ gem install active_interaction --version '~>
|
73
|
+
$ gem install active_interaction --version '~> 4.0'
|
76
74
|
```
|
77
75
|
|
78
76
|
This project uses [Semantic Versioning][]. Check out [GitHub releases][] for a
|
79
77
|
detailed list of changes. For help upgrading to version 2, please read [the
|
80
78
|
announcement post][].
|
81
79
|
|
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
80
|
## Basic usage
|
87
81
|
|
88
82
|
To define an interaction, create a subclass of `ActiveInteraction::Base`. Then
|
@@ -241,7 +235,8 @@ ArrayInteraction.run!(toppings: [:cheese, 'pepperoni'])
|
|
241
235
|
# => 2
|
242
236
|
```
|
243
237
|
|
244
|
-
Use a block to constrain the types of elements an array can contain.
|
238
|
+
Use a block to constrain the types of elements an array can contain. Note that
|
239
|
+
you can only have one filter inside an array block, and it must not have a name.
|
245
240
|
|
246
241
|
``` rb
|
247
242
|
array :birthdays do
|
@@ -249,19 +244,29 @@ array :birthdays do
|
|
249
244
|
end
|
250
245
|
```
|
251
246
|
|
252
|
-
|
253
|
-
|
247
|
+
For `interface`, `object`, and `record` filters, the name of the array filter
|
248
|
+
will be singularized and used to determine the type of value passed. In the
|
249
|
+
example below, the objects passed would need to be of type `Cow`.
|
254
250
|
|
255
251
|
``` rb
|
256
252
|
array :cows do
|
257
|
-
object
|
253
|
+
object
|
254
|
+
end
|
255
|
+
```
|
256
|
+
|
257
|
+
You can override this by passing the necessary information to the inner filter.
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
array :managers do
|
261
|
+
object class: People
|
258
262
|
end
|
259
263
|
```
|
260
264
|
|
261
265
|
### Boolean
|
262
266
|
|
263
|
-
Boolean filters convert the strings `"1"` and `"
|
264
|
-
`true`. They also convert `"0"` and `"
|
267
|
+
Boolean filters convert the strings `"1"`, `"true"`, and `"on"`
|
268
|
+
(case-insensitive) into `true`. They also convert `"0"`, `"false"`, and `"off"`
|
269
|
+
into `false`. Blank strings will be treated as `nil`.
|
265
270
|
|
266
271
|
``` rb
|
267
272
|
class BooleanInteraction < ActiveInteraction::Base
|
@@ -353,8 +358,45 @@ hash :stuff,
|
|
353
358
|
|
354
359
|
### Interface
|
355
360
|
|
356
|
-
Interface filters allow you to specify
|
357
|
-
|
361
|
+
Interface filters allow you to specify an interface that the passed value must
|
362
|
+
meet in order to pass. The name of the interface is used to look for a constant
|
363
|
+
inside the ancestor listing for the passed value. This allows for a variety of
|
364
|
+
checks depending on what's passed. Class instances are checked for an included
|
365
|
+
module or an inherited ancestor class. Classes are checked for an extended
|
366
|
+
module or an inherited ancestor class. Modules are checked for an extended
|
367
|
+
module.
|
368
|
+
|
369
|
+
``` rb
|
370
|
+
class InterfaceInteraction < ActiveInteraction::Base
|
371
|
+
interface :exception
|
372
|
+
|
373
|
+
def execute
|
374
|
+
exception
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
InterfaceInteraction.run!(exception: Exception)
|
379
|
+
# ActiveInteraction::InvalidInteractionError: Exception is not a valid interface
|
380
|
+
InterfaceInteraction.run!(exception: NameError) # a subclass of Exception
|
381
|
+
# => NameError
|
382
|
+
```
|
383
|
+
|
384
|
+
You can use `:from` to specify a class or module. This would be the equivalent
|
385
|
+
of what's above.
|
386
|
+
|
387
|
+
```rb
|
388
|
+
class InterfaceInteraction < ActiveInteraction::Base
|
389
|
+
interface :error,
|
390
|
+
from: Exception
|
391
|
+
|
392
|
+
def execute
|
393
|
+
error
|
394
|
+
end
|
395
|
+
end
|
396
|
+
```
|
397
|
+
|
398
|
+
You can also create an anonymous interface on the fly by passing the `methods`
|
399
|
+
option.
|
358
400
|
|
359
401
|
``` rb
|
360
402
|
class InterfaceInteraction < ActiveInteraction::Base
|
@@ -378,30 +420,10 @@ InterfaceInteraction.run!(serializer: JSON)
|
|
378
420
|
# => "{\"is_json\":true}"
|
379
421
|
```
|
380
422
|
|
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
423
|
### Object
|
401
424
|
|
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`.
|
425
|
+
Object filters allow you to require an instance of a particular class or one of
|
426
|
+
its subclasses.
|
405
427
|
|
406
428
|
``` rb
|
407
429
|
class Cow
|
@@ -438,8 +460,8 @@ object :dolly3,
|
|
438
460
|
```
|
439
461
|
|
440
462
|
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
|
463
|
+
you can use the `converter` option. It is only called if the value provided is
|
464
|
+
not an instance of the class or one of its subclasses. The `converter` option
|
443
465
|
accepts a symbol that specifies a class method on the object class or a proc.
|
444
466
|
Both will be passed the value and any errors thrown inside the converter will
|
445
467
|
cause the value to be considered invalid. Any returned value that is not the
|
@@ -466,13 +488,13 @@ ObjectInteraction.run!(ip_address: 1)
|
|
466
488
|
|
467
489
|
### Record
|
468
490
|
|
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
|
-
|
491
|
+
Record filters allow you to require an instance of a particular class (or one
|
492
|
+
of its subclasses) or a value that can be used to locate an instance of the
|
493
|
+
object. If the value does not match, it will call `find` on the class of the
|
494
|
+
record. This is particularly useful when working with ActiveRecord objects.
|
495
|
+
Like an object filter, the class is derived from the name passed but can be
|
496
|
+
specified with the `class` option. The value given to the `default` option will
|
497
|
+
also be found.
|
476
498
|
|
477
499
|
``` rb
|
478
500
|
class RecordInteraction < ActiveInteraction::Base
|
@@ -542,9 +564,10 @@ SymbolInteraction.run!(method: :object_id)
|
|
542
564
|
### Dates and times
|
543
565
|
|
544
566
|
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`
|
567
|
+
convert strings into their expected data types using `.parse`. Blank strings
|
568
|
+
will be treated as `nil`. If you give the `format` option, they will instead
|
569
|
+
convert strings using `.strptime`. Note that formats won't work with `DateTime`
|
570
|
+
and `Time` filters if a time zone is set.
|
548
571
|
|
549
572
|
#### Date
|
550
573
|
|
@@ -618,7 +641,8 @@ time :start,
|
|
618
641
|
### Numbers
|
619
642
|
|
620
643
|
All numeric filters accept numeric input. They will also convert strings using
|
621
|
-
the appropriate method from `Kernel` (like `.Float`).
|
644
|
+
the appropriate method from `Kernel` (like `.Float`). Blank strings will be
|
645
|
+
treated as `nil`.
|
622
646
|
|
623
647
|
#### Decimal
|
624
648
|
|
@@ -679,24 +703,27 @@ IntegerInteraction.run!(limit: 10)
|
|
679
703
|
```
|
680
704
|
|
681
705
|
When a `String` is passed into an `integer` input, the value will be coerced.
|
682
|
-
|
683
|
-
|
684
|
-
|
706
|
+
A default base of `10` is used though it may be overridden with the `base` option.
|
707
|
+
If a base of `0` is provided, the coercion will respect radix indicators present
|
708
|
+
in the string.
|
685
709
|
|
686
710
|
``` rb
|
687
711
|
class IntegerInteraction < ActiveInteraction::Base
|
688
|
-
integer :limit1
|
689
|
-
integer :limit2
|
712
|
+
integer :limit1
|
713
|
+
integer :limit2, base: 8
|
714
|
+
integer :limit3, base: 0
|
690
715
|
|
691
716
|
def execute
|
692
|
-
[limit1, limit2]
|
717
|
+
[limit1, limit2, limit3]
|
693
718
|
end
|
694
719
|
end
|
695
720
|
|
696
|
-
IntegerInteraction.run!(limit1:
|
697
|
-
# => [
|
698
|
-
IntegerInteraction.run!(limit1: "
|
699
|
-
#
|
721
|
+
IntegerInteraction.run!(limit1: 71, limit2: 71, limit3: 71)
|
722
|
+
# => [71, 71, 71]
|
723
|
+
IntegerInteraction.run!(limit1: "071", limit2: "071", limit3: "0x71")
|
724
|
+
# => [71, 57, 113]
|
725
|
+
IntegerInteraction.run!(limit1: "08", limit2: "08", limit3: "08")
|
726
|
+
ActiveInteraction::InvalidInteractionError: Limit2 is not a valid integer, Limit3 is not a valid integer
|
700
727
|
```
|
701
728
|
|
702
729
|
## Rails
|
@@ -940,10 +967,6 @@ The interaction that updates accounts is more complicated than the others. It
|
|
940
967
|
requires an account to update, but the other inputs are optional. If they're
|
941
968
|
missing, it'll ignore those attributes. If they're present, it'll update them.
|
942
969
|
|
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
970
|
``` rb
|
948
971
|
class UpdateAccount < ActiveInteraction::Base
|
949
972
|
object :account
|
@@ -953,14 +976,14 @@ class UpdateAccount < ActiveInteraction::Base
|
|
953
976
|
|
954
977
|
validates :first_name,
|
955
978
|
presence: true,
|
956
|
-
|
979
|
+
unless: -> { first_name.nil? }
|
957
980
|
validates :last_name,
|
958
981
|
presence: true,
|
959
|
-
|
982
|
+
unless: -> { last_name.nil? }
|
960
983
|
|
961
984
|
def execute
|
962
|
-
account.first_name = first_name if first_name?
|
963
|
-
account.last_name = last_name if last_name?
|
985
|
+
account.first_name = first_name if first_name.present?
|
986
|
+
account.last_name = last_name if last_name.present?
|
964
987
|
|
965
988
|
unless account.save
|
966
989
|
errors.merge!(account.errors)
|
@@ -1177,9 +1200,6 @@ def execute
|
|
1177
1200
|
end
|
1178
1201
|
```
|
1179
1202
|
|
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
1203
|
ActiveInteraction also supports merging errors. This is useful if you want to
|
1184
1204
|
delegate validation to some other object. For example, if you have an
|
1185
1205
|
interaction that updates a record, you might want that record to validate
|
@@ -1375,41 +1395,6 @@ UpdateUser.run!(user: user, birthday: nil)
|
|
1375
1395
|
UpdateUser.run!(user: user, birthday: Date.new(2000, 1, 2))
|
1376
1396
|
```
|
1377
1397
|
|
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
1398
|
### Translations
|
1414
1399
|
|
1415
1400
|
ActiveInteraction is i18n aware out of the box! All you have to do is add
|
@@ -1462,8 +1447,8 @@ I18nInteraction.run(name: false).errors.messages[:name]
|
|
1462
1447
|
|
1463
1448
|
## Credits
|
1464
1449
|
|
1465
|
-
ActiveInteraction is brought to you by [Aaron Lasseigne][]
|
1466
|
-
[Taylor Fausak][] and
|
1450
|
+
ActiveInteraction is brought to you by [Aaron Lasseigne][].
|
1451
|
+
Along with Aaron, [Taylor Fausak][] helped create and maintain ActiveInteraction but has since moved on.
|
1467
1452
|
|
1468
1453
|
If you want to contribute to ActiveInteraction, please read
|
1469
1454
|
[our contribution guidelines][]. A [complete list of contributors][] is
|
@@ -1472,14 +1457,11 @@ available on GitHub.
|
|
1472
1457
|
ActiveInteraction is licensed under [the MIT License][].
|
1473
1458
|
|
1474
1459
|
[activeinteraction]: https://github.com/AaronLasseigne/active_interaction
|
1475
|
-
[
|
1460
|
+
[API Documentation]: http://rubydoc.info/github/AaronLasseigne/active_interaction
|
1476
1461
|
[semantic versioning]: http://semver.org/spec/v2.0.0.html
|
1477
1462
|
[GitHub releases]: https://github.com/AaronLasseigne/active_interaction/releases
|
1478
|
-
[the announcement post]: http://devblog.orgsync.com/2015/05/06/announcing-active-interaction-2/
|
1479
|
-
[active_model-errors_details]: https://github.com/cowbell/active_model-errors_details
|
1480
1463
|
[aaron lasseigne]: https://github.com/AaronLasseigne
|
1481
1464
|
[taylor fausak]: https://github.com/tfausak
|
1482
|
-
[orgsync]: https://github.com/orgsync
|
1483
1465
|
[our contribution guidelines]: CONTRIBUTING.md
|
1484
1466
|
[complete list of contributors]: https://github.com/AaronLasseigne/active_interaction/graphs/contributors
|
1485
1467
|
[the mit license]: LICENSE.md
|
@@ -1488,5 +1470,4 @@ ActiveInteraction is licensed under [the MIT License][].
|
|
1488
1470
|
[the filters section]: #filters
|
1489
1471
|
[the errors section]: #errors
|
1490
1472
|
[the optional inputs section]: #optional-inputs
|
1491
|
-
[aire]: example
|
1492
1473
|
[`with_options`]: http://api.rubyonrails.org/classes/Object.html#method-i-with_options
|