flows 0.0.2 → 0.1.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/.gitignore +4 -0
- data/Gemfile.lock +41 -1
- data/README.md +296 -2
- data/bin/benchmark +88 -0
- data/bin/demo +4 -4
- data/bin/examples.rb +159 -0
- data/bin/profile_10steps +64 -0
- data/bin/ruby_benchmarks +26 -0
- data/flows.gemspec +10 -1
- data/lib/flows/operation/builder/build_router.rb +37 -0
- data/lib/flows/operation/builder.rb +78 -23
- data/lib/flows/operation/dsl.rb +57 -18
- data/lib/flows/operation/errors.rb +10 -0
- data/lib/flows/operation/executor.rb +14 -9
- data/lib/flows/operation.rb +11 -7
- data/lib/flows/result/err.rb +5 -5
- data/lib/flows/result/ok.rb +5 -5
- data/lib/flows/result.rb +2 -6
- data/lib/flows/result_router.rb +14 -0
- data/lib/flows/router.rb +5 -9
- data/lib/flows/version.rb +1 -1
- data/lib/flows.rb +1 -0
- data/profile/.keep +0 -0
- metadata +79 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a69e7b183fcc1a9a0e0eabeaac0e66aff9fc55ea458fa34a5c37de86c7970ab
|
4
|
+
data.tar.gz: 20dbb58536ba20c0f7c7032757679ea968088965890851e93af81e2b4cb148f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b606d7df548e65d694f4700ecf6991667bca8f6626a41111bce6cbe9f8949ad0c5cfc58830fd1596b1fc3c170eaca7aed2b4f8f83092a5a7d174979978ece70b
|
7
|
+
data.tar.gz: 4fbfd1e9422aca8b7800b4930d32a7a3a4f4eca67eceab08cf0b20fcde24ef628d677f5bc40ffa1f7a1c9c3af6f1f80de78a6e248adf145f23f63d3d4ae6c77c
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,19 +1,45 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
flows (0.0
|
4
|
+
flows (0.1.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ast (2.4.0)
|
10
|
+
benchmark-ips (2.7.2)
|
10
11
|
codecov (0.1.14)
|
11
12
|
json
|
12
13
|
simplecov
|
13
14
|
url
|
14
15
|
coderay (1.1.2)
|
16
|
+
concurrent-ruby (1.1.5)
|
15
17
|
diff-lcs (1.3)
|
16
18
|
docile (1.3.1)
|
19
|
+
dry-configurable (0.8.3)
|
20
|
+
concurrent-ruby (~> 1.0)
|
21
|
+
dry-core (~> 0.4, >= 0.4.7)
|
22
|
+
dry-container (0.7.2)
|
23
|
+
concurrent-ruby (~> 1.0)
|
24
|
+
dry-configurable (~> 0.1, >= 0.1.3)
|
25
|
+
dry-core (0.4.9)
|
26
|
+
concurrent-ruby (~> 1.0)
|
27
|
+
dry-equalizer (0.2.2)
|
28
|
+
dry-events (0.2.0)
|
29
|
+
concurrent-ruby (~> 1.0)
|
30
|
+
dry-core (~> 0.4)
|
31
|
+
dry-equalizer (~> 0.2)
|
32
|
+
dry-matcher (0.8.1)
|
33
|
+
dry-core (>= 0.4.7)
|
34
|
+
dry-monads (1.3.0)
|
35
|
+
concurrent-ruby (~> 1.0)
|
36
|
+
dry-core (~> 0.4, >= 0.4.4)
|
37
|
+
dry-equalizer
|
38
|
+
dry-transaction (0.13.0)
|
39
|
+
dry-container (>= 0.2.8)
|
40
|
+
dry-events (>= 0.1.0)
|
41
|
+
dry-matcher (>= 0.7.0)
|
42
|
+
dry-monads (>= 0.4.0)
|
17
43
|
jaro_winkler (1.5.2)
|
18
44
|
json (2.2.0)
|
19
45
|
method_source (0.9.2)
|
@@ -51,12 +77,21 @@ GEM
|
|
51
77
|
rubocop (>= 0.58.0)
|
52
78
|
rubocop-rspec (1.32.0)
|
53
79
|
rubocop (>= 0.60.0)
|
80
|
+
ruby-prof (1.0.0)
|
54
81
|
ruby-progressbar (1.10.0)
|
55
82
|
simplecov (0.16.1)
|
56
83
|
docile (~> 1.1)
|
57
84
|
json (>= 1.8, < 3)
|
58
85
|
simplecov-html (~> 0.10.0)
|
59
86
|
simplecov-html (0.10.2)
|
87
|
+
stackprof (0.2.12)
|
88
|
+
trailblazer-activity (0.8.4)
|
89
|
+
trailblazer-context (>= 0.1.4)
|
90
|
+
trailblazer-activity-dsl-linear (0.1.8)
|
91
|
+
trailblazer-activity (>= 0.8.3, < 1.0.0)
|
92
|
+
trailblazer-context (0.1.4)
|
93
|
+
trailblazer-operation (0.5.2)
|
94
|
+
trailblazer-activity-dsl-linear (>= 0.1.6, < 1.0.0)
|
60
95
|
unicode-display_width (1.5.0)
|
61
96
|
url (0.3.2)
|
62
97
|
|
@@ -64,8 +99,10 @@ PLATFORMS
|
|
64
99
|
ruby
|
65
100
|
|
66
101
|
DEPENDENCIES
|
102
|
+
benchmark-ips
|
67
103
|
bundler (~> 2.0)
|
68
104
|
codecov
|
105
|
+
dry-transaction
|
69
106
|
flows!
|
70
107
|
pry
|
71
108
|
rake (~> 10.0)
|
@@ -73,7 +110,10 @@ DEPENDENCIES
|
|
73
110
|
rubocop
|
74
111
|
rubocop-performance
|
75
112
|
rubocop-rspec
|
113
|
+
ruby-prof
|
76
114
|
simplecov
|
115
|
+
stackprof
|
116
|
+
trailblazer-operation
|
77
117
|
|
78
118
|
BUNDLED WITH
|
79
119
|
2.0.1
|
data/README.md
CHANGED
@@ -4,7 +4,11 @@
|
|
4
4
|
[](https://codecov.io/gh/ffloyd/flows)
|
5
5
|
[](https://badge.fury.io/rb/flows)
|
6
6
|
|
7
|
-
|
7
|
+
Small and fast ruby framework for implementing railway-like operations.
|
8
|
+
By design it close to [Trailblazer::Operation](http://trailblazer.to/gems/operation/2.0/) and [Dry::Transaction](https://dry-rb.org/gems/dry-transaction/),
|
9
|
+
but has more simpler and flexible DSL for defining operations and matching results. Also `flows` is significantly faster.
|
10
|
+
|
11
|
+
`flows` has no production dependencies so you can use it with any framework.
|
8
12
|
|
9
13
|
## Installation
|
10
14
|
|
@@ -24,7 +28,297 @@ Or install it yourself as:
|
|
24
28
|
|
25
29
|
## Usage
|
26
30
|
|
27
|
-
|
31
|
+
### `Flows::Flow`
|
32
|
+
|
33
|
+
Low-level instrument for defining execution flows. Used internally as execution engine for `Flows::Operation`.
|
34
|
+
Check out source code and specs for details.
|
35
|
+
|
36
|
+
### `Flows::Result`
|
37
|
+
|
38
|
+
Result Object implementation. Inspired by [Dry::Monads::Result](https://dry-rb.org/gems/dry-monads/1.0/result/) and
|
39
|
+
[Rust Result Objects](https://doc.rust-lang.org/1.30.0/book/2018-edition/ch09-02-recoverable-errors-with-result.html).
|
40
|
+
|
41
|
+
Main concepts & conventions:
|
42
|
+
|
43
|
+
* separate classes for successful (`Flows::Result::Ok`) and failure (`Flows::Result::Err`) results
|
44
|
+
* both classes has same parent class `Flows::Result`
|
45
|
+
* result data should be a `Hash` with symbol keys and any values
|
46
|
+
* result has a status
|
47
|
+
* default status for successful results is `:success`
|
48
|
+
* default status for failure results is `:failure`
|
49
|
+
|
50
|
+
Basic usage:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
# create successful result with data {a: 1, b: 2}
|
54
|
+
result_ok = Flows::Result::Ok.new(a:1, b: 2)
|
55
|
+
|
56
|
+
# get `:a` from result
|
57
|
+
result_ok.unwrap[:a] # 1
|
58
|
+
|
59
|
+
# get error data from result
|
60
|
+
result_ok.error[:a] # raises exception
|
61
|
+
|
62
|
+
# get status from result
|
63
|
+
result_ok.status # :success
|
64
|
+
|
65
|
+
# boolean flags
|
66
|
+
result_ok.ok? # true
|
67
|
+
result_ok.err? # false
|
68
|
+
|
69
|
+
# create successful result with data {a: 1, b: 2} and status `:custom`
|
70
|
+
result_ok_custom = Flows::Result::Ok.new({ a: 1, b: 2 }, status: :custom)
|
71
|
+
|
72
|
+
# get status from result
|
73
|
+
result_ok_custom.status # :custom
|
74
|
+
|
75
|
+
# create failure result with data {a: 1, b: 2}
|
76
|
+
result_err = Flows::Result::Err.new(a:1, b: 2)
|
77
|
+
|
78
|
+
# get `:a` from result
|
79
|
+
result_err.unwrap[:a] # raises exception
|
80
|
+
|
81
|
+
# get error data from result
|
82
|
+
result_err.error[:a] # 1
|
83
|
+
|
84
|
+
# get status from result
|
85
|
+
result_err.status # :failure
|
86
|
+
|
87
|
+
# boolean flags
|
88
|
+
result_ok.ok? # false
|
89
|
+
result_ok.err? # true
|
90
|
+
|
91
|
+
# create failure result with data {a: 1, b: 2} and status `:custom`
|
92
|
+
result_err_custom = Flows::Result::Err.new({ a: 1, b: 2 }, status: :custom)
|
93
|
+
|
94
|
+
# get status from result
|
95
|
+
result_err_custom.status # :custom
|
96
|
+
```
|
97
|
+
|
98
|
+
Mixin `Flows::Result::Helpers` contains tools for simpler generating and matching Result Objects:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
include Flows::Result::Helpers
|
102
|
+
|
103
|
+
# create successful result with data {a: 1, b: 2}
|
104
|
+
result_ok = ok(a:1, b: 2)
|
105
|
+
|
106
|
+
# create successful result with data {a: 1, b: 2} and status `:custom`
|
107
|
+
result_ok_custom = ok(:custom, a: 1, b: 2)
|
108
|
+
|
109
|
+
# create failure result with data {a: 1, b: 2}
|
110
|
+
result_err = err(a:1, b: 2)
|
111
|
+
|
112
|
+
# create failure result with data {a: 1, b: 2} and status `:custom`
|
113
|
+
result_err_custom = err(:custom, a: 1, b: 2)
|
114
|
+
|
115
|
+
# matching helpers
|
116
|
+
result = ...
|
117
|
+
|
118
|
+
case result
|
119
|
+
when match_ok(:custom)
|
120
|
+
# matches only successful results with status :custom
|
121
|
+
when match_ok
|
122
|
+
# matches only successful results with any status
|
123
|
+
when match_err(:custom)
|
124
|
+
# matches only failure results with status :custom
|
125
|
+
when match_err
|
126
|
+
# matches only failure results with any status
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
### `Flows::Operation`
|
131
|
+
|
132
|
+
Let's solve simple task using operation:
|
133
|
+
|
134
|
+
* given numbers `a` and `b`
|
135
|
+
* result should contain sum of this numbers
|
136
|
+
* result should contain square of this sum
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
class Summator
|
140
|
+
# Make this class an operation by including this module.
|
141
|
+
# It adds DSL, initializer and call method.
|
142
|
+
# Also it includes Flows::Result::Helper both on DSL and instance level.
|
143
|
+
include Flows::Operation
|
144
|
+
|
145
|
+
# This is step definitions.
|
146
|
+
# In simplest form step defined by its name and
|
147
|
+
# step implementation expected to be in a method
|
148
|
+
# with same name.
|
149
|
+
#
|
150
|
+
# Steps will be executed in a definition order.
|
151
|
+
step :validate
|
152
|
+
step :calc_sum
|
153
|
+
step :calc_square
|
154
|
+
|
155
|
+
# Which keys of operation data we want to expose on success
|
156
|
+
ok_shape :sum, :sum_square
|
157
|
+
|
158
|
+
# Which keys of operation data we want to expose on failure
|
159
|
+
err_shape :message
|
160
|
+
|
161
|
+
# Step implementation receives execution context as keyword arguments.
|
162
|
+
# For the first step context equals to operation arguments.
|
163
|
+
#
|
164
|
+
# Step implementation must return Result Object.
|
165
|
+
# Result Objects's data will be merged into operation context.
|
166
|
+
#
|
167
|
+
# If result is successful - next step will be executed.
|
168
|
+
# If not - operation terminates and returns failure.
|
169
|
+
def validate(a:, b:, **)
|
170
|
+
err(message: 'a is not a number') if !a.is_a?(Number)
|
171
|
+
err(message: 'b is not a number') if !b.is_a?(Number)
|
172
|
+
|
173
|
+
ok
|
174
|
+
end
|
175
|
+
|
176
|
+
def calc_sum(a:, b:, **)
|
177
|
+
ok(sum: a + b)
|
178
|
+
end
|
179
|
+
|
180
|
+
# We may get data from previous steps because all results' data are merged to context.
|
181
|
+
def calc_square(sum:, **)
|
182
|
+
ok(sum_square: a * b)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# prepare operation
|
188
|
+
operation = Summator.new
|
189
|
+
|
190
|
+
# execute operation
|
191
|
+
result = operation.call(a: 1, b: 2)
|
192
|
+
|
193
|
+
result.ok? # true
|
194
|
+
result.unwrap # { sum: 3, sum_square: 9 } - only keys from success shape present
|
195
|
+
|
196
|
+
|
197
|
+
result = operation.call(a: nil, b: nil)
|
198
|
+
|
199
|
+
result.ok? # false
|
200
|
+
result.error # { message: 'a is not a number' } - only keys from error shape present
|
201
|
+
```
|
202
|
+
|
203
|
+
#### Result Shapes
|
204
|
+
|
205
|
+
You may limit list of exposed fields by defining success and failure shapes. _After_ step definitions use `ok_shape` to define shapes of success result,
|
206
|
+
and `err_shape` to define shapes of failure result. Examples:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
# Set exposed keys for :success status of successful result.
|
210
|
+
#
|
211
|
+
# Success result will have shape like { key1: ..., key2: ... }
|
212
|
+
#
|
213
|
+
# If one of keys is missing in the final operation context an exception will be raised.
|
214
|
+
ok_shape :key1, :key2
|
215
|
+
|
216
|
+
# Set different exposed keys for different statuses.
|
217
|
+
#
|
218
|
+
# Operation result status is a status of last executed step result.
|
219
|
+
ok_shape status1: [:key1, :key2],
|
220
|
+
status2: [:key3]
|
221
|
+
|
222
|
+
# Failure shapes defined in the same way:
|
223
|
+
err_shape :key1, :key2
|
224
|
+
err_shape status1: [:key1, :key2],
|
225
|
+
status2: [:key3]
|
226
|
+
```
|
227
|
+
|
228
|
+
Operation definition should have exact one `ok_shape` DSL-call and zero or one `err_shape` DSL-call. If you want to disable shaping
|
229
|
+
you can write `no_shape` DSL-call instead of shape definitions.
|
230
|
+
|
231
|
+
#### Routing & Tracks
|
232
|
+
|
233
|
+
You define side tracks, even nested ones:
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
step :outer_1 # next step is outer_2
|
237
|
+
|
238
|
+
track :some_track do
|
239
|
+
step :inner_1 # next step is inner_2
|
240
|
+
track :inner_track do
|
241
|
+
step :deep_1 # next step is deep_2
|
242
|
+
step :deep_2 # next step is inner_2
|
243
|
+
end
|
244
|
+
step :inner_2 # next step in outer_2
|
245
|
+
end
|
246
|
+
|
247
|
+
step :outer_2
|
248
|
+
```
|
249
|
+
|
250
|
+
In definition above tracks will not be used because there is no routes to this tracks. You may define routing like this:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
# if result is successful and has status :to_some_track - next step will be inner_1
|
254
|
+
# for any other successful results - outer_2
|
255
|
+
step :outer_1,
|
256
|
+
match_ok(:to_some_track) => :some_track
|
257
|
+
|
258
|
+
track :some_track do
|
259
|
+
step :inner_1, match_err => :inner_track # redirect to inner_track on failure result
|
260
|
+
track :inner_track do
|
261
|
+
step :deep_1, match_ok(:some_status) => :outer_2 # you may redirect to steps too
|
262
|
+
step :deep_2
|
263
|
+
end
|
264
|
+
step :inner_2
|
265
|
+
end
|
266
|
+
|
267
|
+
step :outer_2
|
268
|
+
```
|
269
|
+
|
270
|
+
#### Lambda Steps
|
271
|
+
|
272
|
+
You can use lambda for in-place step implementation:
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
step :name, ->(a:, b:, **) { ok(sum: a + b) }
|
276
|
+
```
|
277
|
+
|
278
|
+
#### Dependency Injection
|
279
|
+
|
280
|
+
You can override or inject step implementation on initialization:
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
class Summator
|
284
|
+
include Flows::Operation
|
285
|
+
|
286
|
+
step :sum
|
287
|
+
|
288
|
+
ok_shape :sum
|
289
|
+
end
|
290
|
+
|
291
|
+
summator = Summator.new(deps: {
|
292
|
+
sum: ->(a:, b:, **) { ok(sum: a + b) }
|
293
|
+
})
|
294
|
+
|
295
|
+
summator.call(a: 1, b: 2).unwrap[:sum] # 3
|
296
|
+
```
|
297
|
+
|
298
|
+
#### Wrapping steps
|
299
|
+
|
300
|
+
You can wrap several steps with some logic:
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
step :first
|
304
|
+
|
305
|
+
wrap :wrapper do
|
306
|
+
step :wrapped
|
307
|
+
end
|
308
|
+
|
309
|
+
def wrapper(**context)
|
310
|
+
# do smth
|
311
|
+
result = yield # execute wrapped steps
|
312
|
+
# do smth or modify result
|
313
|
+
result
|
314
|
+
end
|
315
|
+
```
|
316
|
+
|
317
|
+
There is routing limitation when you use wrap:
|
318
|
+
|
319
|
+
* outside `wrap` block you may route to wrapped block by wrapper name (`:wrapper` in the provided example)
|
320
|
+
* you may route wrapped steps only to wrapped steps in the same wrap block
|
321
|
+
* you cannot route to wrapped steps from outside
|
28
322
|
|
29
323
|
## Development
|
30
324
|
|
data/bin/benchmark
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# rubocop:disable all
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'benchmark/ips'
|
6
|
+
|
7
|
+
require_relative './examples'
|
8
|
+
|
9
|
+
puts '-' * 50
|
10
|
+
puts '- task: A + B, one step implementation'
|
11
|
+
puts '-' * 50
|
12
|
+
|
13
|
+
flows_summator = FlowsSummator.new
|
14
|
+
dry_summator = DrySummator.new
|
15
|
+
|
16
|
+
Benchmark.ips do |b|
|
17
|
+
b.report 'Flows::Operation (build each time)' do
|
18
|
+
FlowsSummator.new.call(a: 1, b: 2)
|
19
|
+
end
|
20
|
+
|
21
|
+
b.report 'Flows::Operation (build once)' do
|
22
|
+
flows_summator.call(a: 1, b: 2)
|
23
|
+
end
|
24
|
+
|
25
|
+
unless ENV['FLOWS_ONLY']
|
26
|
+
b.report 'Dry::Transaction (build each time)' do
|
27
|
+
DrySummator.new.call(a: 1, b: 2)
|
28
|
+
end
|
29
|
+
|
30
|
+
b.report 'Dry::Transaction (build once)' do
|
31
|
+
dry_summator.call(a: 1, b: 2)
|
32
|
+
end
|
33
|
+
|
34
|
+
b.report 'Trailblazer::Operation' do
|
35
|
+
TBSummator.call(a: 1, b: 2)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if ENV['WITH_PORO']
|
40
|
+
b.report 'PORO' do
|
41
|
+
POROSummator.call(a: 1, b: 2)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
b.compare!
|
46
|
+
end unless ENV['SKIP_SUM']
|
47
|
+
puts
|
48
|
+
|
49
|
+
|
50
|
+
puts '-' * 50
|
51
|
+
puts '- task: ten steps returns successful result'
|
52
|
+
puts '-' * 50
|
53
|
+
|
54
|
+
flows_ten_steps = FlowsTenSteps.new
|
55
|
+
dry_ten_steps = DryTenSteps.new
|
56
|
+
|
57
|
+
Benchmark.ips do |b|
|
58
|
+
b.report 'Flows::Operation (build each time)' do
|
59
|
+
FlowsTenSteps.new.call(a: 1, b: 2)
|
60
|
+
end
|
61
|
+
|
62
|
+
b.report 'Flows::Operation (build once)' do
|
63
|
+
flows_ten_steps.call(a: 1, b: 2)
|
64
|
+
end
|
65
|
+
|
66
|
+
unless ENV['FLOWS_ONLY']
|
67
|
+
b.report 'Dry::Transaction (build each time)' do
|
68
|
+
DryTenSteps.new.call(a: 1, b: 2)
|
69
|
+
end
|
70
|
+
|
71
|
+
b.report 'Dry::Transaction (build once)' do
|
72
|
+
dry_ten_steps.call(a: 1, b: 2)
|
73
|
+
end
|
74
|
+
|
75
|
+
b.report 'Trailblazer::Operation' do
|
76
|
+
TBTenSteps.call(a: 1, b: 2)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
if ENV['WITH_PORO']
|
81
|
+
b.report 'PORO' do
|
82
|
+
POROTenSteps.call
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
b.compare!
|
87
|
+
end unless ENV['SKIP_10']
|
88
|
+
puts
|
data/bin/demo
CHANGED
@@ -27,8 +27,8 @@ class DivisionOperation
|
|
27
27
|
step :check_for_zero
|
28
28
|
step :divide
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
ok_shape :result
|
31
|
+
err_shape :error
|
32
32
|
|
33
33
|
def check_for_zero(denominator:, **)
|
34
34
|
if denominator.zero?
|
@@ -49,8 +49,8 @@ class NestedDivisionOperation
|
|
49
49
|
|
50
50
|
step :do_division
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
ok_shape :result
|
53
|
+
err_shape :error
|
54
54
|
|
55
55
|
def do_division(**params)
|
56
56
|
DivisionOperation.new.call(**params)
|
data/bin/examples.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
require 'flows'
|
3
|
+
require 'dry/transaction'
|
4
|
+
require 'trailblazer/operation'
|
5
|
+
|
6
|
+
#
|
7
|
+
# Task: a + b = ?
|
8
|
+
#
|
9
|
+
|
10
|
+
class FlowsSummator
|
11
|
+
include Flows::Operation
|
12
|
+
|
13
|
+
step :sum
|
14
|
+
|
15
|
+
ok_shape :sum
|
16
|
+
|
17
|
+
def sum(a:, b:, **)
|
18
|
+
ok(sum: a + b)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class POROSummator
|
23
|
+
def self.call(a:, b:)
|
24
|
+
a + b
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class DrySummator
|
29
|
+
include Dry::Transaction
|
30
|
+
|
31
|
+
step :sum
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def sum(a:, b:)
|
36
|
+
Success(a + b)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class TBSummator < Trailblazer::Operation
|
41
|
+
step :sum
|
42
|
+
|
43
|
+
def sum(opts, a:, b:, **)
|
44
|
+
opts[:sum] = a + b
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Task: 10 steps which returs simple value
|
50
|
+
#
|
51
|
+
|
52
|
+
class FlowsTenSteps
|
53
|
+
include Flows::Operation
|
54
|
+
|
55
|
+
step :s1
|
56
|
+
step :s2
|
57
|
+
step :s3
|
58
|
+
step :s4
|
59
|
+
step :s5
|
60
|
+
step :s6
|
61
|
+
step :s7
|
62
|
+
step :s8
|
63
|
+
step :s9
|
64
|
+
step :s10
|
65
|
+
|
66
|
+
ok_shape :data
|
67
|
+
|
68
|
+
def s1(**); ok(s1: true); end
|
69
|
+
def s2(**); ok(s2: true); end
|
70
|
+
def s3(**); ok(s3: true); end
|
71
|
+
def s4(**); ok(s4: true); end
|
72
|
+
def s5(**); ok(s5: true); end
|
73
|
+
def s5(**); ok(s5: true); end
|
74
|
+
def s6(**); ok(s6: true); end
|
75
|
+
def s7(**); ok(s7: true); end
|
76
|
+
def s8(**); ok(s8: true); end
|
77
|
+
def s9(**); ok(s9: true); end
|
78
|
+
def s10(**); ok(data: :ok); end
|
79
|
+
end
|
80
|
+
|
81
|
+
class POROTenSteps
|
82
|
+
class << self
|
83
|
+
def call()
|
84
|
+
s1
|
85
|
+
s2
|
86
|
+
s3
|
87
|
+
s4
|
88
|
+
s5
|
89
|
+
s6
|
90
|
+
s7
|
91
|
+
s8
|
92
|
+
s9
|
93
|
+
s10
|
94
|
+
end
|
95
|
+
|
96
|
+
def s1; true; end
|
97
|
+
def s2; true; end
|
98
|
+
def s3; true; end
|
99
|
+
def s4; true; end
|
100
|
+
def s5; true; end
|
101
|
+
def s6; true; end
|
102
|
+
def s7; true; end
|
103
|
+
def s8; true; end
|
104
|
+
def s9; true; end
|
105
|
+
def s10; true; end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class DryTenSteps
|
110
|
+
include Dry::Transaction
|
111
|
+
|
112
|
+
step :s1
|
113
|
+
step :s2
|
114
|
+
step :s3
|
115
|
+
step :s4
|
116
|
+
step :s5
|
117
|
+
step :s6
|
118
|
+
step :s7
|
119
|
+
step :s8
|
120
|
+
step :s9
|
121
|
+
step :s10
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def s1; Success(true); end
|
126
|
+
def s2; Success(true); end
|
127
|
+
def s3; Success(true); end
|
128
|
+
def s4; Success(true); end
|
129
|
+
def s5; Success(true); end
|
130
|
+
def s6; Success(true); end
|
131
|
+
def s7; Success(true); end
|
132
|
+
def s8; Success(true); end
|
133
|
+
def s9; Success(true); end
|
134
|
+
def s10; Success(true); end
|
135
|
+
end
|
136
|
+
|
137
|
+
class TBTenSteps < Trailblazer::Operation
|
138
|
+
step :s1
|
139
|
+
step :s2
|
140
|
+
step :s3
|
141
|
+
step :s4
|
142
|
+
step :s5
|
143
|
+
step :s6
|
144
|
+
step :s7
|
145
|
+
step :s8
|
146
|
+
step :s9
|
147
|
+
step :s10
|
148
|
+
|
149
|
+
def s1(opts, **); opts[:s1] = true; end
|
150
|
+
def s2(opts, **); opts[:s2] = true; end
|
151
|
+
def s3(opts, **); opts[:s3] = true; end
|
152
|
+
def s4(opts, **); opts[:s4] = true; end
|
153
|
+
def s5(opts, **); opts[:s5] = true; end
|
154
|
+
def s6(opts, **); opts[:s6] = true; end
|
155
|
+
def s7(opts, **); opts[:s7] = true; end
|
156
|
+
def s8(opts, **); opts[:s8] = true; end
|
157
|
+
def s9(opts, **); opts[:s9] = true; end
|
158
|
+
def s10(opts, **); opts[:s10] = true; end
|
159
|
+
end
|