flows 0.1.0 → 0.2.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/.github/workflows/build.yml +43 -0
- data/.mdlrc +1 -0
- data/.rubocop.yml +25 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +80 -25
- data/README.md +170 -44
- data/bin/benchmark +65 -42
- data/bin/examples.rb +37 -1
- data/bin/profile_10steps +48 -6
- data/docs/.nojekyll +0 -0
- data/docs/CNAME +1 -0
- data/docs/README.md +197 -0
- data/docs/_sidebar.md +26 -0
- data/docs/contributing/benchmarks_profiling.md +3 -0
- data/docs/contributing/local_development.md +3 -0
- data/docs/flow/direct_usage.md +3 -0
- data/docs/flow/general_idea.md +3 -0
- data/docs/index.html +30 -0
- data/docs/operation/basic_usage.md +1 -0
- data/docs/operation/inject_steps.md +3 -0
- data/docs/operation/lambda_steps.md +3 -0
- data/docs/operation/result_shapes.md +3 -0
- data/docs/operation/routing_tracks.md +3 -0
- data/docs/operation/wrapping_steps.md +3 -0
- data/docs/overview/performance.md +336 -0
- data/docs/railway/basic_usage.md +232 -0
- data/docs/result_objects/basic_usage.md +196 -0
- data/docs/result_objects/do_notation.md +139 -0
- data/flows.gemspec +2 -0
- data/forspell.dict +8 -0
- data/lefthook.yml +12 -0
- data/lib/flows.rb +2 -0
- data/lib/flows/flow.rb +1 -1
- data/lib/flows/operation.rb +1 -3
- data/lib/flows/operation/builder.rb +2 -2
- data/lib/flows/operation/dsl.rb +21 -0
- data/lib/flows/railway.rb +48 -0
- data/lib/flows/railway/builder.rb +68 -0
- data/lib/flows/railway/dsl.rb +28 -0
- data/lib/flows/railway/errors.rb +21 -0
- data/lib/flows/railway/executor.rb +23 -0
- data/lib/flows/result.rb +1 -0
- data/lib/flows/result/do.rb +30 -0
- data/lib/flows/result_router.rb +1 -1
- data/lib/flows/version.rb +1 -1
- metadata +59 -3
- data/.travis.yml +0 -8
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative './railway/errors'
|
2
|
+
|
3
|
+
require_relative './railway/dsl'
|
4
|
+
require_relative './railway/builder'
|
5
|
+
require_relative './railway/executor'
|
6
|
+
|
7
|
+
module Flows
|
8
|
+
# Railway DSL
|
9
|
+
module Railway
|
10
|
+
def self.included(mod)
|
11
|
+
mod.extend ::Flows::Railway::DSL
|
12
|
+
end
|
13
|
+
|
14
|
+
include ::Flows::Result::Helpers
|
15
|
+
|
16
|
+
def initialize(method_source: nil, deps: {})
|
17
|
+
_flows_do_checks
|
18
|
+
|
19
|
+
flow = _flows_make_flow(method_source || self, deps)
|
20
|
+
@_flows_executor = _flows_make_executor(flow)
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(**params)
|
24
|
+
@_flows_executor.call(**params)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def _flows_do_checks
|
30
|
+
raise NoStepsError if self.class.steps.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def _flows_make_flow(method_source, deps)
|
34
|
+
::Flows::Railway::Builder.new(
|
35
|
+
steps: self.class.steps,
|
36
|
+
method_source: method_source,
|
37
|
+
deps: deps
|
38
|
+
).call
|
39
|
+
end
|
40
|
+
|
41
|
+
def _flows_make_executor(flow)
|
42
|
+
::Flows::Railway::Executor.new(
|
43
|
+
flow: flow,
|
44
|
+
class_name: self.class.name
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Flows
|
2
|
+
module Railway
|
3
|
+
# Flow builder
|
4
|
+
class Builder
|
5
|
+
attr_reader :steps, :method_source, :deps
|
6
|
+
|
7
|
+
def initialize(steps:, method_source:, deps:)
|
8
|
+
@method_source = method_source
|
9
|
+
@steps = steps
|
10
|
+
@deps = deps
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
resolve_bodies_and_wiring!
|
15
|
+
|
16
|
+
nodes = build_nodes
|
17
|
+
Flows::Flow.new(start_node: nodes.first.name, nodes: nodes)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def resolve_bodies_and_wiring!
|
23
|
+
index = 0
|
24
|
+
|
25
|
+
while index < @steps.length
|
26
|
+
current_step = @steps[index]
|
27
|
+
|
28
|
+
current_step[:next_step] = @steps[index + 1]&.fetch(:name) || :term
|
29
|
+
current_step[:body] = current_step[:custom_body] || resolve_body_from_source(current_step[:name])
|
30
|
+
|
31
|
+
index += 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def resolve_body_from_source(name)
|
36
|
+
return @deps[name] if @deps.key?(name)
|
37
|
+
|
38
|
+
raise(::Flows::Railway::NoStepImplementationError, name) unless @method_source.respond_to?(name)
|
39
|
+
|
40
|
+
@method_source.method(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_nodes
|
44
|
+
@nodes = @steps.map do |step|
|
45
|
+
Flows::Node.new(
|
46
|
+
name: step[:name],
|
47
|
+
body: step[:body],
|
48
|
+
preprocessor: method(:node_preprocessor),
|
49
|
+
postprocessor: method(:node_postprocessor),
|
50
|
+
router: Flows::ResultRouter.new(step[:next_step], :term),
|
51
|
+
|
52
|
+
meta: { name: step[:name] }
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def node_preprocessor(input, _context, _meta)
|
58
|
+
input.unwrap
|
59
|
+
end
|
60
|
+
|
61
|
+
def node_postprocessor(output, context, meta)
|
62
|
+
context[:last_step] = meta[:name]
|
63
|
+
|
64
|
+
output
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Flows
|
2
|
+
module Railway
|
3
|
+
# DSL methods for Railway
|
4
|
+
module DSL
|
5
|
+
attr_reader :steps
|
6
|
+
|
7
|
+
def self.extended(mod, steps = nil)
|
8
|
+
mod.instance_variable_set(:@steps, steps || [])
|
9
|
+
|
10
|
+
mod.class_exec do
|
11
|
+
def self.inherited(subclass)
|
12
|
+
::Flows::Railway::DSL.extended(subclass, steps.map(&:dup))
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
include Flows::Result::Helpers
|
19
|
+
|
20
|
+
def step(name, custom_body = nil)
|
21
|
+
@steps << {
|
22
|
+
name: name,
|
23
|
+
custom_body: custom_body
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Flows
|
2
|
+
module Railway
|
3
|
+
# rubocop:disable Style/Documentation
|
4
|
+
class NoStepsError < ::Flows::Error
|
5
|
+
def message
|
6
|
+
'No steps defined'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class NoStepImplementationError < ::Flows::Error
|
11
|
+
def initialize(step_name)
|
12
|
+
@step_name = step_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
"Missing step definition: #{@step_name}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
# rubocop:enable Style/Documentation
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Flows
|
2
|
+
module Railway
|
3
|
+
# Runner for railway steps
|
4
|
+
class Executor
|
5
|
+
include ::Flows::Result::Helpers
|
6
|
+
|
7
|
+
def initialize(flow:, class_name:)
|
8
|
+
@flow = flow
|
9
|
+
@railway_class_name = class_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(**params)
|
13
|
+
context = {}
|
14
|
+
last_result = @flow.call(ok(params), context: context)
|
15
|
+
|
16
|
+
last_result.meta[:railway] = @railway_class_name
|
17
|
+
last_result.meta[:last_step] = context[:last_step]
|
18
|
+
|
19
|
+
last_result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/flows/result.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Flows
|
2
|
+
class Result
|
3
|
+
# Do-notation for Result Objects
|
4
|
+
module Do
|
5
|
+
# DSL for Do-notation
|
6
|
+
module DSL
|
7
|
+
def do_for(method_name)
|
8
|
+
@flows_result_do_module.define_method(method_name) do |*args|
|
9
|
+
super(*args) do |*fields, result|
|
10
|
+
case result
|
11
|
+
when Flows::Result::Ok
|
12
|
+
fields.any? ? result.unwrap.values_at(*fields) : result.unwrap
|
13
|
+
when Flows::Result::Err then return result
|
14
|
+
else raise "Unexpected result: #{result.inspect}. Should be a Flows::Result"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.included(mod)
|
22
|
+
patch_mod = Module.new
|
23
|
+
|
24
|
+
mod.instance_variable_set(:@flows_result_do_module, patch_mod)
|
25
|
+
mod.prepend(patch_mod)
|
26
|
+
mod.extend(DSL)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/flows/result_router.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Flows
|
2
2
|
# Node router for simple case when result must be a `Flows::Result`
|
3
|
-
# and we don't care about
|
3
|
+
# and we don't care about result status key
|
4
4
|
class ResultRouter
|
5
5
|
def initialize(success_route, failure_route)
|
6
6
|
@success_route = success_route
|
data/lib/flows/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flows
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Kolesnev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: forspell
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.8
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.8
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rubocop
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +80,20 @@ dependencies:
|
|
66
80
|
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-md
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
- !ruby/object:Gem::Dependency
|
70
98
|
name: rubocop-performance
|
71
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -213,11 +241,12 @@ executables: []
|
|
213
241
|
extensions: []
|
214
242
|
extra_rdoc_files: []
|
215
243
|
files:
|
244
|
+
- ".github/workflows/build.yml"
|
216
245
|
- ".gitignore"
|
246
|
+
- ".mdlrc"
|
217
247
|
- ".rspec"
|
218
248
|
- ".rubocop.yml"
|
219
249
|
- ".ruby-version"
|
220
|
-
- ".travis.yml"
|
221
250
|
- CODE_OF_CONDUCT.md
|
222
251
|
- Gemfile
|
223
252
|
- Gemfile.lock
|
@@ -231,7 +260,28 @@ files:
|
|
231
260
|
- bin/profile_10steps
|
232
261
|
- bin/ruby_benchmarks
|
233
262
|
- bin/setup
|
263
|
+
- docs/.nojekyll
|
264
|
+
- docs/CNAME
|
265
|
+
- docs/README.md
|
266
|
+
- docs/_sidebar.md
|
267
|
+
- docs/contributing/benchmarks_profiling.md
|
268
|
+
- docs/contributing/local_development.md
|
269
|
+
- docs/flow/direct_usage.md
|
270
|
+
- docs/flow/general_idea.md
|
271
|
+
- docs/index.html
|
272
|
+
- docs/operation/basic_usage.md
|
273
|
+
- docs/operation/inject_steps.md
|
274
|
+
- docs/operation/lambda_steps.md
|
275
|
+
- docs/operation/result_shapes.md
|
276
|
+
- docs/operation/routing_tracks.md
|
277
|
+
- docs/operation/wrapping_steps.md
|
278
|
+
- docs/overview/performance.md
|
279
|
+
- docs/railway/basic_usage.md
|
280
|
+
- docs/result_objects/basic_usage.md
|
281
|
+
- docs/result_objects/do_notation.md
|
234
282
|
- flows.gemspec
|
283
|
+
- forspell.dict
|
284
|
+
- lefthook.yml
|
235
285
|
- lib/flows.rb
|
236
286
|
- lib/flows/flow.rb
|
237
287
|
- lib/flows/node.rb
|
@@ -241,7 +291,13 @@ files:
|
|
241
291
|
- lib/flows/operation/dsl.rb
|
242
292
|
- lib/flows/operation/errors.rb
|
243
293
|
- lib/flows/operation/executor.rb
|
294
|
+
- lib/flows/railway.rb
|
295
|
+
- lib/flows/railway/builder.rb
|
296
|
+
- lib/flows/railway/dsl.rb
|
297
|
+
- lib/flows/railway/errors.rb
|
298
|
+
- lib/flows/railway/executor.rb
|
244
299
|
- lib/flows/result.rb
|
300
|
+
- lib/flows/result/do.rb
|
245
301
|
- lib/flows/result/err.rb
|
246
302
|
- lib/flows/result/errors.rb
|
247
303
|
- lib/flows/result/helpers.rb
|