-
-
Notifications
You must be signed in to change notification settings - Fork 55
/
step.rb
93 lines (76 loc) · 2.38 KB
/
step.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# frozen_string_literal: true
require "dry/transaction/step_failure"
require "dry/transaction/step_adapter"
module Dry
module Transaction
# @api private
class Step
UNDEFINED = Object.new.freeze
RETURN = -> x { x }
include Dry::Events::Publisher[name || object_id]
include Dry::Monads[:result]
register_event(:step)
register_event(:step_succeeded)
register_event(:step_failed)
attr_reader :adapter
attr_reader :name
attr_reader :operation_name
attr_reader :call_args
# rubocop:disable Metrics/ParameterLists
def initialize(adapter:, name:, operation_name:, options:, operation: nil, call_args: [])
@adapter = StepAdapter[adapter, operation,
{**options, step_name: name, operation_name: operation_name}]
@name = name
@operation_name = operation_name
@call_args = call_args
end
# rubocop:enable Metrics/ParameterLists
def with(operation: UNDEFINED, call_args: UNDEFINED)
return self if operation == UNDEFINED && call_args == UNDEFINED
new_operation = operation == UNDEFINED ? adapter.operation : operation
new_call_args = call_args == UNDEFINED ? self.call_args : Array(call_args)
self.class.new(
adapter: adapter,
name: name,
operation_name: operation_name,
operation: new_operation,
options: adapter.options,
call_args: new_call_args
)
end
def call(input, continue = RETURN)
args = [input, *call_args]
if adapter.yields?
with_broadcast(args) { adapter.(args, &continue) }
else
continue.(with_broadcast(args) { adapter.(args) })
end
end
def with_broadcast(args)
publish(:step, step_name: name, args: args)
yield.fmap { |value|
publish(:step_succeeded, step_name: name, args: args, value: value)
value
}.or { |value|
Failure(
StepFailure.(self, value) {
publish(:step_failed, step_name: name, args: args, value: value)
}
)
}
end
def internal?
!external?
end
def external?
!!operation_name
end
def arity
adapter.operation.arity
end
def operation
adapter.operation
end
end
end
end