flows 0.3.0 → 0.4.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 → test.yml} +5 -10
- data/.gitignore +1 -0
- data/.reek.yml +42 -0
- data/.rubocop.yml +20 -7
- data/.ruby-version +1 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +42 -0
- data/Gemfile +0 -6
- data/Gemfile.lock +139 -74
- data/README.md +158 -364
- data/Rakefile +35 -1
- data/bin/.rubocop.yml +5 -0
- data/bin/all_the_errors +47 -0
- data/bin/benchmark +73 -105
- data/bin/benchmark_cli/compare.rb +118 -0
- data/bin/benchmark_cli/compare/a_plus_b.rb +22 -0
- data/bin/benchmark_cli/compare/base.rb +45 -0
- data/bin/benchmark_cli/compare/command.rb +47 -0
- data/bin/benchmark_cli/compare/ten_steps.rb +22 -0
- data/bin/benchmark_cli/examples.rb +23 -0
- data/bin/benchmark_cli/examples/.rubocop.yml +19 -0
- data/bin/benchmark_cli/examples/a_plus_b/dry_do.rb +23 -0
- data/bin/benchmark_cli/examples/a_plus_b/dry_transaction.rb +17 -0
- data/bin/benchmark_cli/examples/a_plus_b/flows_do.rb +22 -0
- data/bin/benchmark_cli/examples/a_plus_b/flows_railway.rb +13 -0
- data/bin/benchmark_cli/examples/a_plus_b/flows_scp.rb +13 -0
- data/bin/benchmark_cli/examples/a_plus_b/flows_scp_mut.rb +13 -0
- data/bin/benchmark_cli/examples/a_plus_b/flows_scp_oc.rb +21 -0
- data/bin/benchmark_cli/examples/a_plus_b/trailblazer.rb +15 -0
- data/bin/benchmark_cli/examples/ten_steps/dry_do.rb +70 -0
- data/bin/benchmark_cli/examples/ten_steps/dry_transaction.rb +64 -0
- data/bin/benchmark_cli/examples/ten_steps/flows_do.rb +69 -0
- data/bin/benchmark_cli/examples/ten_steps/flows_railway.rb +58 -0
- data/bin/benchmark_cli/examples/ten_steps/flows_scp.rb +58 -0
- data/bin/benchmark_cli/examples/ten_steps/flows_scp_mut.rb +58 -0
- data/bin/benchmark_cli/examples/ten_steps/flows_scp_oc.rb +66 -0
- data/bin/benchmark_cli/examples/ten_steps/trailblazer.rb +60 -0
- data/bin/benchmark_cli/helpers.rb +12 -0
- data/bin/benchmark_cli/ruby.rb +15 -0
- data/bin/benchmark_cli/ruby/command.rb +38 -0
- data/bin/benchmark_cli/ruby/method_exec.rb +71 -0
- data/bin/benchmark_cli/ruby/self_class.rb +69 -0
- data/bin/benchmark_cli/ruby/structs.rb +90 -0
- data/bin/console +1 -0
- data/bin/docserver +7 -0
- data/bin/errors +118 -0
- data/bin/errors_cli/contract_error_demo.rb +49 -0
- data/bin/errors_cli/di_error_demo.rb +38 -0
- data/bin/errors_cli/flows_router_error_demo.rb +15 -0
- data/bin/errors_cli/oc_error_demo.rb +40 -0
- data/bin/errors_cli/railway_error_demo.rb +10 -0
- data/bin/errors_cli/result_error_demo.rb +13 -0
- data/bin/errors_cli/scp_error_demo.rb +17 -0
- data/docs/README.md +2 -186
- data/docs/_sidebar.md +0 -24
- data/docs/index.html +1 -1
- data/flows.gemspec +25 -2
- data/forspell.dict +9 -0
- data/lefthook.yml +9 -0
- data/lib/flows.rb +11 -5
- data/lib/flows/contract.rb +402 -0
- data/lib/flows/contract/array.rb +55 -0
- data/lib/flows/contract/case_eq.rb +41 -0
- data/lib/flows/contract/compose.rb +77 -0
- data/lib/flows/contract/either.rb +53 -0
- data/lib/flows/contract/error.rb +25 -0
- data/lib/flows/contract/hash.rb +75 -0
- data/lib/flows/contract/hash_of.rb +70 -0
- data/lib/flows/contract/helpers.rb +22 -0
- data/lib/flows/contract/predicate.rb +34 -0
- data/lib/flows/contract/transformer.rb +50 -0
- data/lib/flows/contract/tuple.rb +70 -0
- data/lib/flows/flow.rb +75 -7
- data/lib/flows/flow/node.rb +131 -0
- data/lib/flows/flow/router.rb +25 -0
- data/lib/flows/flow/router/custom.rb +54 -0
- data/lib/flows/flow/router/errors.rb +11 -0
- data/lib/flows/flow/router/simple.rb +20 -0
- data/lib/flows/plugin.rb +13 -0
- data/lib/flows/plugin/dependency_injector.rb +159 -0
- data/lib/flows/plugin/dependency_injector/dependency.rb +24 -0
- data/lib/flows/plugin/dependency_injector/dependency_definition.rb +16 -0
- data/lib/flows/plugin/dependency_injector/dependency_list.rb +57 -0
- data/lib/flows/plugin/dependency_injector/errors.rb +58 -0
- data/lib/flows/plugin/implicit_init.rb +45 -0
- data/lib/flows/plugin/output_contract.rb +84 -0
- data/lib/flows/plugin/output_contract/dsl.rb +36 -0
- data/lib/flows/plugin/output_contract/errors.rb +74 -0
- data/lib/flows/plugin/output_contract/wrapper.rb +53 -0
- data/lib/flows/railway.rb +140 -37
- data/lib/flows/railway/dsl.rb +8 -19
- data/lib/flows/railway/errors.rb +8 -12
- data/lib/flows/railway/step.rb +24 -0
- data/lib/flows/railway/step_list.rb +38 -0
- data/lib/flows/result.rb +188 -2
- data/lib/flows/result/do.rb +160 -16
- data/lib/flows/result/err.rb +12 -6
- data/lib/flows/result/errors.rb +29 -17
- data/lib/flows/result/helpers.rb +25 -3
- data/lib/flows/result/ok.rb +12 -6
- data/lib/flows/shared_context_pipeline.rb +216 -0
- data/lib/flows/shared_context_pipeline/dsl.rb +63 -0
- data/lib/flows/shared_context_pipeline/errors.rb +17 -0
- data/lib/flows/shared_context_pipeline/mutation_step.rb +31 -0
- data/lib/flows/shared_context_pipeline/router_definition.rb +21 -0
- data/lib/flows/shared_context_pipeline/step.rb +46 -0
- data/lib/flows/shared_context_pipeline/track.rb +67 -0
- data/lib/flows/shared_context_pipeline/track_list.rb +46 -0
- data/lib/flows/util.rb +17 -0
- data/lib/flows/util/inheritable_singleton_vars.rb +79 -0
- data/lib/flows/util/inheritable_singleton_vars/dup_strategy.rb +109 -0
- data/lib/flows/util/inheritable_singleton_vars/isolation_strategy.rb +104 -0
- data/lib/flows/util/prepend_to_class.rb +145 -0
- data/lib/flows/version.rb +1 -1
- metadata +233 -37
- data/bin/demo +0 -66
- data/bin/examples.rb +0 -195
- data/bin/profile_10steps +0 -106
- data/bin/ruby_benchmarks +0 -26
- data/docs/CNAME +0 -1
- data/docs/contributing/benchmarks_profiling.md +0 -3
- data/docs/contributing/local_development.md +0 -3
- data/docs/flow/direct_usage.md +0 -3
- data/docs/flow/general_idea.md +0 -3
- data/docs/operation/basic_usage.md +0 -1
- data/docs/operation/inject_steps.md +0 -3
- data/docs/operation/lambda_steps.md +0 -3
- data/docs/operation/result_shapes.md +0 -3
- data/docs/operation/routing_tracks.md +0 -3
- data/docs/operation/wrapping_steps.md +0 -3
- data/docs/overview/performance.md +0 -336
- data/docs/railway/basic_usage.md +0 -232
- data/docs/result_objects/basic_usage.md +0 -196
- data/docs/result_objects/do_notation.md +0 -139
- data/lib/flows/implicit_build.rb +0 -16
- data/lib/flows/node.rb +0 -27
- data/lib/flows/operation.rb +0 -55
- data/lib/flows/operation/builder.rb +0 -130
- data/lib/flows/operation/builder/build_router.rb +0 -37
- data/lib/flows/operation/dsl.rb +0 -93
- data/lib/flows/operation/errors.rb +0 -75
- data/lib/flows/operation/executor.rb +0 -78
- data/lib/flows/railway/builder.rb +0 -68
- data/lib/flows/railway/executor.rb +0 -23
- data/lib/flows/result_router.rb +0 -14
- data/lib/flows/router.rb +0 -22
data/lib/flows/implicit_build.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
module Flows
|
2
|
-
# Module to extend Operation and Railway. Adds implicit building feature.
|
3
|
-
module ImplicitBuild
|
4
|
-
attr_reader :default_build
|
5
|
-
|
6
|
-
def self.extended(mod)
|
7
|
-
mod.instance_variable_set(:@default_build, nil)
|
8
|
-
end
|
9
|
-
|
10
|
-
def call(**params)
|
11
|
-
@default_build ||= new
|
12
|
-
|
13
|
-
default_build.call(**params)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/flows/node.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Flows
|
2
|
-
# Representation of FSM node.
|
3
|
-
class Node
|
4
|
-
attr_reader :name, :meta
|
5
|
-
|
6
|
-
def initialize(name:, body:, router:, meta: {}, preprocessor: nil, postprocessor: nil)
|
7
|
-
@name = name
|
8
|
-
@body = body
|
9
|
-
@router = router
|
10
|
-
|
11
|
-
@meta = meta.freeze
|
12
|
-
|
13
|
-
@preprocessor = preprocessor
|
14
|
-
@postprocessor = postprocessor
|
15
|
-
end
|
16
|
-
|
17
|
-
def call(input, context:)
|
18
|
-
input = @preprocessor.call(input, context, @meta) if @preprocessor
|
19
|
-
output = @body.call(input)
|
20
|
-
output = @postprocessor.call(output, context, @meta) if @postprocessor
|
21
|
-
|
22
|
-
route = @router.call(output, context: context, meta: @meta)
|
23
|
-
|
24
|
-
[output, route]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/flows/operation.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require_relative 'operation/errors'
|
2
|
-
|
3
|
-
require_relative 'operation/dsl'
|
4
|
-
require_relative 'operation/builder'
|
5
|
-
require_relative 'operation/executor'
|
6
|
-
|
7
|
-
require_relative 'implicit_build'
|
8
|
-
|
9
|
-
module Flows
|
10
|
-
# Operation DSL
|
11
|
-
module Operation
|
12
|
-
def self.included(mod)
|
13
|
-
mod.extend ::Flows::Operation::DSL
|
14
|
-
mod.extend ::Flows::ImplicitBuild
|
15
|
-
end
|
16
|
-
|
17
|
-
include ::Flows::Result::Helpers
|
18
|
-
|
19
|
-
def initialize(method_source: nil, deps: {})
|
20
|
-
_flows_do_checks
|
21
|
-
|
22
|
-
flow = _flows_make_flow(method_source || self, deps)
|
23
|
-
|
24
|
-
@_flows_executor = _flows_make_executor(flow)
|
25
|
-
end
|
26
|
-
|
27
|
-
def call(**params)
|
28
|
-
@_flows_executor.call(**params)
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def _flows_do_checks
|
34
|
-
raise NoStepsError if self.class.steps.empty?
|
35
|
-
raise NoSuccessShapeError, self if self.class.ok_shapes.nil?
|
36
|
-
end
|
37
|
-
|
38
|
-
def _flows_make_flow(method_source, deps)
|
39
|
-
::Flows::Operation::Builder.new(
|
40
|
-
steps: self.class.steps,
|
41
|
-
method_source: method_source,
|
42
|
-
deps: deps
|
43
|
-
).call
|
44
|
-
end
|
45
|
-
|
46
|
-
def _flows_make_executor(flow)
|
47
|
-
::Flows::Operation::Executor.new(
|
48
|
-
flow: flow,
|
49
|
-
ok_shapes: self.class.ok_shapes,
|
50
|
-
err_shapes: self.class.err_shapes,
|
51
|
-
class_name: self.class.name
|
52
|
-
)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,130 +0,0 @@
|
|
1
|
-
require_relative './builder/build_router'
|
2
|
-
|
3
|
-
module Flows
|
4
|
-
module Operation
|
5
|
-
# Flow builder
|
6
|
-
class Builder
|
7
|
-
attr_reader :steps, :method_source, :deps
|
8
|
-
|
9
|
-
def initialize(steps:, method_source:, deps:)
|
10
|
-
@method_source = method_source
|
11
|
-
@steps = steps
|
12
|
-
@deps = deps
|
13
|
-
|
14
|
-
@step_names = @steps.map { |s| s[:name] }
|
15
|
-
end
|
16
|
-
|
17
|
-
def call
|
18
|
-
resolve_wiring!
|
19
|
-
resolve_bodies!
|
20
|
-
|
21
|
-
nodes = build_nodes
|
22
|
-
Flows::Flow.new(start_node: nodes.first.name, nodes: nodes)
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def resolve_wiring! # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
28
|
-
# we have to disable some linters for performance reasons
|
29
|
-
# this method can be simplified using `map.with_index`, but while loops is about
|
30
|
-
# 2x faster for such cases.
|
31
|
-
index = 0
|
32
|
-
|
33
|
-
while index < @steps.length
|
34
|
-
current_step = @steps[index]
|
35
|
-
next_step_name = nil
|
36
|
-
|
37
|
-
inner_index = index + 1
|
38
|
-
while inner_index < @steps.length
|
39
|
-
candidate = @steps[inner_index]
|
40
|
-
candidate_last_track = candidate[:track_path].last
|
41
|
-
|
42
|
-
if candidate[:track_path] == [] || current_step[:track_path].include?(candidate_last_track)
|
43
|
-
next_step_name = candidate[:name]
|
44
|
-
break
|
45
|
-
end
|
46
|
-
|
47
|
-
inner_index += 1
|
48
|
-
end
|
49
|
-
|
50
|
-
current_step[:next_step] = next_step_name || :term
|
51
|
-
|
52
|
-
index += 1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def resolve_bodies!
|
57
|
-
@steps.each do |step|
|
58
|
-
step.merge!(
|
59
|
-
body: step[:custom_body] || resolve_body_from_source(step[:name])
|
60
|
-
)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def resolve_body_from_source(name)
|
65
|
-
return @deps[name] if @deps.key?(name)
|
66
|
-
|
67
|
-
raise(::Flows::Operation::NoStepImplementationError, name) unless @method_source.respond_to?(name)
|
68
|
-
|
69
|
-
@method_source.method(name)
|
70
|
-
end
|
71
|
-
|
72
|
-
def build_nodes
|
73
|
-
@nodes = @steps.map do |step|
|
74
|
-
Flows::Node.new(
|
75
|
-
name: step[:name],
|
76
|
-
body: build_final_body(step),
|
77
|
-
preprocessor: method(:node_preprocessor),
|
78
|
-
postprocessor: method(:node_postprocessor),
|
79
|
-
router: BuildRouter.call(step[:custom_routes], step[:next_step], @step_names),
|
80
|
-
meta: build_meta(step)
|
81
|
-
)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def build_final_body(step)
|
86
|
-
case step[:type]
|
87
|
-
when :step
|
88
|
-
step[:body]
|
89
|
-
when :wrapper
|
90
|
-
build_wrapper_body(step[:body], step[:block])
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def build_wrapper_body(wrapper, block)
|
95
|
-
suboperation_class = Class.new do
|
96
|
-
include ::Flows::Operation
|
97
|
-
end
|
98
|
-
|
99
|
-
suboperation_class.instance_exec(&block)
|
100
|
-
suboperation_class.no_shape
|
101
|
-
|
102
|
-
suboperation = suboperation_class.new(method_source: @method_source, deps: @deps)
|
103
|
-
|
104
|
-
lambda do |**options|
|
105
|
-
wrapper.call(**options) { suboperation.call(**options) }
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def build_meta(step)
|
110
|
-
{
|
111
|
-
type: step[:type],
|
112
|
-
name: step[:name],
|
113
|
-
track_path: step[:track_path]
|
114
|
-
}
|
115
|
-
end
|
116
|
-
|
117
|
-
def node_preprocessor(_input, context, _meta)
|
118
|
-
context[:data]
|
119
|
-
end
|
120
|
-
|
121
|
-
def node_postprocessor(output, context, meta)
|
122
|
-
output_data = output.ok? ? output.unwrap : output.error
|
123
|
-
context[:data].merge!(output_data)
|
124
|
-
context[:last_step] = meta[:name]
|
125
|
-
|
126
|
-
output
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module Flows
|
2
|
-
module Operation
|
3
|
-
class Builder
|
4
|
-
# Router builder
|
5
|
-
module BuildRouter
|
6
|
-
class << self
|
7
|
-
def call(custom_routes, next_step, step_names)
|
8
|
-
if custom_routes
|
9
|
-
custom_router(custom_routes, next_step, step_names)
|
10
|
-
else
|
11
|
-
Flows::ResultRouter.new(next_step, :term)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def custom_router(custom_routes, next_step, step_names)
|
18
|
-
check_custom_routes(custom_routes, step_names)
|
19
|
-
|
20
|
-
custom_routes[Flows::Result::Ok] ||= next_step
|
21
|
-
custom_routes[Flows::Result::Err] ||= :term
|
22
|
-
|
23
|
-
Flows::Router.new(custom_routes)
|
24
|
-
end
|
25
|
-
|
26
|
-
def check_custom_routes(custom_routes, step_names)
|
27
|
-
custom_routes.values.each do |target|
|
28
|
-
next if step_names.include?(target) || target == :term
|
29
|
-
|
30
|
-
raise(::Flows::Operation::NoStepDefinedError, target)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
data/lib/flows/operation/dsl.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
module Flows
|
2
|
-
module Operation
|
3
|
-
# DSL methods for operation
|
4
|
-
module DSL
|
5
|
-
attr_reader :steps, :ok_shapes, :err_shapes
|
6
|
-
|
7
|
-
def self.extended(mod, steps = nil, ok_shapes = nil, err_shapes = nil)
|
8
|
-
mod.instance_variable_set(:@steps, steps || [])
|
9
|
-
mod.instance_variable_set(:@track_path, [])
|
10
|
-
mod.instance_variable_set(:@ok_shapes, ok_shapes)
|
11
|
-
mod.instance_variable_set(:@err_shapes, err_shapes)
|
12
|
-
|
13
|
-
mod.class_exec do
|
14
|
-
def self.inherited(subclass)
|
15
|
-
::Flows::Operation::DSL.extended(subclass, steps.map(&:dup), ok_shapes, err_shapes)
|
16
|
-
super
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
include Flows::Result::Helpers
|
22
|
-
|
23
|
-
def step(name, custom_body_or_routes = nil, custom_routes = nil)
|
24
|
-
if custom_routes
|
25
|
-
custom_body = custom_body_or_routes
|
26
|
-
elsif custom_body_or_routes.is_a? Hash
|
27
|
-
custom_routes = custom_body_or_routes
|
28
|
-
custom_body = nil
|
29
|
-
else
|
30
|
-
custom_routes = nil
|
31
|
-
custom_body = custom_body_or_routes
|
32
|
-
end
|
33
|
-
|
34
|
-
@steps << make_step(name, custom_routes: custom_routes, custom_body: custom_body)
|
35
|
-
end
|
36
|
-
|
37
|
-
def track(name, &block)
|
38
|
-
track_path_before = @track_path
|
39
|
-
@track_path += [name]
|
40
|
-
|
41
|
-
@steps << make_step(name, custom_body: ->(**) { ok })
|
42
|
-
instance_exec(&block)
|
43
|
-
|
44
|
-
@track_path = track_path_before
|
45
|
-
end
|
46
|
-
|
47
|
-
def routes(routes_hash)
|
48
|
-
routes_hash
|
49
|
-
end
|
50
|
-
|
51
|
-
alias when_ok match_ok
|
52
|
-
alias when_err match_err
|
53
|
-
|
54
|
-
def wrap(name, custom_body = nil, &block)
|
55
|
-
@steps << make_step(name, type: :wrapper, custom_body: custom_body, block: block)
|
56
|
-
end
|
57
|
-
|
58
|
-
def ok_shape(*keys, **code_keys_map)
|
59
|
-
@ok_shapes = if keys.empty?
|
60
|
-
code_keys_map
|
61
|
-
else
|
62
|
-
{ success: keys }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def err_shape(*keys, **code_keys_map)
|
67
|
-
@err_shapes = if keys.empty?
|
68
|
-
code_keys_map
|
69
|
-
else
|
70
|
-
{ failure: keys }
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def no_shape
|
75
|
-
@ok_shapes = :no_shapes
|
76
|
-
@err_shapes = :no_shapes
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
|
81
|
-
def make_step(name, type: :step, custom_routes: {}, custom_body: nil, block: nil)
|
82
|
-
{
|
83
|
-
type: type,
|
84
|
-
name: name,
|
85
|
-
custom_routes: custom_routes,
|
86
|
-
custom_body: custom_body,
|
87
|
-
block: block,
|
88
|
-
track_path: @track_path
|
89
|
-
}
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
module Flows
|
2
|
-
module Operation
|
3
|
-
# rubocop:disable Style/Documentation
|
4
|
-
class NoSuccessShapeError < ::Flows::Error
|
5
|
-
def message
|
6
|
-
'Missing success output shapes'
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
class NoFailureShapeError < ::Flows::Error
|
11
|
-
def message
|
12
|
-
'Missing failure output shape'
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class NoStepsError < ::Flows::Error
|
17
|
-
def message
|
18
|
-
'No steps defined'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class NoStepImplementationError < ::Flows::Error
|
23
|
-
def initialize(step_name)
|
24
|
-
@step_name = step_name
|
25
|
-
end
|
26
|
-
|
27
|
-
def message
|
28
|
-
"Missing step implementation for #{@step_name}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class NoStepDefinedError < ::Flows::Error
|
33
|
-
def initialize(step_name)
|
34
|
-
@step_name = step_name
|
35
|
-
end
|
36
|
-
|
37
|
-
def message
|
38
|
-
"Missing step or track definition: #{@step_name}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
class MissingOutputError < ::Flows::Error
|
43
|
-
def initialize(required_keys, actual_keys)
|
44
|
-
@missing_keys = required_keys - actual_keys
|
45
|
-
end
|
46
|
-
|
47
|
-
def message
|
48
|
-
"Missing keys in output: #{@missing_keys.join(', ')}"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class UnexpectedSuccessStatusError < ::Flows::Error
|
53
|
-
def initialize(actual_status, supported_statuses)
|
54
|
-
@actual_status = actual_status.inspect
|
55
|
-
@supported_statuses = supported_statuses.map(&:inspect).join(', ')
|
56
|
-
end
|
57
|
-
|
58
|
-
def message
|
59
|
-
"Unexpeted success result status: `#{@actual_status}`, supported statuses: `#{@supported_statuses}`"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class UnexpectedFailureStatusError < ::Flows::Error
|
64
|
-
def initialize(actual_status, supported_statuses)
|
65
|
-
@actual_status = actual_status.inspect
|
66
|
-
@supported_statuses = supported_statuses.map(&:inspect).join(', ')
|
67
|
-
end
|
68
|
-
|
69
|
-
def message
|
70
|
-
"Unexpeted failure result status: `#{@actual_status}`, supported statuses: `#{@supported_statuses}`"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
# rubocop:enable Style/Documentation
|
74
|
-
end
|
75
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
module Flows
|
2
|
-
module Operation
|
3
|
-
# Runner for operation steps
|
4
|
-
class Executor
|
5
|
-
include ::Flows::Result::Helpers
|
6
|
-
|
7
|
-
def initialize(flow:, ok_shapes:, err_shapes:, class_name:)
|
8
|
-
@flow = flow
|
9
|
-
|
10
|
-
@ok_shapes = ok_shapes
|
11
|
-
@err_shapes = err_shapes
|
12
|
-
@operation_class_name = class_name
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(**params)
|
16
|
-
context = { data: params }
|
17
|
-
last_result = @flow.call(nil, context: context)
|
18
|
-
|
19
|
-
build_result(last_result, context)
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def build_result(last_result, context)
|
25
|
-
status = last_result.status
|
26
|
-
|
27
|
-
case last_result
|
28
|
-
when Flows::Result::Ok then build_success_result(status, context)
|
29
|
-
when Flows::Result::Err then build_failure_result(status, context, last_result)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def build_success_result(status, context)
|
34
|
-
return ok(status, context[:data]) if @ok_shapes == :no_shapes
|
35
|
-
|
36
|
-
shape = @ok_shapes[status]
|
37
|
-
raise ::Flows::Operation::UnexpectedSuccessStatusError.new(status, @ok_shapes.keys) if shape.nil?
|
38
|
-
|
39
|
-
data = extract_data(context[:data], shape)
|
40
|
-
|
41
|
-
ok(status, data)
|
42
|
-
end
|
43
|
-
|
44
|
-
def build_failure_result(status, context, last_result)
|
45
|
-
raise ::Flows::Operation::NoFailureShapeError if @err_shapes.nil?
|
46
|
-
|
47
|
-
meta = build_meta(context, last_result)
|
48
|
-
|
49
|
-
return Flows::Result::Err.new(context[:data], status: status, meta: meta) if @err_shapes == :no_shapes
|
50
|
-
|
51
|
-
shape = @err_shapes[status]
|
52
|
-
raise ::Flows::Operation::UnexpectedFailureStatusError.new(status, @err_shapes.keys) if shape.nil?
|
53
|
-
|
54
|
-
data = extract_data(context[:data], shape)
|
55
|
-
|
56
|
-
Flows::Result::Err.new(data, status: status, meta: meta)
|
57
|
-
end
|
58
|
-
|
59
|
-
def extract_data(output, keys)
|
60
|
-
raise ::Flows::Operation::MissingOutputError.new(keys, output.keys) unless keys.all? { |key| output.key?(key) }
|
61
|
-
|
62
|
-
output.slice(*keys)
|
63
|
-
end
|
64
|
-
|
65
|
-
def build_meta(context, last_result)
|
66
|
-
meta = {
|
67
|
-
operation: @operation_class_name,
|
68
|
-
step: context[:last_step],
|
69
|
-
context_data: context[:data]
|
70
|
-
}
|
71
|
-
|
72
|
-
meta[:nested_metadata] = last_result.meta if last_result.meta.any?
|
73
|
-
|
74
|
-
meta
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|