workflow_template 0.0.4
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 +7 -0
- data/lib/workflow_template/action/abstract.rb +40 -0
- data/lib/workflow_template/action/description/validated.rb +58 -0
- data/lib/workflow_template/action/description/wrapper.rb +28 -0
- data/lib/workflow_template/action/nested.rb +59 -0
- data/lib/workflow_template/action/simple.rb +28 -0
- data/lib/workflow_template/action/validated.rb +104 -0
- data/lib/workflow_template/action/wrapper.rb +32 -0
- data/lib/workflow_template/action.rb +20 -0
- data/lib/workflow_template/adapters/state/default.rb +72 -0
- data/lib/workflow_template/adapters/state/dry_monads.rb +70 -0
- data/lib/workflow_template/adapters/validation/active_model/builder.rb +18 -0
- data/lib/workflow_template/adapters/validation/active_model/failure.rb +17 -0
- data/lib/workflow_template/adapters/validation/active_model/null_model.rb +24 -0
- data/lib/workflow_template/adapters/validation/active_model/validator.rb +35 -0
- data/lib/workflow_template/adapters/validation/active_model.rb +24 -0
- data/lib/workflow_template/adapters/validation/dry_validation/builder.rb +18 -0
- data/lib/workflow_template/adapters/validation/dry_validation/failure.rb +19 -0
- data/lib/workflow_template/adapters/validation/dry_validation/validator.rb +46 -0
- data/lib/workflow_template/adapters/validation/dry_validation.rb +24 -0
- data/lib/workflow_template/adapters/validation/generic/block.rb +24 -0
- data/lib/workflow_template/adapters/validation/generic/builder.rb +28 -0
- data/lib/workflow_template/adapters/validation/generic/object.rb +30 -0
- data/lib/workflow_template/adapters/validation/generic/validator.rb +25 -0
- data/lib/workflow_template/adapters/validation/generic.rb +24 -0
- data/lib/workflow_template/definer/has_actions/actions.rb +90 -0
- data/lib/workflow_template/definer/has_actions/description.rb +48 -0
- data/lib/workflow_template/definer/has_actions/dsl.rb +64 -0
- data/lib/workflow_template/definer/has_actions/insert.rb +28 -0
- data/lib/workflow_template/definer/has_actions/inside.rb +27 -0
- data/lib/workflow_template/definer/has_actions/nested.rb +65 -0
- data/lib/workflow_template/definer/has_actions/position.rb +83 -0
- data/lib/workflow_template/definer/has_actions/redefine.rb +28 -0
- data/lib/workflow_template/definer/has_actions/root.rb +22 -0
- data/lib/workflow_template/definer/has_actions.rb +45 -0
- data/lib/workflow_template/definer/has_default_state_transition_strategy.rb +34 -0
- data/lib/workflow_template/definer/has_output_normalizer.rb +35 -0
- data/lib/workflow_template/definer/has_state_adapter.rb +30 -0
- data/lib/workflow_template/definer/has_validations/action.rb +20 -0
- data/lib/workflow_template/definer/has_validations/description.rb +38 -0
- data/lib/workflow_template/definer/has_validations/validations.rb +162 -0
- data/lib/workflow_template/definer/has_validations.rb +70 -0
- data/lib/workflow_template/error.rb +99 -0
- data/lib/workflow_template/outcome/block.rb +58 -0
- data/lib/workflow_template/outcome/handler.rb +106 -0
- data/lib/workflow_template/outcome/status.rb +33 -0
- data/lib/workflow_template/outcome/statuses.rb +60 -0
- data/lib/workflow_template/outcome.rb +53 -0
- data/lib/workflow_template/performer.rb +46 -0
- data/lib/workflow_template/state/abstract.rb +33 -0
- data/lib/workflow_template/state/adapter.rb +67 -0
- data/lib/workflow_template/state/class_methods.rb +43 -0
- data/lib/workflow_template/state/final.rb +74 -0
- data/lib/workflow_template/state/intermediate.rb +102 -0
- data/lib/workflow_template/state/meta.rb +35 -0
- data/lib/workflow_template/state/normalizer.rb +34 -0
- data/lib/workflow_template/state/validation.rb +32 -0
- data/lib/workflow_template/state.rb +41 -0
- data/lib/workflow_template/validation/adapter/abstract/builder.rb +28 -0
- data/lib/workflow_template/validation/adapter/abstract/result/failure.rb +25 -0
- data/lib/workflow_template/validation/adapter/abstract/validator.rb +23 -0
- data/lib/workflow_template/validation/adapter.rb +35 -0
- data/lib/workflow_template/validation/builder/error.rb +11 -0
- data/lib/workflow_template/validation/builder/proxy.rb +129 -0
- data/lib/workflow_template/validation/error.rb +16 -0
- data/lib/workflow_template/validation/evaluation/abstract.rb +57 -0
- data/lib/workflow_template/validation/evaluation/boolean.rb +28 -0
- data/lib/workflow_template/validation/evaluation/canonical.rb +21 -0
- data/lib/workflow_template/validation/evaluation.rb +4 -0
- data/lib/workflow_template/validation/result/failure/abstract.rb +15 -0
- data/lib/workflow_template/validation/result/failure.rb +52 -0
- data/lib/workflow_template/validation/result/success.rb +19 -0
- data/lib/workflow_template/validation/validator/result/failure.rb +36 -0
- data/lib/workflow_template/validation/validator/result/success.rb +21 -0
- data/lib/workflow_template/workflow/description.rb +56 -0
- data/lib/workflow_template/workflow.rb +69 -0
- data/lib/workflow_template.rb +11 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d667870c842a4893938a5e8c16d15a25dc93b34a5abac6d0bac3edb406508712
|
4
|
+
data.tar.gz: afdd0e2bfc21078e170220e8b94e60d6b5b0a9bccd66c212f7f28bdf82b59c24
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 95110fcbdecc896edb5e991ce6f02fcc8f3ee6f72ada962ab90dfdad469c3fdc9a23f7d4c2e04b112a9b9fcf416195ee035676cc046125203c3ac1acbfa70b56
|
7
|
+
data.tar.gz: 6768412262225de5d9df7ea6ab85cb294a6c3dedee3a7f34b6630e2c27c736379de6c5f5daa893e9de1ec56c8e04145eb43a94123cc75c407200444de8b68c0c
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../error'
|
4
|
+
|
5
|
+
module WorkflowTemplate
|
6
|
+
module Action
|
7
|
+
module Abstract
|
8
|
+
module Prepared
|
9
|
+
include Abstract
|
10
|
+
|
11
|
+
def perform(state, receiver)
|
12
|
+
raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Named
|
17
|
+
include Abstract
|
18
|
+
|
19
|
+
attr_reader :name
|
20
|
+
|
21
|
+
def initialize(name)
|
22
|
+
@name = name.to_sym
|
23
|
+
freeze
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Unprepared
|
28
|
+
include Named
|
29
|
+
end
|
30
|
+
|
31
|
+
def describe
|
32
|
+
raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
|
33
|
+
end
|
34
|
+
|
35
|
+
def prepare(*)
|
36
|
+
raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WorkflowTemplate
|
4
|
+
module Action
|
5
|
+
module Description
|
6
|
+
class Validated
|
7
|
+
def self.instance(action)
|
8
|
+
new action
|
9
|
+
end
|
10
|
+
|
11
|
+
private_class_method :new
|
12
|
+
|
13
|
+
attr_reader :action
|
14
|
+
|
15
|
+
def initialize(action)
|
16
|
+
@action = action
|
17
|
+
freeze
|
18
|
+
end
|
19
|
+
|
20
|
+
def format(level:)
|
21
|
+
["#{' ' * level}#{self.class.describe(action)}"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.describe(action)
|
25
|
+
extras = [
|
26
|
+
describe_defaults(action),
|
27
|
+
describe_validations(action),
|
28
|
+
describe_state_transition_strategy(action)
|
29
|
+
].compact
|
30
|
+
return action.name if extras.empty?
|
31
|
+
|
32
|
+
"#{action.name} #{extras.join(', ')}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.describe_defaults(action)
|
36
|
+
hash = action.defaults
|
37
|
+
return if hash.nil? || hash.empty?
|
38
|
+
|
39
|
+
"defaults: { #{hash.map { |key, value| "#{key}: #{value}" }.join(', ')} }"
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.describe_validations(action)
|
43
|
+
case action.validates
|
44
|
+
when nil then nil
|
45
|
+
when Array then "validates: #{action.validates.join(', ')}" unless action.validates.empty?
|
46
|
+
else "validates: #{action.validates}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.describe_state_transition_strategy(action)
|
51
|
+
return if action.state_transition_strategy.nil?
|
52
|
+
|
53
|
+
"state: #{action.state_transition_strategy}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'validated'
|
4
|
+
|
5
|
+
module WorkflowTemplate
|
6
|
+
module Action
|
7
|
+
module Description
|
8
|
+
class Wrapper < Validated
|
9
|
+
def self.instance(action, nested_actions)
|
10
|
+
new action, nested_actions
|
11
|
+
end
|
12
|
+
|
13
|
+
private_class_method :new
|
14
|
+
|
15
|
+
attr_reader :action, :nested_actions
|
16
|
+
|
17
|
+
def initialize(action, nested_actions)
|
18
|
+
@nested_actions = nested_actions.freeze
|
19
|
+
super(action)
|
20
|
+
end
|
21
|
+
|
22
|
+
def format(level:)
|
23
|
+
super + nested_actions.flat_map { |nested_action| nested_action.format(level: level + 1) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require_relative 'abstract'
|
5
|
+
|
6
|
+
module WorkflowTemplate
|
7
|
+
module Action
|
8
|
+
module Nested
|
9
|
+
class Unprepared
|
10
|
+
include Action::Abstract::Unprepared
|
11
|
+
include Nested
|
12
|
+
|
13
|
+
def self.instance(wrapper_action, workflow_module, &block)
|
14
|
+
workflow = Module.new do
|
15
|
+
extend workflow_module
|
16
|
+
|
17
|
+
instance_eval(&block)
|
18
|
+
send :store_wrapper_action, wrapper_action
|
19
|
+
|
20
|
+
freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
new(wrapper_action.name, workflow)
|
24
|
+
end
|
25
|
+
|
26
|
+
private_class_method :new
|
27
|
+
end
|
28
|
+
|
29
|
+
class Prepared
|
30
|
+
extend Forwardable
|
31
|
+
include Action::Abstract::Named
|
32
|
+
include Action::Abstract::Prepared
|
33
|
+
include Nested
|
34
|
+
|
35
|
+
def_delegator :@workflow, :perform
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(name, workflow)
|
39
|
+
@workflow = workflow
|
40
|
+
super(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def duplicate(&block)
|
44
|
+
duplicate = @workflow.redefine(&block)
|
45
|
+
|
46
|
+
Unprepared.send(:new, name, duplicate)
|
47
|
+
end
|
48
|
+
|
49
|
+
def prepare(*args)
|
50
|
+
prepared = @workflow.prepare(*args)
|
51
|
+
Prepared.send(:new, name, prepared)
|
52
|
+
end
|
53
|
+
|
54
|
+
def describe
|
55
|
+
@workflow.describe
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'validated'
|
4
|
+
|
5
|
+
module WorkflowTemplate
|
6
|
+
module Action
|
7
|
+
module Simple
|
8
|
+
class Unprepared < Validated::Unprepared
|
9
|
+
def prepare(validations)
|
10
|
+
Prepared.instance(self, validations)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Prepared < Validated::Prepared
|
15
|
+
private
|
16
|
+
|
17
|
+
def invoke_validated(state, receiver)
|
18
|
+
result = invoke_method(state, receiver)
|
19
|
+
state.process_wrapped_result(result, self, trace: true, validate: true)
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_standard_error(error, state)
|
23
|
+
state.merge_error(error, self)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require_relative 'abstract'
|
5
|
+
require_relative 'description/validated'
|
6
|
+
|
7
|
+
module WorkflowTemplate
|
8
|
+
module Action
|
9
|
+
module Validated
|
10
|
+
class Unprepared
|
11
|
+
include Abstract::Unprepared
|
12
|
+
|
13
|
+
def self.normalize_validation_names(option)
|
14
|
+
return if option.nil?
|
15
|
+
return option.map(&:to_sym).freeze if option.is_a?(Array)
|
16
|
+
|
17
|
+
option.to_sym.freeze
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :defaults, :validates, :state_transition_strategy
|
21
|
+
|
22
|
+
def initialize(name, defaults: nil, validates: nil, state_transition_strategy: nil)
|
23
|
+
@defaults = defaults.freeze
|
24
|
+
@validates = self.class.normalize_validation_names(validates)
|
25
|
+
|
26
|
+
unless state_transition_strategy.nil?
|
27
|
+
@state_transition_strategy = State.normalize_transition_strategy(state_transition_strategy)
|
28
|
+
end
|
29
|
+
super(name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare(*args)
|
33
|
+
raise NotImplementedError, "#{self.class.name}##{__method__} unimplemented"
|
34
|
+
end
|
35
|
+
|
36
|
+
def describe
|
37
|
+
Description::Validated.instance(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Prepared
|
42
|
+
include Abstract::Prepared
|
43
|
+
extend Forwardable
|
44
|
+
|
45
|
+
FATAL_SUBCLASSES = Fatal.constants.map { |name| Fatal.const_get(name) }.freeze
|
46
|
+
|
47
|
+
def_delegators :unprepared, :defaults
|
48
|
+
def_delegators :unprepared, :describe
|
49
|
+
def_delegators :unprepared, :name
|
50
|
+
def_delegators :unprepared, :state_transition_strategy
|
51
|
+
def_delegators :unprepared, :validates
|
52
|
+
|
53
|
+
def self.instance(unprepared, validations)
|
54
|
+
new unprepared, validations.resolve_validations(unprepared.validates)
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize(unprepared, validations)
|
58
|
+
@unprepared = unprepared
|
59
|
+
@validations = validations
|
60
|
+
freeze
|
61
|
+
end
|
62
|
+
|
63
|
+
private_class_method :new
|
64
|
+
|
65
|
+
def prepare(validations)
|
66
|
+
self.class.instance(unprepared, validations)
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_reader :unprepared, :validations
|
70
|
+
|
71
|
+
def perform(state, receiver, &block)
|
72
|
+
invoke_validated(state, receiver, &block)
|
73
|
+
rescue *FATAL_SUBCLASSES
|
74
|
+
raise
|
75
|
+
rescue Fatal => e
|
76
|
+
detailed = Fatal::Detailed.new(name, state.bare_state, e.message)
|
77
|
+
raise detailed
|
78
|
+
rescue ArgumentError => e
|
79
|
+
invocation = method(:invoke_validated)
|
80
|
+
raise Fatal::ArgumentError.new(name, e.message) if Fatal::ArgumentError.depth(e, invocation) == 2
|
81
|
+
|
82
|
+
handle_standard_error(e, state)
|
83
|
+
rescue StandardError => e
|
84
|
+
handle_standard_error(e, state)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def invoke_method(state, receiver, &block)
|
90
|
+
raise Fatal::Unimplemented, name unless receiver.respond_to? name
|
91
|
+
|
92
|
+
input = with_defaults(state.bare_state)
|
93
|
+
receiver.send(name, **input, &block)
|
94
|
+
end
|
95
|
+
|
96
|
+
def with_defaults(input)
|
97
|
+
return input if defaults.nil?
|
98
|
+
|
99
|
+
defaults.merge(input)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'validated'
|
4
|
+
require_relative 'description/wrapper'
|
5
|
+
|
6
|
+
module WorkflowTemplate
|
7
|
+
module Action
|
8
|
+
module Wrapper
|
9
|
+
class Unprepared < Validated::Unprepared
|
10
|
+
def prepare(validations)
|
11
|
+
Prepared.instance(self, validations)
|
12
|
+
end
|
13
|
+
|
14
|
+
def describe(nested_actions)
|
15
|
+
Description::Wrapper.instance(self, nested_actions)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Prepared < Validated::Prepared
|
20
|
+
private
|
21
|
+
|
22
|
+
def invoke_validated(state, receiver, *, &block)
|
23
|
+
invoke_method state, receiver, &block
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle_standard_error(error, state, *, **)
|
27
|
+
state.class.wrap_error_with_bare_state(error, {})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'action/simple'
|
4
|
+
require_relative 'action/wrapper'
|
5
|
+
require_relative 'action/nested'
|
6
|
+
|
7
|
+
module WorkflowTemplate
|
8
|
+
module Action
|
9
|
+
def self.instance(name, type, **opts)
|
10
|
+
case type
|
11
|
+
when :simple
|
12
|
+
Simple::Unprepared.new(name, **opts)
|
13
|
+
when :wrapper
|
14
|
+
Wrapper::Unprepared.new(name, **opts)
|
15
|
+
else
|
16
|
+
raise Error, "Unimplemented action type: #{type}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../state/adapter'
|
4
|
+
require_relative '../../state/validation'
|
5
|
+
|
6
|
+
module WorkflowTemplate
|
7
|
+
module Adapters
|
8
|
+
module State
|
9
|
+
module Default
|
10
|
+
module InstanceMethods
|
11
|
+
include WorkflowTemplate::State::Adapter::Abstract::InstanceMethods
|
12
|
+
|
13
|
+
# Optimizations
|
14
|
+
|
15
|
+
def halted?
|
16
|
+
!!wrapped_state[:halted]
|
17
|
+
end
|
18
|
+
|
19
|
+
def error?
|
20
|
+
!!wrapped_state[:error]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
include WorkflowTemplate::State::Adapter::Abstract::ClassMethods
|
26
|
+
|
27
|
+
def canonical?(wrapped_state)
|
28
|
+
wrapped_state.is_a? Hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def error?(wrapped_state)
|
32
|
+
!!wrapped_state[:error]
|
33
|
+
end
|
34
|
+
|
35
|
+
def wrap_success(bare_state)
|
36
|
+
bare_state
|
37
|
+
end
|
38
|
+
|
39
|
+
def unwrap_success(wrapped_state)
|
40
|
+
wrapped_state
|
41
|
+
end
|
42
|
+
|
43
|
+
def wrap_error_with_bare_state(error, bare_state)
|
44
|
+
{ **bare_state, error: error }
|
45
|
+
end
|
46
|
+
|
47
|
+
def unwrap_error(wrapped_state)
|
48
|
+
wrapped_state[:error]
|
49
|
+
end
|
50
|
+
|
51
|
+
def map_unwrappable_state(wrapped_state)
|
52
|
+
yield wrapped_state
|
53
|
+
end
|
54
|
+
|
55
|
+
def flat_map_unwrappable_state(wrapped_state)
|
56
|
+
yield wrapped_state
|
57
|
+
end
|
58
|
+
|
59
|
+
def run_handler!(state, binding, &block)
|
60
|
+
if binding
|
61
|
+
binding.receiver.instance_exec(**state.bare_state, &block)
|
62
|
+
else
|
63
|
+
block.call(**state.bare_state)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
WorkflowTemplate::State::Adapter.register :default, self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/monads'
|
4
|
+
require_relative '../../state/adapter'
|
5
|
+
|
6
|
+
module WorkflowTemplate
|
7
|
+
module Adapters
|
8
|
+
module State
|
9
|
+
module DryMonads
|
10
|
+
module Handler
|
11
|
+
extend Dry::Monads[:result]
|
12
|
+
end
|
13
|
+
|
14
|
+
module InstanceMethods
|
15
|
+
include WorkflowTemplate::State::Adapter::Abstract::InstanceMethods
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
include WorkflowTemplate::State::Adapter::Abstract::ClassMethods
|
20
|
+
|
21
|
+
def canonical?(wrapped_state)
|
22
|
+
wrapped_state.is_a? Dry::Monads::Result
|
23
|
+
end
|
24
|
+
|
25
|
+
def error?(wrapped_state)
|
26
|
+
wrapped_state.failure?
|
27
|
+
end
|
28
|
+
|
29
|
+
def wrap_success(bare_state)
|
30
|
+
Dry::Monads::Success(bare_state)
|
31
|
+
end
|
32
|
+
|
33
|
+
def unwrap_success(wrapped_state)
|
34
|
+
raise Fatal::InconsistentState, "Expected Success, got #{wrapped_state}" unless wrapped_state.success?
|
35
|
+
|
36
|
+
wrapped_state.success
|
37
|
+
end
|
38
|
+
|
39
|
+
def wrap_error_with_bare_state(error, _bare_state)
|
40
|
+
Dry::Monads::Failure(error)
|
41
|
+
end
|
42
|
+
|
43
|
+
def unwrap_error(wrapped_state)
|
44
|
+
raise Fatal::InconsistentState, "Expected Failure, got #{wrapped_state}" unless wrapped_state.failure?
|
45
|
+
|
46
|
+
wrapped_state.failure
|
47
|
+
end
|
48
|
+
|
49
|
+
def map_unwrappable_state(wrapped_state, &block)
|
50
|
+
wrapped_state.fmap(&block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def flat_map_unwrappable_state(wrapped_state, &block)
|
54
|
+
wrapped_state.bind(&block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def run_handler!(state, _binding, &block)
|
58
|
+
if state.error?
|
59
|
+
state.wrapped_state.or { Handler.instance_exec(state.error, &block) }
|
60
|
+
else
|
61
|
+
state.wrapped_state.bind { Handler.instance_exec(**state.bare_state, &block) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
WorkflowTemplate::State::Adapter.register(:dry_monads, self)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../validation/adapter/abstract/builder'
|
4
|
+
require_relative 'validator'
|
5
|
+
|
6
|
+
module WorkflowTemplate
|
7
|
+
module Adapters
|
8
|
+
module Validation
|
9
|
+
module ActiveModel
|
10
|
+
class Builder < WorkflowTemplate::Validation::Adapter::Abstract::Builder
|
11
|
+
def validate
|
12
|
+
proxy.declare(Validator)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../validation/validator/result/failure'
|
4
|
+
|
5
|
+
module WorkflowTemplate
|
6
|
+
module Adapters
|
7
|
+
module Validation
|
8
|
+
module ActiveModel
|
9
|
+
class Failure < WorkflowTemplate::Validation::Validator::Result::Failure
|
10
|
+
def message(*)
|
11
|
+
data.full_messages.to_sentence
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
|
5
|
+
module WorkflowTemplate
|
6
|
+
module Adapters
|
7
|
+
module Validation
|
8
|
+
module ActiveModel
|
9
|
+
class NullModel
|
10
|
+
include ::ActiveModel::Validations
|
11
|
+
include ::ActiveModel::Naming
|
12
|
+
|
13
|
+
@_model_name = ::ActiveModel::Name.new(self, nil, 'Unknown')
|
14
|
+
|
15
|
+
def base
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
validates :base, presence: true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../validation/adapter/abstract/validator'
|
4
|
+
require_relative '../../../validation/validator/result/success'
|
5
|
+
require_relative 'failure'
|
6
|
+
require_relative 'null_model'
|
7
|
+
|
8
|
+
module WorkflowTemplate
|
9
|
+
module Adapters
|
10
|
+
module Validation
|
11
|
+
module ActiveModel
|
12
|
+
class Validator
|
13
|
+
extend WorkflowTemplate::Validation::Adapter::Abstract::Validator
|
14
|
+
|
15
|
+
def self.call(input)
|
16
|
+
model = input || NullModel.new
|
17
|
+
return WorkflowTemplate::Validation::Validator::Result::Success if model.valid?
|
18
|
+
|
19
|
+
code = input ? "#{model.model_name.singular}_invalid" : :model_nil
|
20
|
+
|
21
|
+
Failure.new(
|
22
|
+
self,
|
23
|
+
code: code,
|
24
|
+
data: model.errors
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.describe
|
29
|
+
'model to be valid'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../validation/adapter'
|
4
|
+
require_relative 'active_model/builder'
|
5
|
+
|
6
|
+
module WorkflowTemplate
|
7
|
+
module Adapters
|
8
|
+
module Validation
|
9
|
+
module ActiveModel
|
10
|
+
extend WorkflowTemplate::Validation::Adapter
|
11
|
+
|
12
|
+
def self.builder_class
|
13
|
+
Builder
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.result_type
|
17
|
+
:canonical
|
18
|
+
end
|
19
|
+
|
20
|
+
register(:active_model)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../validation/adapter/abstract/builder'
|
4
|
+
require_relative 'validator'
|
5
|
+
|
6
|
+
module WorkflowTemplate
|
7
|
+
module Adapters
|
8
|
+
module Validation
|
9
|
+
module DryValidation
|
10
|
+
class Builder < WorkflowTemplate::Validation::Adapter::Abstract::Builder
|
11
|
+
def validate(contract:)
|
12
|
+
proxy.declare(Validator.new(contract))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../validation/validator/result/failure'
|
4
|
+
|
5
|
+
module WorkflowTemplate
|
6
|
+
module Adapters
|
7
|
+
module Validation
|
8
|
+
module DryValidation
|
9
|
+
class Failure < WorkflowTemplate::Validation::Validator::Result::Failure
|
10
|
+
def message(*)
|
11
|
+
return if data.nil?
|
12
|
+
|
13
|
+
data.errors(full: true).messages.map(&:text).join(', ')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|