dry-transaction 0.10.2 → 0.11.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 +5 -5
- data/Gemfile +1 -1
- data/Gemfile.lock +20 -14
- data/lib/dry/transaction/builder.rb +2 -4
- data/lib/dry/transaction/callable.rb +38 -0
- data/lib/dry/transaction/errors.rb +27 -0
- data/lib/dry/transaction/instance_methods.rb +22 -5
- data/lib/dry/transaction/operation.rb +4 -4
- data/lib/dry/transaction/operation_resolver.rb +5 -1
- data/lib/dry/transaction/result_matcher.rb +3 -3
- data/lib/dry/transaction/stack.rb +24 -0
- data/lib/dry/transaction/step.rb +37 -21
- data/lib/dry/transaction/step_adapter.rb +49 -0
- data/lib/dry/transaction/step_adapters/around.rb +25 -0
- data/lib/dry/transaction/step_adapters/check.rb +18 -0
- data/lib/dry/transaction/step_adapters/map.rb +3 -3
- data/lib/dry/transaction/step_adapters/raw.rb +6 -12
- data/lib/dry/transaction/step_adapters/tee.rb +4 -4
- data/lib/dry/transaction/step_adapters/try.rb +11 -8
- data/lib/dry/transaction/step_adapters.rb +2 -0
- data/lib/dry/transaction/version.rb +1 -1
- data/lib/dry/transaction.rb +14 -11
- data/spec/examples.txt +81 -65
- data/spec/integration/around_spec.rb +81 -0
- data/spec/integration/custom_step_adapters_spec.rb +6 -4
- data/spec/integration/operation_spec.rb +3 -3
- data/spec/integration/passing_step_arguments_spec.rb +1 -1
- data/spec/integration/publishing_step_events_spec.rb +36 -17
- data/spec/integration/transaction_spec.rb +165 -37
- data/spec/integration/transaction_without_steps_spec.rb +101 -0
- data/spec/spec_helper.rb +14 -5
- data/spec/support/container.rb +10 -0
- data/spec/support/database.rb +12 -0
- data/spec/support/db_transactions.rb +45 -0
- data/spec/support/result_mixin.rb +3 -0
- data/spec/unit/step_adapters/around_spec.rb +46 -0
- data/spec/unit/step_adapters/check_spec.rb +43 -0
- data/spec/unit/step_adapters/map_spec.rb +5 -12
- data/spec/unit/step_adapters/raw_spec.rb +16 -32
- data/spec/unit/step_adapters/tee_spec.rb +4 -10
- data/spec/unit/step_adapters/try_spec.rb +24 -33
- data/spec/unit/step_spec.rb +41 -10
- metadata +39 -21
- data/spec/support/either_mixin.rb +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6e276d629eb7ee813600d0cfce597d0857370b5ee44472de1495faa16f7db44f
|
|
4
|
+
data.tar.gz: 240ce1181835f188c975415c947b2b10f8f45de45d2ea6e0293af360d680796b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b6d04f7008727c783260df83e97221a5ebecc9b703da004d860bc040ed5334869d4844d2977cc5575e7a59ebd4a5ed95a6745aaa50981f7fb97aa777511265c2
|
|
7
|
+
data.tar.gz: b242f6281051877a0bc85f962e8655f3c92439388fa5790ad793ad34afbaa15a628f6f0aa8bc3484d250dd8be515232d18accca218a39a51a88d3c86d1f4bfe2
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
dry-transaction (0.
|
|
4
|
+
dry-transaction (0.11.0)
|
|
5
5
|
dry-container (>= 0.2.8)
|
|
6
|
-
dry-
|
|
7
|
-
dry-
|
|
8
|
-
|
|
6
|
+
dry-events (>= 0.1.0)
|
|
7
|
+
dry-matcher (>= 0.7.0)
|
|
8
|
+
dry-monads (>= 0.4.0)
|
|
9
9
|
|
|
10
10
|
GEM
|
|
11
11
|
remote: https://rubygems.org/
|
|
12
12
|
specs:
|
|
13
13
|
ast (2.3.0)
|
|
14
|
-
byebug (
|
|
14
|
+
byebug (9.1.0)
|
|
15
15
|
codeclimate-test-reporter (0.5.0)
|
|
16
16
|
simplecov (>= 0.7.1, < 1.0.0)
|
|
17
17
|
coderay (1.1.1)
|
|
@@ -23,12 +23,16 @@ GEM
|
|
|
23
23
|
dry-container (0.6.0)
|
|
24
24
|
concurrent-ruby (~> 1.0)
|
|
25
25
|
dry-configurable (~> 0.1, >= 0.1.3)
|
|
26
|
-
dry-core (0.
|
|
26
|
+
dry-core (0.4.2)
|
|
27
27
|
concurrent-ruby (~> 1.0)
|
|
28
28
|
dry-equalizer (0.2.0)
|
|
29
|
-
dry-
|
|
30
|
-
|
|
31
|
-
dry-core
|
|
29
|
+
dry-events (0.1.0)
|
|
30
|
+
concurrent-ruby (~> 1.0)
|
|
31
|
+
dry-core (~> 0.4)
|
|
32
|
+
dry-equalizer (~> 0.2)
|
|
33
|
+
dry-matcher (0.7.0)
|
|
34
|
+
dry-monads (0.4.0)
|
|
35
|
+
dry-core (~> 0.3, >= 0.3.3)
|
|
32
36
|
dry-equalizer
|
|
33
37
|
json (1.8.6)
|
|
34
38
|
method_source (0.8.2)
|
|
@@ -39,6 +43,9 @@ GEM
|
|
|
39
43
|
coderay (~> 1.1.0)
|
|
40
44
|
method_source (~> 0.8.1)
|
|
41
45
|
slop (~> 3.4)
|
|
46
|
+
pry-byebug (3.5.0)
|
|
47
|
+
byebug (~> 9.1)
|
|
48
|
+
pry (~> 0.10)
|
|
42
49
|
rainbow (2.1.0)
|
|
43
50
|
rake (11.2.2)
|
|
44
51
|
rspec (3.3.0)
|
|
@@ -68,7 +75,6 @@ GEM
|
|
|
68
75
|
simplecov-html (0.10.0)
|
|
69
76
|
slop (3.6.0)
|
|
70
77
|
unicode-display_width (1.1.1)
|
|
71
|
-
wisper (2.0.0)
|
|
72
78
|
yard (0.8.7.6)
|
|
73
79
|
|
|
74
80
|
PLATFORMS
|
|
@@ -76,16 +82,16 @@ PLATFORMS
|
|
|
76
82
|
|
|
77
83
|
DEPENDENCIES
|
|
78
84
|
bundler (~> 1.15)
|
|
79
|
-
byebug
|
|
80
85
|
codeclimate-test-reporter
|
|
81
86
|
dry-container
|
|
82
87
|
dry-transaction!
|
|
83
88
|
pry
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
pry-byebug
|
|
90
|
+
rake (~> 11.2, >= 11.2.2)
|
|
91
|
+
rspec (~> 3.3)
|
|
86
92
|
rubocop
|
|
87
93
|
simplecov
|
|
88
94
|
yard
|
|
89
95
|
|
|
90
96
|
BUNDLED WITH
|
|
91
|
-
1.
|
|
97
|
+
1.16.1
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require "dry/monads/either"
|
|
2
1
|
require "dry/transaction/step"
|
|
3
2
|
require "dry/transaction/dsl"
|
|
4
3
|
require "dry/transaction/instance_methods"
|
|
@@ -17,9 +16,8 @@ module Dry
|
|
|
17
16
|
|
|
18
17
|
def included(klass)
|
|
19
18
|
klass.extend(dsl_mod)
|
|
20
|
-
klass.
|
|
21
|
-
klass.
|
|
22
|
-
klass.send(:include, Dry::Monads::Either::Mixin)
|
|
19
|
+
klass.include(InstanceMethods)
|
|
20
|
+
klass.prepend(resolver_mod)
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
23
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Dry
|
|
2
|
+
module Transaction
|
|
3
|
+
# @api private
|
|
4
|
+
class Callable
|
|
5
|
+
def self.[](callable)
|
|
6
|
+
if callable.is_a?(self)
|
|
7
|
+
callable
|
|
8
|
+
elsif callable.nil?
|
|
9
|
+
nil
|
|
10
|
+
else
|
|
11
|
+
new(callable)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :operation
|
|
16
|
+
attr_reader :arity
|
|
17
|
+
|
|
18
|
+
def initialize(operation)
|
|
19
|
+
@operation = case operation
|
|
20
|
+
when Proc, Method
|
|
21
|
+
operation
|
|
22
|
+
else
|
|
23
|
+
operation.method(:call)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
@arity = @operation.arity
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def call(*args, &block)
|
|
30
|
+
if arity.zero?
|
|
31
|
+
operation.(&block)
|
|
32
|
+
else
|
|
33
|
+
operation.(*args, &block)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Dry
|
|
2
|
+
module Transaction
|
|
3
|
+
class InvalidStepError < ArgumentError
|
|
4
|
+
def initialize(step_name)
|
|
5
|
+
super("step +`#{step_name}`+ must respond to `#call`")
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class MissingStepError < ArgumentError
|
|
10
|
+
def initialize(step_name)
|
|
11
|
+
super("Definition for step +`#{step_name}`+ is missing")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class InvalidResultError < ArgumentError
|
|
16
|
+
def initialize(step_name)
|
|
17
|
+
super("step +#{step_name}+ must return a Result object")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class MissingCatchListError < ArgumentError
|
|
22
|
+
def initialize(step_name)
|
|
23
|
+
super("step +#{step_name}+ requires one or more exception classes provided via +catch:+")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -1,33 +1,38 @@
|
|
|
1
|
-
require "dry/monads"
|
|
1
|
+
require "dry/monads/result"
|
|
2
2
|
require "dry/transaction/result_matcher"
|
|
3
|
+
require "dry/transaction/stack"
|
|
3
4
|
|
|
4
5
|
module Dry
|
|
5
6
|
module Transaction
|
|
6
7
|
module InstanceMethods
|
|
8
|
+
include Dry::Monads::Result::Mixin
|
|
9
|
+
|
|
7
10
|
attr_reader :steps
|
|
8
11
|
attr_reader :operations
|
|
9
12
|
attr_reader :listeners
|
|
13
|
+
attr_reader :stack
|
|
10
14
|
|
|
11
15
|
def initialize(steps: (self.class.steps), listeners: nil, **operations)
|
|
12
16
|
@steps = steps.map { |step|
|
|
13
|
-
operation =
|
|
17
|
+
operation = resolve_operation(step, operations)
|
|
14
18
|
step.with(operation: operation)
|
|
15
19
|
}
|
|
16
20
|
@operations = operations
|
|
21
|
+
@stack = Stack.new(@steps)
|
|
17
22
|
subscribe(listeners) unless listeners.nil?
|
|
18
23
|
end
|
|
19
24
|
|
|
20
|
-
def call(input, &block)
|
|
25
|
+
def call(input = nil, &block)
|
|
21
26
|
assert_step_arity
|
|
22
27
|
|
|
23
|
-
result =
|
|
28
|
+
result = stack.(Success(input))
|
|
24
29
|
|
|
25
30
|
if block
|
|
26
31
|
ResultMatcher.(result, &block)
|
|
27
32
|
else
|
|
28
33
|
result.or { |step_failure|
|
|
29
34
|
# Unwrap the value from the StepFailure and return it directly
|
|
30
|
-
|
|
35
|
+
Failure(step_failure.value)
|
|
31
36
|
}
|
|
32
37
|
end
|
|
33
38
|
end
|
|
@@ -76,6 +81,18 @@ module Dry
|
|
|
76
81
|
operation.(*args, &block)
|
|
77
82
|
end
|
|
78
83
|
|
|
84
|
+
def resolve_operation(step, **operations)
|
|
85
|
+
if methods.include?(step.step_name) || private_methods.include?(step.step_name)
|
|
86
|
+
method(step.step_name)
|
|
87
|
+
elsif operations[step.step_name].nil?
|
|
88
|
+
raise MissingStepError.new(step.step_name)
|
|
89
|
+
elsif operations[step.step_name].respond_to?(:call)
|
|
90
|
+
operations[step.step_name]
|
|
91
|
+
else
|
|
92
|
+
raise InvalidStepError.new(step.step_name)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
79
96
|
def assert_valid_step_args(step_args)
|
|
80
97
|
step_args.each_key do |step_name|
|
|
81
98
|
unless steps.any? { |step| step.step_name == step_name }
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
require "dry/monads/
|
|
1
|
+
require "dry/monads/result"
|
|
2
2
|
require "dry/matcher"
|
|
3
|
-
require "dry/matcher/
|
|
3
|
+
require "dry/matcher/result_matcher"
|
|
4
4
|
|
|
5
5
|
module Dry
|
|
6
6
|
module Transaction
|
|
7
7
|
module Operation
|
|
8
8
|
def self.included(klass)
|
|
9
9
|
klass.class_eval do
|
|
10
|
-
include Dry::Monads::
|
|
11
|
-
include Dry::Matcher.for(:call, with: Dry::Matcher::
|
|
10
|
+
include Dry::Monads::Result::Mixin
|
|
11
|
+
include Dry::Matcher.for(:call, with: Dry::Matcher::ResultMatcher)
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -6,7 +6,11 @@ module Dry
|
|
|
6
6
|
define_method :initialize do |**kwargs|
|
|
7
7
|
operation_kwargs = self.class.steps.select(&:operation_name).map { |step|
|
|
8
8
|
operation = kwargs.fetch(step.step_name) {
|
|
9
|
-
ops_container
|
|
9
|
+
if ops_container && ops_container.key?(step.operation_name)
|
|
10
|
+
ops_container[step.operation_name]
|
|
11
|
+
else
|
|
12
|
+
nil
|
|
13
|
+
end
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
[step.step_name, operation]
|
|
@@ -5,17 +5,17 @@ module Dry
|
|
|
5
5
|
ResultMatcher = Dry::Matcher.new(
|
|
6
6
|
success: Dry::Matcher::Case.new(
|
|
7
7
|
match: -> result { result.right? },
|
|
8
|
-
resolve: -> result { result.value }
|
|
8
|
+
resolve: -> result { result.value! }
|
|
9
9
|
),
|
|
10
10
|
failure: Dry::Matcher::Case.new(
|
|
11
11
|
match: -> result, step_name = nil {
|
|
12
12
|
if step_name
|
|
13
|
-
result.left? && result.
|
|
13
|
+
result.left? && result.left.step.step_name == step_name
|
|
14
14
|
else
|
|
15
15
|
result.left?
|
|
16
16
|
end
|
|
17
17
|
},
|
|
18
|
-
resolve: -> result { result.
|
|
18
|
+
resolve: -> result { result.left.value }
|
|
19
19
|
)
|
|
20
20
|
)
|
|
21
21
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Dry
|
|
2
|
+
module Transaction
|
|
3
|
+
# @api private
|
|
4
|
+
class Stack
|
|
5
|
+
RETURN = -> x { x }
|
|
6
|
+
|
|
7
|
+
def initialize(steps)
|
|
8
|
+
@stack = compile(steps)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call(m)
|
|
12
|
+
@stack.(m)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def compile(steps)
|
|
18
|
+
steps.reverse.reduce(RETURN) do |next_step, step|
|
|
19
|
+
proc { |m| m.bind { |value| step.(value, next_step) } }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/dry/transaction/step.rb
CHANGED
|
@@ -1,62 +1,78 @@
|
|
|
1
|
-
require "dry/monads/
|
|
2
|
-
require
|
|
1
|
+
require "dry/monads/result"
|
|
2
|
+
require 'dry/events/publisher'
|
|
3
3
|
require "dry/transaction/step_failure"
|
|
4
|
+
require "dry/transaction/step_adapter"
|
|
4
5
|
|
|
5
6
|
module Dry
|
|
6
7
|
module Transaction
|
|
7
8
|
# @api private
|
|
8
9
|
class Step
|
|
9
10
|
UNDEFINED = Object.new.freeze
|
|
11
|
+
RETURN = -> x { x }
|
|
10
12
|
|
|
11
|
-
include
|
|
12
|
-
include Dry::Monads::
|
|
13
|
+
include Dry::Events::Publisher[name || object_id]
|
|
14
|
+
include Dry::Monads::Result::Mixin
|
|
15
|
+
|
|
16
|
+
register_event(:step)
|
|
17
|
+
register_event(:step_succeeded)
|
|
18
|
+
register_event(:step_failed)
|
|
13
19
|
|
|
14
20
|
attr_reader :step_adapter
|
|
15
21
|
attr_reader :step_name
|
|
16
22
|
attr_reader :operation_name
|
|
17
|
-
attr_reader :operation
|
|
18
|
-
attr_reader :options
|
|
19
23
|
attr_reader :call_args
|
|
20
24
|
|
|
21
25
|
def initialize(step_adapter, step_name, operation_name, operation, options, call_args = [])
|
|
22
|
-
@step_adapter = step_adapter
|
|
26
|
+
@step_adapter = StepAdapter[step_adapter, operation, **options, step_name: step_name]
|
|
23
27
|
@step_name = step_name
|
|
24
28
|
@operation_name = operation_name
|
|
25
|
-
@operation = operation
|
|
26
|
-
@options = options
|
|
27
29
|
@call_args = call_args
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
def with(operation: UNDEFINED, call_args: UNDEFINED)
|
|
31
33
|
return self if operation == UNDEFINED && call_args == UNDEFINED
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
|
|
35
|
+
new_operation = operation == UNDEFINED ? step_adapter.operation : operation
|
|
36
|
+
new_call_args = call_args == UNDEFINED ? self.call_args : Array(call_args)
|
|
34
37
|
|
|
35
38
|
self.class.new(
|
|
36
39
|
step_adapter,
|
|
37
40
|
step_name,
|
|
38
41
|
operation_name,
|
|
39
42
|
new_operation,
|
|
40
|
-
options,
|
|
41
|
-
new_call_args
|
|
43
|
+
step_adapter.options,
|
|
44
|
+
new_call_args
|
|
42
45
|
)
|
|
43
46
|
end
|
|
44
47
|
|
|
45
|
-
def call(input)
|
|
46
|
-
args = [input
|
|
47
|
-
|
|
48
|
+
def call(input, continue = RETURN)
|
|
49
|
+
args = [input, *call_args]
|
|
50
|
+
|
|
51
|
+
if step_adapter.yields?
|
|
52
|
+
with_broadcast(args) { step_adapter.(args, &continue) }
|
|
53
|
+
else
|
|
54
|
+
continue.(with_broadcast(args) { step_adapter.(args) })
|
|
55
|
+
end
|
|
56
|
+
end
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
def with_broadcast(args)
|
|
59
|
+
publish(:step, step_name: step_name, args: args)
|
|
60
|
+
|
|
61
|
+
yield.fmap { |value|
|
|
62
|
+
publish(:step_succeeded, step_name: step_name, args: args, value: value)
|
|
51
63
|
value
|
|
52
64
|
}.or { |value|
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
publish(:step_failed, step_name: step_name, args: args, value: value)
|
|
66
|
+
Failure(StepFailure.new(self, value))
|
|
55
67
|
}
|
|
56
68
|
end
|
|
57
69
|
|
|
58
70
|
def arity
|
|
59
|
-
|
|
71
|
+
step_adapter.operation.arity
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def operation
|
|
75
|
+
step_adapter.operation
|
|
60
76
|
end
|
|
61
77
|
end
|
|
62
78
|
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require "dry/transaction/callable"
|
|
2
|
+
|
|
3
|
+
module Dry
|
|
4
|
+
module Transaction
|
|
5
|
+
# @api private
|
|
6
|
+
class StepAdapter
|
|
7
|
+
def self.[](adapter, operation, options)
|
|
8
|
+
if adapter.is_a?(self)
|
|
9
|
+
adapter.with(operation, options)
|
|
10
|
+
else
|
|
11
|
+
new(adapter, operation, options)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :adapter
|
|
16
|
+
attr_reader :operation
|
|
17
|
+
attr_reader :options
|
|
18
|
+
|
|
19
|
+
def initialize(adapter, operation, options)
|
|
20
|
+
@adapter = case adapter
|
|
21
|
+
when Proc, Method
|
|
22
|
+
adapter
|
|
23
|
+
else
|
|
24
|
+
adapter.method(:call)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@operation = Callable[operation]
|
|
28
|
+
|
|
29
|
+
@options = options
|
|
30
|
+
|
|
31
|
+
@yields = @adapter.
|
|
32
|
+
parameters.
|
|
33
|
+
any? { |type, _| type == :block }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def yields?
|
|
37
|
+
@yields
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call(args, &block)
|
|
41
|
+
adapter.(operation, options, args, &block)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def with(operation = self.operation, new_options = {})
|
|
45
|
+
self.class.new(adapter, operation, options.merge(new_options))
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "dry/monads/result"
|
|
2
|
+
require "dry/transaction/errors"
|
|
3
|
+
|
|
4
|
+
module Dry
|
|
5
|
+
module Transaction
|
|
6
|
+
class StepAdapters
|
|
7
|
+
# @api private
|
|
8
|
+
class Around
|
|
9
|
+
include Dry::Monads::Result::Mixin
|
|
10
|
+
|
|
11
|
+
def call(operation, options, args, &block)
|
|
12
|
+
result = operation.(*args, &block)
|
|
13
|
+
|
|
14
|
+
unless result.is_a?(Dry::Monads::Result)
|
|
15
|
+
raise InvalidResultError.new(options[:step_name])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
result
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
register :around, Around.new
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Dry
|
|
2
|
+
module Transaction
|
|
3
|
+
class StepAdapters
|
|
4
|
+
# @api private
|
|
5
|
+
class Check
|
|
6
|
+
include Dry::Monads::Either::Mixin
|
|
7
|
+
|
|
8
|
+
def call(operation, _options, args)
|
|
9
|
+
input = args[0]
|
|
10
|
+
res = operation.(*args)
|
|
11
|
+
res == true || res.is_a?(Success) ? Success(input) : Failure(input)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
register :check, Check.new
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -3,10 +3,10 @@ module Dry
|
|
|
3
3
|
class StepAdapters
|
|
4
4
|
# @api private
|
|
5
5
|
class Map
|
|
6
|
-
include Dry::Monads::
|
|
6
|
+
include Dry::Monads::Result::Mixin
|
|
7
7
|
|
|
8
|
-
def call(
|
|
9
|
-
|
|
8
|
+
def call(operation, _options, args)
|
|
9
|
+
Success(operation.(*args))
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
require "dry/monads/
|
|
1
|
+
require "dry/monads/result"
|
|
2
|
+
require "dry/transaction/errors"
|
|
3
|
+
require "dry/transaction/step_adapters/around"
|
|
2
4
|
|
|
3
5
|
module Dry
|
|
4
6
|
module Transaction
|
|
5
7
|
class StepAdapters
|
|
6
8
|
# @api private
|
|
7
|
-
class Raw
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def call(step, input, *args)
|
|
11
|
-
result = step.operation.call(input, *args)
|
|
12
|
-
|
|
13
|
-
unless result.is_a?(Dry::Monads::Either)
|
|
14
|
-
raise ArgumentError, "step +#{step.step_name}+ must return an Either object"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
result
|
|
9
|
+
class Raw < Around
|
|
10
|
+
def call(operation, options, args)
|
|
11
|
+
super(operation, options, args, &nil)
|
|
18
12
|
end
|
|
19
13
|
end
|
|
20
14
|
|
|
@@ -3,11 +3,11 @@ module Dry
|
|
|
3
3
|
class StepAdapters
|
|
4
4
|
# @api private
|
|
5
5
|
class Tee
|
|
6
|
-
include Dry::Monads::
|
|
6
|
+
include Dry::Monads::Result::Mixin
|
|
7
7
|
|
|
8
|
-
def call(
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
def call(operation, _options, args)
|
|
9
|
+
operation.(*args)
|
|
10
|
+
Success(args[0])
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
+
require "dry/transaction/errors"
|
|
2
|
+
|
|
1
3
|
module Dry
|
|
2
4
|
module Transaction
|
|
3
5
|
class StepAdapters
|
|
4
6
|
# @api private
|
|
5
7
|
class Try
|
|
6
|
-
include Dry::Monads::
|
|
8
|
+
include Dry::Monads::Result::Mixin
|
|
7
9
|
|
|
8
|
-
def call(
|
|
9
|
-
unless
|
|
10
|
-
raise
|
|
10
|
+
def call(operation, options, args)
|
|
11
|
+
unless options[:catch]
|
|
12
|
+
raise MissingCatchListError.new(options[:step_name])
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
result = operation.(*args)
|
|
16
|
+
Success(result)
|
|
17
|
+
rescue *Array(options[:catch]) => e
|
|
18
|
+
e = options[:raise].new(e.message) if options[:raise]
|
|
19
|
+
Failure(e)
|
|
17
20
|
end
|
|
18
21
|
end
|
|
19
22
|
|
|
@@ -8,7 +8,9 @@ module Dry
|
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
require "dry/transaction/step_adapters/check"
|
|
11
12
|
require "dry/transaction/step_adapters/map"
|
|
12
13
|
require "dry/transaction/step_adapters/raw"
|
|
13
14
|
require "dry/transaction/step_adapters/tee"
|
|
14
15
|
require "dry/transaction/step_adapters/try"
|
|
16
|
+
require "dry/transaction/step_adapters/around"
|