active_interaction 2.2.0 → 3.0.0
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 +15 -0
- data/README.md +47 -5
- data/lib/active_interaction/backports.rb +0 -26
- data/lib/active_interaction/concerns/runnable.rb +1 -7
- data/lib/active_interaction/errors.rb +21 -1
- data/lib/active_interaction/filter_column.rb +1 -1
- data/lib/active_interaction/filters/interface_filter.rb +1 -1
- data/lib/active_interaction/version.rb +1 -1
- data/spec/active_interaction/base_spec.rb +7 -7
- data/spec/active_interaction/concerns/missable_spec.rb +2 -2
- data/spec/active_interaction/concerns/runnable_spec.rb +1 -1
- data/spec/active_interaction/filters/hash_filter_spec.rb +0 -10
- data/spec/active_interaction/filters/interface_filter_spec.rb +1 -1
- data/spec/active_interaction/integration/interface_interaction_spec.rb +1 -1
- metadata +9 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66bb9089f91627be5b2370b6e68eb216ff3da581
|
4
|
+
data.tar.gz: 0f107c34005d354adb1fc2bad3b72776b588b455
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d17dab874880c2d8b363e749ef785800bece6d567196937968bd20637a8f7c1df5e653583d0397f11b2934d2c00aba16ada93af8e7b0abda6aa53df07de91463
|
7
|
+
data.tar.gz: 09dbd1ee68e85d8a0b49e492eb2043e75350fb6194385f654cb95fed861bfb63046e53ce7f909f83e0b90ea4097b71e2616d2ba11f6968b864b8004f07906d01
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# [3.0.0][] (2016-01-13)
|
2
|
+
|
3
|
+
## Changed
|
4
|
+
|
5
|
+
- [#333][]: Copy symbolic errors when using `compose`.
|
6
|
+
|
7
|
+
## Removed
|
8
|
+
|
9
|
+
- [#344][]: Support for Ruby 1.9.3.
|
10
|
+
- [#346][]: Support for ActiveModel 3.2.
|
11
|
+
|
1
12
|
# [2.2.0][] (2015-12-18)
|
2
13
|
|
3
14
|
## Added
|
@@ -493,6 +504,7 @@ For help upgrading to version 2, please read [the announcement post][].
|
|
493
504
|
|
494
505
|
- Initial release.
|
495
506
|
|
507
|
+
[3.0.0]: https://github.com/orgsync/active_interaction/compare/v2.2.0...v3.0.0
|
496
508
|
[2.2.0]: https://github.com/orgsync/active_interaction/compare/v2.1.5...v2.2.0
|
497
509
|
[2.1.5]: https://github.com/orgsync/active_interaction/compare/v2.1.4...v2.1.5
|
498
510
|
[2.1.4]: https://github.com/orgsync/active_interaction/compare/v2.1.3...v2.1.4
|
@@ -644,6 +656,9 @@ For help upgrading to version 2, please read [the announcement post][].
|
|
644
656
|
[#320]: https://github.com/orgsync/active_interaction/issues/320
|
645
657
|
[#330]: https://github.com/orgsync/active_interaction/pull/330
|
646
658
|
[#332]: https://github.com/orgsync/active_interaction/pull/332
|
659
|
+
[#333]: https://github.com/orgsync/active_interaction/pull/333
|
647
660
|
[#336]: https://github.com/orgsync/active_interaction/pull/336
|
661
|
+
[#344]: https://github.com/orgsync/active_interaction/pull/344
|
662
|
+
[#346]: https://github.com/orgsync/active_interaction/pull/346
|
648
663
|
|
649
664
|
[the announcement post]: http://devblog.orgsync.com/2015/05/06/announcing-active-interaction-2/
|
data/README.md
CHANGED
@@ -67,21 +67,23 @@ Read more on [the project page][] or check out [the full documentation][].
|
|
67
67
|
Add it to your Gemfile:
|
68
68
|
|
69
69
|
``` rb
|
70
|
-
gem 'active_interaction', '~>
|
70
|
+
gem 'active_interaction', '~> 3.0'
|
71
71
|
```
|
72
72
|
|
73
73
|
Or install it manually:
|
74
74
|
|
75
75
|
``` sh
|
76
|
-
$ gem install active_interaction --version '~>
|
76
|
+
$ gem install active_interaction --version '~> 3.0'
|
77
77
|
```
|
78
78
|
|
79
79
|
This project uses [Semantic Versioning][]. Check out [the change log][] for a
|
80
80
|
detailed list of changes. For help upgrading to version 2, please read [the
|
81
81
|
announcement post][].
|
82
82
|
|
83
|
-
ActiveInteraction works with all supported versions of Ruby (2.0 through 2.
|
84
|
-
and ActiveModel (
|
83
|
+
ActiveInteraction works with all supported versions of Ruby (2.0 through 2.3)
|
84
|
+
and ActiveModel (4.0 through 4.2).
|
85
|
+
|
86
|
+
If you want to use ActiveInteraction with Ruby < 2.0.0 or ActiveModel < 4.0.0, use ActiveInteraction < 3.0.0.
|
85
87
|
|
86
88
|
## Basic usage
|
87
89
|
|
@@ -873,7 +875,7 @@ end
|
|
873
875
|
|
874
876
|
We recommend putting your interactions in `app/interactions`. It's also very
|
875
877
|
helpful to group them by model. That way you can look in
|
876
|
-
`app/interactions/accounts` for all the ways you can interact with accounts.
|
878
|
+
`app/interactions/accounts` for all the ways you can interact with accounts.
|
877
879
|
In order to use this structure add `config.autoload_paths += Dir.glob("#{config.root}/app/interactions/*")` in your `application.rb`
|
878
880
|
|
879
881
|
```
|
@@ -981,6 +983,9 @@ class AddAndDouble < ActiveInteraction::Base
|
|
981
983
|
end
|
982
984
|
```
|
983
985
|
|
986
|
+
Note that errors in composed interactions have a few tricky cases. See [the
|
987
|
+
errors section][] for more information about them.
|
988
|
+
|
984
989
|
### Defaults
|
985
990
|
|
986
991
|
The default value for an input can take on many different forms. Setting the
|
@@ -1100,6 +1105,42 @@ class UpdateThing < ActiveInteraction::Base
|
|
1100
1105
|
end
|
1101
1106
|
```
|
1102
1107
|
|
1108
|
+
When a composed interaction fails, its errors are merged onto the caller. This
|
1109
|
+
generally produces good error messages, but there are a few cases to look out
|
1110
|
+
for.
|
1111
|
+
|
1112
|
+
``` rb
|
1113
|
+
class Inner < ActiveInteraction::Base
|
1114
|
+
boolean :x, :y
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
class Outer < ActiveInteraction::Base
|
1118
|
+
string :x
|
1119
|
+
boolean :z, default: nil
|
1120
|
+
|
1121
|
+
def execute
|
1122
|
+
compose(Inner, x: x, y: z)
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
outcome = Outer.run(x: 'yes')
|
1127
|
+
outcome.errors.details
|
1128
|
+
# => { :x => [{ :error => :invalid_type, :type => "boolean" }],
|
1129
|
+
# :base => [{ :error => "Y is required" }] }
|
1130
|
+
outcome.errors.full_messages.join(' and ')
|
1131
|
+
# => "X is not a valid boolean and Y is required"
|
1132
|
+
```
|
1133
|
+
|
1134
|
+
Since both interactions have an input called `x`, the inner error for that
|
1135
|
+
input is moved to the `x` error on the outer interaction. This results in a
|
1136
|
+
misleading error that claims the input `x` is not a valid boolean even though
|
1137
|
+
it's a string on the outer interaction.
|
1138
|
+
|
1139
|
+
Since only the inner interaction has an input called `y`, the inner error for
|
1140
|
+
that input is moved to the `base` error on the outer interaction. This results
|
1141
|
+
in a confusing error that claims the input `y` is required even though it's not
|
1142
|
+
present on the outer interaction.
|
1143
|
+
|
1103
1144
|
### Forms
|
1104
1145
|
|
1105
1146
|
The outcome returned by `.run` can be used in forms as though it were an
|
@@ -1348,6 +1389,7 @@ ActiveInteraction is licensed under [the MIT License][].
|
|
1348
1389
|
[formtastic]: https://rubygems.org/gems/formtastic
|
1349
1390
|
[simple_form]: https://rubygems.org/gems/simple_form
|
1350
1391
|
[the filters section]: #filters
|
1392
|
+
[the errors section]: #errors
|
1351
1393
|
[the optional inputs section]: #optional-inputs
|
1352
1394
|
[aire]: example
|
1353
1395
|
[`with_options`]: http://api.rubyonrails.org/classes/Object.html#method-i-with_options
|
@@ -4,22 +4,7 @@
|
|
4
4
|
require 'active_support/core_ext'
|
5
5
|
|
6
6
|
module ActiveInteraction
|
7
|
-
class GroupedInput # rubocop:disable Style/Documentation
|
8
|
-
# Required for Ruby <= 1.9.3.
|
9
|
-
def [](name)
|
10
|
-
send(name)
|
11
|
-
end unless method_defined?(:[])
|
12
|
-
|
13
|
-
# Required for Ruby <= 1.9.3.
|
14
|
-
def []=(name, value)
|
15
|
-
send("#{name}=", value)
|
16
|
-
end unless method_defined?(:[]=)
|
17
|
-
end
|
18
|
-
|
19
7
|
class Errors # rubocop:disable Style/Documentation
|
20
|
-
# Required for Rails < 3.2.13.
|
21
|
-
protected :initialize_dup
|
22
|
-
|
23
8
|
# Required for Rails < 5.
|
24
9
|
#
|
25
10
|
# Extracted from active_model-errors_details 1.2.0. Modified to add support
|
@@ -67,15 +52,4 @@ module ActiveInteraction
|
|
67
52
|
end
|
68
53
|
include Details unless method_defined?(:details)
|
69
54
|
end
|
70
|
-
|
71
|
-
class HashFilter # rubocop:disable Style/Documentation
|
72
|
-
# Required for Rails < 4.0.0.
|
73
|
-
def self.transform_keys(hash, &block)
|
74
|
-
return hash.transform_keys(&block) if hash.respond_to?(:transform_keys)
|
75
|
-
|
76
|
-
result = {}
|
77
|
-
hash.each_key { |key| result[block.call(key)] = hash[key] }
|
78
|
-
result
|
79
|
-
end
|
80
|
-
end
|
81
55
|
end
|
@@ -80,18 +80,12 @@ module ActiveInteraction
|
|
80
80
|
|
81
81
|
self.result =
|
82
82
|
if result_or_errors.is_a?(ActiveInteraction::Errors)
|
83
|
-
|
83
|
+
errors.merge!(result_or_errors)
|
84
84
|
else
|
85
85
|
result_or_errors
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
def merge_errors_onto_base(new_errors)
|
90
|
-
new_errors.full_messages.each do |message|
|
91
|
-
errors.add(:base, message) unless errors.added?(:base, message)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
89
|
# @return [Object]
|
96
90
|
#
|
97
91
|
# @raise [InvalidInteractionError] If there are validation errors.
|
@@ -97,6 +97,10 @@ module ActiveInteraction
|
|
97
97
|
def merge_messages!(other)
|
98
98
|
other.messages.each do |attribute, messages|
|
99
99
|
messages.each do |message|
|
100
|
+
unless attribute?(attribute)
|
101
|
+
message = full_message(attribute, message)
|
102
|
+
attribute = :base
|
103
|
+
end
|
100
104
|
add(attribute, message) unless added?(attribute, message)
|
101
105
|
end
|
102
106
|
end
|
@@ -107,9 +111,25 @@ module ActiveInteraction
|
|
107
111
|
details.each do |detail|
|
108
112
|
detail = detail.dup
|
109
113
|
error = detail.delete(:error)
|
110
|
-
|
114
|
+
|
115
|
+
merge_detail!(other, attribute, detail, error)
|
111
116
|
end
|
112
117
|
end
|
113
118
|
end
|
119
|
+
|
120
|
+
def merge_detail!(other, attribute, detail, error)
|
121
|
+
if attribute?(attribute)
|
122
|
+
add(attribute, error, detail) unless added?(attribute, error, detail)
|
123
|
+
else
|
124
|
+
message = full_message(
|
125
|
+
attribute, other.generate_message(attribute, error))
|
126
|
+
attribute = :base
|
127
|
+
add(attribute, message) unless added?(attribute, message)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def attribute?(attribute)
|
132
|
+
@base.respond_to?(attribute)
|
133
|
+
end
|
114
134
|
end
|
115
135
|
end
|
@@ -19,12 +19,12 @@ AddInteraction = Class.new(TestInteraction) do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
InterruptInteraction = Class.new(TestInteraction) do
|
22
|
-
object :x, :
|
22
|
+
object :x, :z,
|
23
23
|
class: Object,
|
24
24
|
default: nil
|
25
25
|
|
26
26
|
def execute
|
27
|
-
compose(AddInteraction,
|
27
|
+
compose(AddInteraction, x: x, y: z)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -337,11 +337,11 @@ describe ActiveInteraction::Base do
|
|
337
337
|
describe '#compose' do
|
338
338
|
let(:described_class) { InterruptInteraction }
|
339
339
|
let(:x) { rand }
|
340
|
-
let(:
|
340
|
+
let(:z) { rand }
|
341
341
|
|
342
342
|
context 'with valid composition' do
|
343
343
|
before do
|
344
|
-
inputs.merge!(x: x,
|
344
|
+
inputs.merge!(x: x, z: z)
|
345
345
|
end
|
346
346
|
|
347
347
|
it 'is valid' do
|
@@ -349,7 +349,7 @@ describe ActiveInteraction::Base do
|
|
349
349
|
end
|
350
350
|
|
351
351
|
it 'returns the sum' do
|
352
|
-
expect(result).to eql x +
|
352
|
+
expect(result).to eql x + z
|
353
353
|
end
|
354
354
|
end
|
355
355
|
|
@@ -359,8 +359,8 @@ describe ActiveInteraction::Base do
|
|
359
359
|
end
|
360
360
|
|
361
361
|
it 'has the correct errors' do
|
362
|
-
expect(outcome.errors
|
363
|
-
.to
|
362
|
+
expect(outcome.errors.details)
|
363
|
+
.to eql(x: [{ error: :missing }], base: [{ error: 'Y is required' }])
|
364
364
|
end
|
365
365
|
end
|
366
366
|
end
|
@@ -67,7 +67,7 @@ describe ActiveInteraction::Missable do
|
|
67
67
|
end
|
68
68
|
|
69
69
|
context 'with names' do
|
70
|
-
let(:names) { [
|
70
|
+
let(:names) { %i[a b c] }
|
71
71
|
|
72
72
|
it 'yields' do
|
73
73
|
expect do |b|
|
@@ -87,7 +87,7 @@ describe ActiveInteraction::Missable do
|
|
87
87
|
end
|
88
88
|
|
89
89
|
context 'with names & options' do
|
90
|
-
let(:names) { [
|
90
|
+
let(:names) { %i[a b c] }
|
91
91
|
let(:options) { { a: nil, b: false, c: true } }
|
92
92
|
|
93
93
|
it 'yields' do
|
@@ -6,16 +6,6 @@ describe ActiveInteraction::HashFilter, :filter do
|
|
6
6
|
include_context 'filters'
|
7
7
|
it_behaves_like 'a filter'
|
8
8
|
|
9
|
-
context 'backports' do
|
10
|
-
describe '.transform_keys' do
|
11
|
-
it 'transforms keys' do
|
12
|
-
original = { 'key' => 'value' }
|
13
|
-
transformed = described_class.transform_keys(original, &:to_sym)
|
14
|
-
expect(transformed).to eql(key: 'value')
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
9
|
context 'with a nested nameless filter' do
|
20
10
|
let(:block) { proc { hash } }
|
21
11
|
|
@@ -8,7 +8,7 @@ describe ActiveInteraction::InterfaceFilter, :filter do
|
|
8
8
|
include_context 'filters'
|
9
9
|
it_behaves_like 'a filter'
|
10
10
|
|
11
|
-
before { options[:methods] = [
|
11
|
+
before { options[:methods] = %i[dump load] }
|
12
12
|
|
13
13
|
describe '#cast' do
|
14
14
|
let(:result) { filter.cast(value, nil) }
|
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:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Lasseigne
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-01-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -17,40 +17,34 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '4'
|
21
21
|
- - "<"
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: '
|
23
|
+
version: '6'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
27
27
|
requirements:
|
28
28
|
- - ">="
|
29
29
|
- !ruby/object:Gem::Version
|
30
|
-
version: '
|
30
|
+
version: '4'
|
31
31
|
- - "<"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '6'
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: actionpack
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
41
|
-
- - "<"
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: '5'
|
40
|
+
version: '0'
|
44
41
|
type: :development
|
45
42
|
prerelease: false
|
46
43
|
version_requirements: !ruby/object:Gem::Requirement
|
47
44
|
requirements:
|
48
45
|
- - ">="
|
49
46
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
51
|
-
- - "<"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '5'
|
47
|
+
version: '0'
|
54
48
|
- !ruby/object:Gem::Dependency
|
55
49
|
name: benchmark-ips
|
56
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -298,7 +292,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
298
292
|
requirements:
|
299
293
|
- - ">="
|
300
294
|
- !ruby/object:Gem::Version
|
301
|
-
version:
|
295
|
+
version: '2'
|
302
296
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
303
297
|
requirements:
|
304
298
|
- - ">="
|