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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/lib/workflow_template/action/abstract.rb +40 -0
  3. data/lib/workflow_template/action/description/validated.rb +58 -0
  4. data/lib/workflow_template/action/description/wrapper.rb +28 -0
  5. data/lib/workflow_template/action/nested.rb +59 -0
  6. data/lib/workflow_template/action/simple.rb +28 -0
  7. data/lib/workflow_template/action/validated.rb +104 -0
  8. data/lib/workflow_template/action/wrapper.rb +32 -0
  9. data/lib/workflow_template/action.rb +20 -0
  10. data/lib/workflow_template/adapters/state/default.rb +72 -0
  11. data/lib/workflow_template/adapters/state/dry_monads.rb +70 -0
  12. data/lib/workflow_template/adapters/validation/active_model/builder.rb +18 -0
  13. data/lib/workflow_template/adapters/validation/active_model/failure.rb +17 -0
  14. data/lib/workflow_template/adapters/validation/active_model/null_model.rb +24 -0
  15. data/lib/workflow_template/adapters/validation/active_model/validator.rb +35 -0
  16. data/lib/workflow_template/adapters/validation/active_model.rb +24 -0
  17. data/lib/workflow_template/adapters/validation/dry_validation/builder.rb +18 -0
  18. data/lib/workflow_template/adapters/validation/dry_validation/failure.rb +19 -0
  19. data/lib/workflow_template/adapters/validation/dry_validation/validator.rb +46 -0
  20. data/lib/workflow_template/adapters/validation/dry_validation.rb +24 -0
  21. data/lib/workflow_template/adapters/validation/generic/block.rb +24 -0
  22. data/lib/workflow_template/adapters/validation/generic/builder.rb +28 -0
  23. data/lib/workflow_template/adapters/validation/generic/object.rb +30 -0
  24. data/lib/workflow_template/adapters/validation/generic/validator.rb +25 -0
  25. data/lib/workflow_template/adapters/validation/generic.rb +24 -0
  26. data/lib/workflow_template/definer/has_actions/actions.rb +90 -0
  27. data/lib/workflow_template/definer/has_actions/description.rb +48 -0
  28. data/lib/workflow_template/definer/has_actions/dsl.rb +64 -0
  29. data/lib/workflow_template/definer/has_actions/insert.rb +28 -0
  30. data/lib/workflow_template/definer/has_actions/inside.rb +27 -0
  31. data/lib/workflow_template/definer/has_actions/nested.rb +65 -0
  32. data/lib/workflow_template/definer/has_actions/position.rb +83 -0
  33. data/lib/workflow_template/definer/has_actions/redefine.rb +28 -0
  34. data/lib/workflow_template/definer/has_actions/root.rb +22 -0
  35. data/lib/workflow_template/definer/has_actions.rb +45 -0
  36. data/lib/workflow_template/definer/has_default_state_transition_strategy.rb +34 -0
  37. data/lib/workflow_template/definer/has_output_normalizer.rb +35 -0
  38. data/lib/workflow_template/definer/has_state_adapter.rb +30 -0
  39. data/lib/workflow_template/definer/has_validations/action.rb +20 -0
  40. data/lib/workflow_template/definer/has_validations/description.rb +38 -0
  41. data/lib/workflow_template/definer/has_validations/validations.rb +162 -0
  42. data/lib/workflow_template/definer/has_validations.rb +70 -0
  43. data/lib/workflow_template/error.rb +99 -0
  44. data/lib/workflow_template/outcome/block.rb +58 -0
  45. data/lib/workflow_template/outcome/handler.rb +106 -0
  46. data/lib/workflow_template/outcome/status.rb +33 -0
  47. data/lib/workflow_template/outcome/statuses.rb +60 -0
  48. data/lib/workflow_template/outcome.rb +53 -0
  49. data/lib/workflow_template/performer.rb +46 -0
  50. data/lib/workflow_template/state/abstract.rb +33 -0
  51. data/lib/workflow_template/state/adapter.rb +67 -0
  52. data/lib/workflow_template/state/class_methods.rb +43 -0
  53. data/lib/workflow_template/state/final.rb +74 -0
  54. data/lib/workflow_template/state/intermediate.rb +102 -0
  55. data/lib/workflow_template/state/meta.rb +35 -0
  56. data/lib/workflow_template/state/normalizer.rb +34 -0
  57. data/lib/workflow_template/state/validation.rb +32 -0
  58. data/lib/workflow_template/state.rb +41 -0
  59. data/lib/workflow_template/validation/adapter/abstract/builder.rb +28 -0
  60. data/lib/workflow_template/validation/adapter/abstract/result/failure.rb +25 -0
  61. data/lib/workflow_template/validation/adapter/abstract/validator.rb +23 -0
  62. data/lib/workflow_template/validation/adapter.rb +35 -0
  63. data/lib/workflow_template/validation/builder/error.rb +11 -0
  64. data/lib/workflow_template/validation/builder/proxy.rb +129 -0
  65. data/lib/workflow_template/validation/error.rb +16 -0
  66. data/lib/workflow_template/validation/evaluation/abstract.rb +57 -0
  67. data/lib/workflow_template/validation/evaluation/boolean.rb +28 -0
  68. data/lib/workflow_template/validation/evaluation/canonical.rb +21 -0
  69. data/lib/workflow_template/validation/evaluation.rb +4 -0
  70. data/lib/workflow_template/validation/result/failure/abstract.rb +15 -0
  71. data/lib/workflow_template/validation/result/failure.rb +52 -0
  72. data/lib/workflow_template/validation/result/success.rb +19 -0
  73. data/lib/workflow_template/validation/validator/result/failure.rb +36 -0
  74. data/lib/workflow_template/validation/validator/result/success.rb +21 -0
  75. data/lib/workflow_template/workflow/description.rb +56 -0
  76. data/lib/workflow_template/workflow.rb +69 -0
  77. data/lib/workflow_template.rb +11 -0
  78. 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