active_interaction 0.8.0 → 0.9.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 +14 -9
- data/README.md +30 -18
- data/lib/active_interaction.rb +0 -1
- data/lib/active_interaction/base.rb +22 -9
- data/lib/active_interaction/errors.rb +27 -3
- data/lib/active_interaction/filter.rb +1 -0
- data/lib/active_interaction/filters/array_filter.rb +1 -1
- data/lib/active_interaction/modules/core.rb +2 -2
- data/lib/active_interaction/version.rb +1 -1
- data/spec/active_interaction/base_spec.rb +49 -0
- data/spec/active_interaction/integration/hash_interaction_spec.rb +1 -1
- metadata +2 -5
- data/lib/active_interaction/pipeline.rb +0 -92
- data/spec/active_interaction/pipeline_spec.rb +0 -117
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1139d1df0d150418f22b231b09423c894ba98c41
|
4
|
+
data.tar.gz: c53767591c098f28c46ffa8ae77fb31ac714e310
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5524134f37f76b6252d1ee82a2fe9d879aae1debec5d46679b66eb608e42bd49668c59532c5e2fda8f64999b5582649fb090c78e0c9c7048df2d05cd7e729474
|
7
|
+
data.tar.gz: 591d0b74feed33a7a7d39ebe67f61adea4c7f5721541d9c570ef39c8dd06b53f4cfd74ee8bac8dc8a78508c447d942a7e0cacbb80813392640ddce8d79f9b512
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# [Master][]
|
2
2
|
|
3
|
+
# [0.9.0][] (2013-12-02)
|
4
|
+
|
5
|
+
- Add experimental composition implementation
|
6
|
+
(`ActiveInteraction::Base#compose`).
|
7
|
+
- Remove `ActiveInteraction::Pipeline`.
|
8
|
+
|
3
9
|
# [0.8.0][] (2013-11-14)
|
4
10
|
|
5
11
|
- Add ability to document interactions and filters.
|
@@ -8,7 +14,6 @@
|
|
8
14
|
|
9
15
|
- Add ability to chain a series of interactions together with
|
10
16
|
`ActiveInteraction::Pipeline`.
|
11
|
-
- Refactor internals (abstract filters & core class).
|
12
17
|
|
13
18
|
# [0.6.1][] (2013-11-14)
|
14
19
|
|
@@ -16,18 +21,17 @@
|
|
16
21
|
|
17
22
|
# [0.6.0][] (2013-11-14)
|
18
23
|
|
19
|
-
- Error class now end with `Error
|
20
|
-
- By default, strip unlisted keys from hashes. To retain the old behavior,
|
21
|
-
`strip: false` on a hash filter
|
22
|
-
- Prevent specifying defaults (other than `nil` or `{}`) on hash filters. Set
|
23
|
-
defaults on the nested filters instead
|
24
|
+
- **Error class now end with `Error`.**
|
25
|
+
- **By default, strip unlisted keys from hashes. To retain the old behavior,
|
26
|
+
set `strip: false` on a hash filter.**
|
27
|
+
- **Prevent specifying defaults (other than `nil` or `{}`) on hash filters. Set
|
28
|
+
defaults on the nested filters instead.**
|
24
29
|
- Add ability to introspect interactions with `filters`.
|
25
30
|
- Fix bug that prevented listing multiple attributes in a hash filter.
|
26
31
|
- Allow getting all of the user-supplied inputs in an interaction with
|
27
32
|
`inputs`.
|
28
33
|
- Fix bug that prevented hash filters from being nested in array filters.
|
29
34
|
- Replace `allow_nil: true` with `default: nil`.
|
30
|
-
- Refactor internals.
|
31
35
|
- Add a symbol filter.
|
32
36
|
- Allow adding symbolic errors with `errors.add_sym` and retrieving them with
|
33
37
|
`errors.symbolic`.
|
@@ -76,11 +80,12 @@
|
|
76
80
|
|
77
81
|
- Correct gemspec dependencies on activemodel.
|
78
82
|
|
79
|
-
# [0.1.0][] (2013-
|
83
|
+
# [0.1.0][] (2013-07-12)
|
80
84
|
|
81
85
|
- Initial release.
|
82
86
|
|
83
|
-
[master]: https://github.com/orgsync/active_interaction/compare/v0.
|
87
|
+
[master]: https://github.com/orgsync/active_interaction/compare/v0.9.0...master
|
88
|
+
[0.9.0]: https://github.com/orgsync/active_interaction/compare/v0.9.0...0.9.0
|
84
89
|
[0.8.0]: https://github.com/orgsync/active_interaction/compare/v0.7.0...v0.8.0
|
85
90
|
[0.7.0]: https://github.com/orgsync/active_interaction/compare/v0.6.1...v0.7.0
|
86
91
|
[0.6.1]: https://github.com/orgsync/active_interaction/compare/v0.6.0...v0.6.1
|
data/README.md
CHANGED
@@ -25,7 +25,7 @@ This project uses [semantic versioning][].
|
|
25
25
|
Add it to your Gemfile:
|
26
26
|
|
27
27
|
```ruby
|
28
|
-
gem 'active_interaction', '~> 0.
|
28
|
+
gem 'active_interaction', '~> 0.9.0'
|
29
29
|
```
|
30
30
|
|
31
31
|
And then execute:
|
@@ -117,7 +117,7 @@ Or, you can do this:
|
|
117
117
|
```ruby
|
118
118
|
result = UserSignup.run!(params)
|
119
119
|
# Either returns the result of execute,
|
120
|
-
# or raises ActiveInteraction::
|
120
|
+
# or raises ActiveInteraction::InvalidInteractionError
|
121
121
|
```
|
122
122
|
|
123
123
|
## What can I pass to an interaction?
|
@@ -202,26 +202,36 @@ Check out the [documentation][] for a full list of methods.
|
|
202
202
|
|
203
203
|
## How do I compose interactions?
|
204
204
|
|
205
|
-
|
206
|
-
|
207
|
-
|
205
|
+
(Note: this feature is experimental. See [#41][] & [#79][].)
|
206
|
+
|
207
|
+
You can run interactions from within other interactions by calling `compose`.
|
208
|
+
If the interaction is successful, it'll return the result (just like if you had
|
209
|
+
called it with `run!`). If something went wrong, execution will halt
|
210
|
+
immediately and the errors will be moved onto the caller.
|
208
211
|
|
209
212
|
```ruby
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
213
|
+
class DoSomeMath < ActiveInteraction::Base
|
214
|
+
integer :x, :y
|
215
|
+
def execute
|
216
|
+
sum = compose(Add, inputs)
|
217
|
+
square = compose(Square, x: sum)
|
218
|
+
compose(Add, x: square, y: square)
|
219
|
+
end
|
214
220
|
end
|
215
|
-
|
216
|
-
|
217
|
-
# => 128 # ((3 + 5) ** 2) * 2
|
221
|
+
DoSomeMath.run!(x: 3, y: 5)
|
222
|
+
# 128 => ((3 + 5) ** 2) * 2
|
218
223
|
```
|
219
224
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
+
```ruby
|
226
|
+
class AddThree < ActiveInteraction::Base
|
227
|
+
integer :y
|
228
|
+
def execute
|
229
|
+
compose(Add, x: 3, y: y)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
AddThree.run!(y: nil)
|
233
|
+
# => ActiveInteraction::InvalidInteractionError: Y is required
|
234
|
+
```
|
225
235
|
|
226
236
|
## How do I translate an interaction?
|
227
237
|
|
@@ -270,6 +280,8 @@ p Interaction.run.errors.messages
|
|
270
280
|
|
271
281
|
This project was inspired by the fantastic work done in [Mutations][].
|
272
282
|
|
283
|
+
[#41]: https://github.com/orgsync/active_interaction/issues/41
|
284
|
+
[#79]: https://github.com/orgsync/active_interaction/issues/79
|
273
285
|
[1]: https://badge.fury.io/rb/active_interaction "Gem Version"
|
274
286
|
[2]: https://travis-ci.org/orgsync/active_interaction "Build Status"
|
275
287
|
[3]: https://coveralls.io/r/orgsync/active_interaction "Coverage Status"
|
@@ -283,4 +295,4 @@ This project was inspired by the fantastic work done in [Mutations][].
|
|
283
295
|
[gem version]: https://badge.fury.io/rb/active_interaction.png
|
284
296
|
[mutations]: https://github.com/cypriss/mutations
|
285
297
|
[project page]: http://orgsync.github.io/active_interaction/
|
286
|
-
[semantic versioning]: http://semver.org
|
298
|
+
[semantic versioning]: http://semver.org/spec/v2.0.0.html
|
data/lib/active_interaction.rb
CHANGED
@@ -27,7 +27,6 @@ require 'active_interaction/filters/symbol_filter'
|
|
27
27
|
require 'active_interaction/filters/time_filter'
|
28
28
|
|
29
29
|
require 'active_interaction/base'
|
30
|
-
require 'active_interaction/pipeline'
|
31
30
|
|
32
31
|
I18n.backend.load_translations(
|
33
32
|
Dir.glob(File.join(%w(lib active_interaction locale *.yml)))
|
@@ -54,6 +54,7 @@ module ActiveInteraction
|
|
54
54
|
begin
|
55
55
|
send("#{filter.name}=", filter.clean(options[filter.name]))
|
56
56
|
rescue InvalidValueError, MissingValueError
|
57
|
+
# Validators (#input_errors) will add errors if appropriate.
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
@@ -86,8 +87,7 @@ module ActiveInteraction
|
|
86
87
|
# Returns the output from {#execute} if there are no validation errors or
|
87
88
|
# `nil` otherwise.
|
88
89
|
#
|
89
|
-
# @return [
|
90
|
-
# @return [Object] if there are no validation errors.
|
90
|
+
# @return [Object, nil] the output or nil if there were validation errors
|
91
91
|
def result
|
92
92
|
@_interaction_result
|
93
93
|
end
|
@@ -120,7 +120,13 @@ module ActiveInteraction
|
|
120
120
|
def self.run(*args)
|
121
121
|
new(*args).tap do |interaction|
|
122
122
|
if interaction.valid?
|
123
|
-
result = transaction
|
123
|
+
result = transaction do
|
124
|
+
begin
|
125
|
+
interaction.execute
|
126
|
+
rescue Interrupt
|
127
|
+
# Inner interaction failed. #compose handles merging errors.
|
128
|
+
end
|
129
|
+
end
|
124
130
|
|
125
131
|
if interaction.errors.empty?
|
126
132
|
interaction.instance_variable_set(:@_interaction_result, result)
|
@@ -162,15 +168,22 @@ module ActiveInteraction
|
|
162
168
|
end
|
163
169
|
|
164
170
|
def runtime_errors
|
165
|
-
|
166
|
-
|
167
|
-
@_interaction_runtime_errors.symbolic.each do |attribute, symbols|
|
168
|
-
symbols.each { |symbol| errors.add_sym(attribute, symbol) }
|
171
|
+
if @_interaction_runtime_errors
|
172
|
+
errors.merge!(@_interaction_runtime_errors)
|
169
173
|
end
|
174
|
+
end
|
170
175
|
|
171
|
-
|
172
|
-
|
176
|
+
def compose(interaction, options = {})
|
177
|
+
outcome = interaction.run(options)
|
178
|
+
return outcome.result if outcome.valid?
|
179
|
+
|
180
|
+
# This can't use Errors#merge! because the errors have to be added to
|
181
|
+
# base.
|
182
|
+
outcome.errors.full_messages.each do |message|
|
183
|
+
errors.add(:base, message) unless errors.added?(:base, message)
|
173
184
|
end
|
185
|
+
|
186
|
+
raise Interrupt
|
174
187
|
end
|
175
188
|
end
|
176
189
|
end
|
@@ -2,9 +2,6 @@ module ActiveInteraction
|
|
2
2
|
# Top-level error class. All other errors subclass this.
|
3
3
|
Error = Class.new(StandardError)
|
4
4
|
|
5
|
-
# Raised when trying to run an empty pipeline.
|
6
|
-
EmptyPipelineError = Class.new(Error)
|
7
|
-
|
8
5
|
# Raised if a class name is invalid.
|
9
6
|
InvalidClassError = Class.new(Error)
|
10
7
|
|
@@ -29,6 +26,10 @@ module ActiveInteraction
|
|
29
26
|
# Raised if there is no default value.
|
30
27
|
NoDefaultError = Class.new(Error)
|
31
28
|
|
29
|
+
# @private
|
30
|
+
Interrupt = Class.new(::Interrupt)
|
31
|
+
private_constant :Interrupt
|
32
|
+
|
32
33
|
# A small extension to provide symbolic error messages to make introspecting
|
33
34
|
# and testing easier.
|
34
35
|
#
|
@@ -80,5 +81,28 @@ module ActiveInteraction
|
|
80
81
|
symbolic.clear
|
81
82
|
super
|
82
83
|
end
|
84
|
+
|
85
|
+
# Merge other errors into this one.
|
86
|
+
#
|
87
|
+
# @param other [Errors]
|
88
|
+
#
|
89
|
+
# @return [Errors]
|
90
|
+
def merge!(other)
|
91
|
+
other.symbolic.each do |attribute, symbols|
|
92
|
+
symbols.each do |symbol|
|
93
|
+
add_sym(attribute, symbol)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
other.messages.each do |attribute, messages|
|
98
|
+
messages.each do |message|
|
99
|
+
unless added?(attribute, message)
|
100
|
+
add(attribute, message)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
self
|
106
|
+
end
|
83
107
|
end
|
84
108
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
begin
|
2
2
|
require 'active_record'
|
3
3
|
rescue LoadError
|
4
|
+
# ActiveRecord is an optional dependency.
|
4
5
|
end
|
5
6
|
|
6
7
|
module ActiveInteraction
|
7
|
-
# Functionality common between {Base}
|
8
|
+
# Functionality common between {Base}.
|
8
9
|
#
|
9
10
|
# @see Base
|
10
|
-
# @see Pipeline
|
11
11
|
module Core
|
12
12
|
# Get or set the description.
|
13
13
|
#
|
@@ -272,6 +272,55 @@ describe ActiveInteraction::Base do
|
|
272
272
|
end
|
273
273
|
end
|
274
274
|
|
275
|
+
describe '#compose' do
|
276
|
+
let(:described_class) { InterruptInteraction }
|
277
|
+
let(:x) { rand }
|
278
|
+
let(:y) { rand }
|
279
|
+
|
280
|
+
AddInteraction = Class.new(ActiveInteraction::Base) do
|
281
|
+
float :x, :y
|
282
|
+
|
283
|
+
def execute
|
284
|
+
x + y
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
InterruptInteraction = Class.new(ActiveInteraction::Base) do
|
289
|
+
model :x, :y,
|
290
|
+
class: Object,
|
291
|
+
default: nil
|
292
|
+
|
293
|
+
def execute
|
294
|
+
compose(AddInteraction, inputs)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'with valid composition' do
|
299
|
+
before do
|
300
|
+
options.merge!(x: x, y: y)
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'is valid' do
|
304
|
+
expect(outcome).to be_valid
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'returns the sum' do
|
308
|
+
expect(result).to eq x + y
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context 'with invalid composition' do
|
313
|
+
it 'is invalid' do
|
314
|
+
expect(outcome).to be_invalid
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'has the correct errors' do
|
318
|
+
expect(outcome.errors[:base]).
|
319
|
+
to match_array ['X is required', 'Y is required']
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
275
324
|
describe '#execute' do
|
276
325
|
it 'raises an error' do
|
277
326
|
expect { interaction.execute }.to raise_error NotImplementedError
|
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: 0.
|
4
|
+
version: 0.9.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: 2013-
|
12
|
+
date: 2013-12-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -174,7 +174,6 @@ files:
|
|
174
174
|
- lib/active_interaction/modules/method_missing.rb
|
175
175
|
- lib/active_interaction/modules/overload_hash.rb
|
176
176
|
- lib/active_interaction/modules/validation.rb
|
177
|
-
- lib/active_interaction/pipeline.rb
|
178
177
|
- lib/active_interaction/version.rb
|
179
178
|
- lib/active_interaction.rb
|
180
179
|
- spec/active_interaction/base_spec.rb
|
@@ -211,7 +210,6 @@ files:
|
|
211
210
|
- spec/active_interaction/modules/method_missing_spec.rb
|
212
211
|
- spec/active_interaction/modules/overload_hash_spec.rb
|
213
212
|
- spec/active_interaction/modules/validation_spec.rb
|
214
|
-
- spec/active_interaction/pipeline_spec.rb
|
215
213
|
- spec/spec_helper.rb
|
216
214
|
- spec/support/filters.rb
|
217
215
|
- spec/support/interactions.rb
|
@@ -277,7 +275,6 @@ test_files:
|
|
277
275
|
- spec/active_interaction/modules/method_missing_spec.rb
|
278
276
|
- spec/active_interaction/modules/overload_hash_spec.rb
|
279
277
|
- spec/active_interaction/modules/validation_spec.rb
|
280
|
-
- spec/active_interaction/pipeline_spec.rb
|
281
278
|
- spec/spec_helper.rb
|
282
279
|
- spec/support/filters.rb
|
283
280
|
- spec/support/interactions.rb
|
@@ -1,92 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'active_record'
|
3
|
-
rescue LoadError
|
4
|
-
end
|
5
|
-
|
6
|
-
module ActiveInteraction
|
7
|
-
# Compose interactions by piping them together.
|
8
|
-
#
|
9
|
-
# @since 0.7.0
|
10
|
-
class Pipeline
|
11
|
-
include Core
|
12
|
-
|
13
|
-
# Set up a pipeline with a series of interactions.
|
14
|
-
#
|
15
|
-
# @example
|
16
|
-
# ActiveInteraction::Pipeline.new do
|
17
|
-
# pipe InteractionOne
|
18
|
-
# pipe InteractionTwo
|
19
|
-
# end
|
20
|
-
def initialize(&block)
|
21
|
-
@steps = []
|
22
|
-
instance_eval(&block) if block_given?
|
23
|
-
end
|
24
|
-
|
25
|
-
# Add an interaction to the end of the pipeline.
|
26
|
-
#
|
27
|
-
# @example With a lambda
|
28
|
-
# pipe Interaction, -> result { { a: result, b: result } }
|
29
|
-
#
|
30
|
-
# @example With a symbol
|
31
|
-
# pipe Interaction, :thing
|
32
|
-
# # -> result { { thing: result } }
|
33
|
-
#
|
34
|
-
# @example With nil
|
35
|
-
# pipe Interaction
|
36
|
-
# # -> result { result }
|
37
|
-
#
|
38
|
-
# @param interaction [Base] the interaction to add
|
39
|
-
# @param function [Proc] a function to convert the output of an interaction
|
40
|
-
# into the input for the next one
|
41
|
-
# @param function [Symbol] a shortcut for creating a function that puts the
|
42
|
-
# output into a hash with this key
|
43
|
-
# @param function [nil] a shortcut for creating a function that passes the
|
44
|
-
# output straight through
|
45
|
-
#
|
46
|
-
# @return [Pipeline]
|
47
|
-
def pipe(interaction, function = nil)
|
48
|
-
@steps << [lambdafy(function), interaction]
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
# Run all the interactions in the pipeline. If any interaction fails, stop
|
53
|
-
# and return immediately without running any more interactions.
|
54
|
-
#
|
55
|
-
# @param (see Base.run)
|
56
|
-
#
|
57
|
-
# @return [Base] an instance of the last successful interaction in the
|
58
|
-
# pipeline
|
59
|
-
#
|
60
|
-
# @raise [EmptyPipelineError] if nothing is in the pipeline
|
61
|
-
def run(*args)
|
62
|
-
raise EmptyPipelineError if @steps.empty?
|
63
|
-
|
64
|
-
transaction do
|
65
|
-
function, interaction = @steps.first
|
66
|
-
outcome = interaction.run(function.call(*args))
|
67
|
-
@steps.drop(1).reduce(outcome) { |o, (f, i)| bind(o, f, i) }
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
def bind(outcome, function, interaction)
|
74
|
-
if outcome.valid?
|
75
|
-
interaction.run(function.call(outcome.result))
|
76
|
-
else
|
77
|
-
outcome
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def lambdafy(thing)
|
82
|
-
case thing
|
83
|
-
when NilClass
|
84
|
-
-> result { result }
|
85
|
-
when Symbol
|
86
|
-
-> result { { thing => result } }
|
87
|
-
else
|
88
|
-
thing
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,117 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ActiveInteraction::Pipeline do
|
4
|
-
let(:invalid_interaction) do
|
5
|
-
Class.new(TestInteraction) do
|
6
|
-
float :a
|
7
|
-
validates :a, inclusion: { in: [] }
|
8
|
-
def execute; a end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:square_interaction) do
|
13
|
-
Class.new(TestInteraction) do
|
14
|
-
float :a
|
15
|
-
def execute; a ** 2 end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
let(:swap_interaction) do
|
20
|
-
Class.new(TestInteraction) do
|
21
|
-
float :a, :b
|
22
|
-
def execute; { a: b, b: a } end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'raises an error with no pipes' do
|
27
|
-
pipeline = described_class.new
|
28
|
-
expect {
|
29
|
-
pipeline.run
|
30
|
-
}.to raise_error ActiveInteraction::EmptyPipelineError
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'returns an invalid outcome with one invalid pipe' do
|
34
|
-
interaction = invalid_interaction
|
35
|
-
pipeline = described_class.new do
|
36
|
-
pipe interaction
|
37
|
-
end
|
38
|
-
|
39
|
-
options = { a: rand }
|
40
|
-
expect(pipeline.run(options)).to be_invalid
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'succeeds with one pipe' do
|
44
|
-
interaction = swap_interaction
|
45
|
-
pipeline = described_class.new do
|
46
|
-
pipe interaction
|
47
|
-
end
|
48
|
-
|
49
|
-
options = { a: rand, b: rand }
|
50
|
-
expect(pipeline.run(options).result).to eq(a: options[:b], b: options[:a])
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'succeeds with two pipes' do
|
54
|
-
interaction = swap_interaction
|
55
|
-
pipeline = described_class.new do
|
56
|
-
pipe interaction
|
57
|
-
pipe interaction
|
58
|
-
end
|
59
|
-
|
60
|
-
options = { a: rand, b: rand }
|
61
|
-
expect(pipeline.run(options).result).to eq options
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'succeeds with an implicit transformation' do
|
65
|
-
interaction = square_interaction
|
66
|
-
pipeline = described_class.new do
|
67
|
-
pipe interaction
|
68
|
-
end
|
69
|
-
|
70
|
-
options = { a: rand }
|
71
|
-
expect(pipeline.run(options).result).to eq options[:a] ** 2
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'succeeds with a symbolic transformation' do
|
75
|
-
interaction = square_interaction
|
76
|
-
pipeline = described_class.new do
|
77
|
-
pipe interaction, :a
|
78
|
-
end
|
79
|
-
|
80
|
-
options = rand
|
81
|
-
expect(pipeline.run(options).result).to eq options ** 2
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'succeeds with a lambda transformation' do
|
85
|
-
interaction = square_interaction
|
86
|
-
pipeline = described_class.new do
|
87
|
-
pipe interaction, -> result { { a: 2 * result } }
|
88
|
-
end
|
89
|
-
|
90
|
-
options = rand
|
91
|
-
expect(pipeline.run(options).result).to eq (2 * options) ** 2
|
92
|
-
end
|
93
|
-
|
94
|
-
describe '#run!' do
|
95
|
-
it 'raises an error with one invalid pipe' do
|
96
|
-
interaction = invalid_interaction
|
97
|
-
pipeline = described_class.new do
|
98
|
-
pipe interaction
|
99
|
-
end
|
100
|
-
|
101
|
-
options = { a: rand }
|
102
|
-
expect {
|
103
|
-
pipeline.run!(options)
|
104
|
-
}.to raise_error ActiveInteraction::InvalidInteractionError
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'returns the outcome with one valid pipe' do
|
108
|
-
interaction = square_interaction
|
109
|
-
pipeline = described_class.new do
|
110
|
-
pipe interaction
|
111
|
-
end
|
112
|
-
|
113
|
-
options = { a: rand }
|
114
|
-
expect(pipeline.run!(options)).to eq options[:a] ** 2
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|