dry-transaction 0.9.0 → 0.10.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.
@@ -3,9 +3,11 @@ require "wisper"
3
3
  require "dry/transaction/step_failure"
4
4
 
5
5
  module Dry
6
- class Transaction
6
+ module Transaction
7
7
  # @api private
8
8
  class Step
9
+ UNDEFINED = Object.new.freeze
10
+
9
11
  include Wisper::Publisher
10
12
  include Dry::Monads::Either::Mixin
11
13
 
@@ -14,26 +16,35 @@ module Dry
14
16
  attr_reader :operation_name
15
17
  attr_reader :operation
16
18
  attr_reader :options
17
- attr_reader :block
18
19
  attr_reader :call_args
19
20
 
20
- def initialize(step_adapter, step_name, operation_name, operation, options, call_args = [], &block)
21
+ def initialize(step_adapter, step_name, operation_name, operation, options, call_args = [])
21
22
  @step_adapter = step_adapter
22
23
  @step_name = step_name
23
24
  @operation_name = operation_name
24
25
  @operation = operation
25
26
  @options = options
26
- @block = block
27
27
  @call_args = call_args
28
28
  end
29
29
 
30
- def with_call_args(*call_args)
31
- self.class.new(step_adapter, step_name, operation_name, operation, options, call_args, &block)
30
+ def with(operation: UNDEFINED, call_args: UNDEFINED)
31
+ return self if operation == UNDEFINED && call_args == UNDEFINED
32
+ new_operation = operation == UNDEFINED ? self.operation : operation
33
+ new_call_args = call_args == UNDEFINED ? self.call_args : call_args
34
+
35
+ self.class.new(
36
+ step_adapter,
37
+ step_name,
38
+ operation_name,
39
+ new_operation,
40
+ options,
41
+ new_call_args,
42
+ )
32
43
  end
33
44
 
34
45
  def call(input)
35
- args = [input] + call_args
36
- result = step_adapter.call(self, *args, &block)
46
+ args = [input] + Array(call_args)
47
+ result = step_adapter.call(self, *args)
37
48
 
38
49
  result.fmap { |value|
39
50
  broadcast :"#{step_name}_success", value
@@ -1,7 +1,7 @@
1
1
  require "dry-container"
2
2
 
3
3
  module Dry
4
- class Transaction
4
+ module Transaction
5
5
  class StepAdapters
6
6
  extend Dry::Container::Mixin
7
7
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
- class Transaction
2
+ module Transaction
3
3
  class StepAdapters
4
4
  # @api private
5
5
  class Map
@@ -1,7 +1,7 @@
1
1
  require "dry/monads/either"
2
2
 
3
3
  module Dry
4
- class Transaction
4
+ module Transaction
5
5
  class StepAdapters
6
6
  # @api private
7
7
  class Raw
@@ -1,5 +1,5 @@
1
1
  module Dry
2
- class Transaction
2
+ module Transaction
3
3
  class StepAdapters
4
4
  # @api private
5
5
  class Tee
@@ -1,5 +1,5 @@
1
1
  module Dry
2
- class Transaction
2
+ module Transaction
3
3
  class StepAdapters
4
4
  # @api private
5
5
  class Try
@@ -1,13 +1,11 @@
1
1
  module Dry
2
- class Transaction
2
+ module Transaction
3
3
  # A wrapper for storing together the step that failed
4
4
  # and value describing the failure.
5
5
  class StepFailure
6
6
  attr_reader :step
7
7
  attr_reader :value
8
8
 
9
- # @param step [Step]
10
- # @param value [Object]
11
9
  def initialize(step, value)
12
10
  @step = step
13
11
  @value = value
@@ -1,6 +1,6 @@
1
1
  module Dry
2
2
  # Business transaction DSL.
3
- class Transaction
4
- VERSION = "0.9.0".freeze
3
+ module Transaction
4
+ VERSION = "0.10.0".freeze
5
5
  end
6
6
  end
data/spec/examples.txt CHANGED
@@ -1,77 +1,62 @@
1
1
  example_id | status | run_time |
2
2
  -------------------------------------------------------- | ------ | --------------- |
3
- ./spec/integration/custom_matcher_spec.rb[1:1] | passed | 0.00027 seconds |
4
- ./spec/integration/custom_step_adapters_spec.rb[1:1] | passed | 0.00042 seconds |
5
- ./spec/integration/passing_step_arguments_spec.rb[1:1:1] | passed | 0.00105 seconds |
6
- ./spec/integration/passing_step_arguments_spec.rb[1:2:1] | passed | 0.00122 seconds |
7
- ./spec/integration/passing_step_arguments_spec.rb[1:3:1] | passed | 0.00018 seconds |
8
- ./spec/integration/publishing_step_events_spec.rb[1:1:1] | passed | 0.00049 seconds |
9
- ./spec/integration/publishing_step_events_spec.rb[1:1:2] | passed | 0.00135 seconds |
10
- ./spec/integration/publishing_step_events_spec.rb[1:2:1] | passed | 0.0007 seconds |
11
- ./spec/integration/publishing_step_events_spec.rb[1:2:2] | passed | 0.00051 seconds |
12
- ./spec/integration/transaction_spec.rb[1:1:1] | passed | 0.00105 seconds |
13
- ./spec/integration/transaction_spec.rb[1:1:2] | passed | 0.00022 seconds |
14
- ./spec/integration/transaction_spec.rb[1:1:3] | passed | 0.00025 seconds |
15
- ./spec/integration/transaction_spec.rb[1:1:4] | passed | 0.00034 seconds |
16
- ./spec/integration/transaction_spec.rb[1:1:5] | passed | 0.00025 seconds |
17
- ./spec/integration/transaction_spec.rb[1:2:1] | passed | 0.00023 seconds |
18
- ./spec/integration/transaction_spec.rb[1:2:2] | passed | 0.00023 seconds |
19
- ./spec/integration/transaction_spec.rb[1:2:3] | passed | 0.00023 seconds |
20
- ./spec/integration/transaction_spec.rb[1:2:4] | passed | 0.00022 seconds |
21
- ./spec/integration/transaction_spec.rb[1:2:5] | passed | 0.00028 seconds |
22
- ./spec/integration/transaction_spec.rb[1:2:6] | passed | 0.00025 seconds |
23
- ./spec/integration/transaction_spec.rb[1:3:1] | passed | 0.00021 seconds |
24
- ./spec/integration/transaction_spec.rb[1:3:2] | passed | 0.00025 seconds |
25
- ./spec/integration/transaction_spec.rb[1:3:3] | passed | 0.00021 seconds |
26
- ./spec/integration/transaction_spec.rb[1:3:4] | passed | 0.00019 seconds |
27
- ./spec/integration/transaction_spec.rb[1:3:5] | passed | 0.00023 seconds |
28
- ./spec/integration/transaction_spec.rb[1:4:1] | passed | 0.00028 seconds |
29
- ./spec/unit/step_adapters/map_spec.rb[1:1:1] | passed | 0.00009 seconds |
30
- ./spec/unit/step_adapters/map_spec.rb[1:1:2] | passed | 0.0001 seconds |
31
- ./spec/unit/step_adapters/raw_spec.rb[1:1:1:1] | passed | 0.00015 seconds |
32
- ./spec/unit/step_adapters/raw_spec.rb[1:1:2:1] | passed | 0.00012 seconds |
33
- ./spec/unit/step_adapters/raw_spec.rb[1:1:2:2] | passed | 0.0001 seconds |
34
- ./spec/unit/step_adapters/raw_spec.rb[1:1:3:1] | passed | 0.00011 seconds |
35
- ./spec/unit/step_adapters/raw_spec.rb[1:1:3:2] | passed | 0.0006 seconds |
36
- ./spec/unit/step_adapters/tee_spec.rb[1:1:1] | passed | 0.00016 seconds |
37
- ./spec/unit/step_adapters/tee_spec.rb[1:1:2] | passed | 0.00011 seconds |
38
- ./spec/unit/step_adapters/try_spec.rb[1:1:1:1] | passed | 0.00018 seconds |
39
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:1] | passed | 0.00014 seconds |
40
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:2] | passed | 0.00016 seconds |
41
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:3:1] | passed | 0.00015 seconds |
42
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:3:2] | passed | 0.00016 seconds |
43
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:1] | passed | 0.00013 seconds |
44
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:2] | passed | 0.00015 seconds |
45
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:3:1] | passed | 0.00014 seconds |
46
- ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:3:2] | passed | 0.00014 seconds |
47
- ./spec/unit/step_definition_spec.rb[1:1] | passed | 0.00015 seconds |
48
- ./spec/unit/step_definition_spec.rb[1:2:1] | passed | 0.00013 seconds |
49
- ./spec/unit/step_definition_spec.rb[1:3:1] | passed | 0.00013 seconds |
50
- ./spec/unit/step_definition_spec.rb[1:3:2] | passed | 0.00013 seconds |
51
- ./spec/unit/step_spec.rb[1:1:1:1] | passed | 0.00017 seconds |
52
- ./spec/unit/step_spec.rb[1:1:1:2] | passed | 0.00042 seconds |
53
- ./spec/unit/step_spec.rb[1:1:2:1] | passed | 0.00144 seconds |
54
- ./spec/unit/step_spec.rb[1:1:2:2] | passed | 0.00153 seconds |
55
- ./spec/unit/step_spec.rb[1:1:2:3] | passed | 0.00641 seconds |
56
- ./spec/unit/step_spec.rb[1:2:1:1] | passed | 0.00016 seconds |
57
- ./spec/unit/step_spec.rb[1:2:2:1] | passed | 0.00013 seconds |
58
- ./spec/unit/transaction_spec.rb[1:1:1] | passed | 0.00024 seconds |
59
- ./spec/unit/transaction_spec.rb[1:1:2] | passed | 0.00019 seconds |
60
- ./spec/unit/transaction_spec.rb[1:1:3] | passed | 0.00016 seconds |
61
- ./spec/unit/transaction_spec.rb[1:1:4] | passed | 0.00019 seconds |
62
- ./spec/unit/transaction_spec.rb[1:2:1] | passed | 0.00016 seconds |
63
- ./spec/unit/transaction_spec.rb[1:2:2] | passed | 0.00018 seconds |
64
- ./spec/unit/transaction_spec.rb[1:2:3] | passed | 0.00015 seconds |
65
- ./spec/unit/transaction_spec.rb[1:2:4] | passed | 0.00016 seconds |
66
- ./spec/unit/transaction_spec.rb[1:3:1] | passed | 0.00015 seconds |
67
- ./spec/unit/transaction_spec.rb[1:3:2] | passed | 0.0002 seconds |
68
- ./spec/unit/transaction_spec.rb[1:4:1] | passed | 0.00028 seconds |
69
- ./spec/unit/transaction_spec.rb[1:4:2] | passed | 0.00019 seconds |
70
- ./spec/unit/transaction_spec.rb[1:4:3] | passed | 0.00013 seconds |
71
- ./spec/unit/transaction_spec.rb[1:4:4] | passed | 0.00014 seconds |
72
- ./spec/unit/transaction_spec.rb[1:4:5:1] | passed | 0.00023 seconds |
73
- ./spec/unit/transaction_spec.rb[1:4:5:2] | passed | 0.00018 seconds |
74
- ./spec/unit/transaction_spec.rb[1:4:6:1] | passed | 0.0002 seconds |
75
- ./spec/unit/transaction_spec.rb[1:4:6:2] | passed | 0.00022 seconds |
76
- ./spec/unit/transaction_spec.rb[1:4:7:1] | passed | 0.00019 seconds |
77
- ./spec/unit/transaction_spec.rb[1:4:7:2] | passed | 0.0002 seconds |
3
+ ./spec/integration/custom_step_adapters_spec.rb[1:1] | passed | 0.00312 seconds |
4
+ ./spec/integration/operation_spec.rb[1:1] | passed | 0.00014 seconds |
5
+ ./spec/integration/operation_spec.rb[1:2] | passed | 0.00016 seconds |
6
+ ./spec/integration/passing_step_arguments_spec.rb[1:1:1] | passed | 0.00048 seconds |
7
+ ./spec/integration/passing_step_arguments_spec.rb[1:2:1] | passed | 0.00038 seconds |
8
+ ./spec/integration/passing_step_arguments_spec.rb[1:3:1] | passed | 0.00067 seconds |
9
+ ./spec/integration/publishing_step_events_spec.rb[1:1:1] | passed | 0.00057 seconds |
10
+ ./spec/integration/publishing_step_events_spec.rb[1:1:2] | passed | 0.00054 seconds |
11
+ ./spec/integration/publishing_step_events_spec.rb[1:2:1] | passed | 0.00225 seconds |
12
+ ./spec/integration/publishing_step_events_spec.rb[1:2:2] | passed | 0.00048 seconds |
13
+ ./spec/integration/transaction_spec.rb[1:1:1] | passed | 0.00102 seconds |
14
+ ./spec/integration/transaction_spec.rb[1:1:2] | passed | 0.00083 seconds |
15
+ ./spec/integration/transaction_spec.rb[1:1:3] | passed | 0.00054 seconds |
16
+ ./spec/integration/transaction_spec.rb[1:1:4] | passed | 0.00207 seconds |
17
+ ./spec/integration/transaction_spec.rb[1:1:5] | passed | 0.00081 seconds |
18
+ ./spec/integration/transaction_spec.rb[1:2:1] | passed | 0.00032 seconds |
19
+ ./spec/integration/transaction_spec.rb[1:3:1] | passed | 0.00041 seconds |
20
+ ./spec/integration/transaction_spec.rb[1:4:1] | passed | 0.00032 seconds |
21
+ ./spec/integration/transaction_spec.rb[1:5:1] | passed | 0.00032 seconds |
22
+ ./spec/integration/transaction_spec.rb[1:6:1] | passed | 0.00098 seconds |
23
+ ./spec/integration/transaction_spec.rb[1:7:1] | passed | 0.00034 seconds |
24
+ ./spec/integration/transaction_spec.rb[1:7:2] | passed | 0.00035 seconds |
25
+ ./spec/integration/transaction_spec.rb[1:7:3] | passed | 0.00231 seconds |
26
+ ./spec/integration/transaction_spec.rb[1:7:4] | passed | 0.00035 seconds |
27
+ ./spec/integration/transaction_spec.rb[1:7:5] | passed | 0.00037 seconds |
28
+ ./spec/integration/transaction_spec.rb[1:7:6] | passed | 0.00038 seconds |
29
+ ./spec/integration/transaction_spec.rb[1:8:1] | passed | 0.00032 seconds |
30
+ ./spec/integration/transaction_spec.rb[1:8:2] | passed | 0.0003 seconds |
31
+ ./spec/integration/transaction_spec.rb[1:8:3] | passed | 0.00032 seconds |
32
+ ./spec/integration/transaction_spec.rb[1:8:4] | passed | 0.00033 seconds |
33
+ ./spec/integration/transaction_spec.rb[1:8:5] | passed | 0.00038 seconds |
34
+ ./spec/integration/transaction_spec.rb[1:9:1] | passed | 0.00031 seconds |
35
+ ./spec/unit/step_adapters/map_spec.rb[1:1:1] | passed | 0.00137 seconds |
36
+ ./spec/unit/step_adapters/map_spec.rb[1:1:2] | passed | 0.00124 seconds |
37
+ ./spec/unit/step_adapters/raw_spec.rb[1:1:1:1] | passed | 0.00217 seconds |
38
+ ./spec/unit/step_adapters/raw_spec.rb[1:1:2:1] | passed | 0.00011 seconds |
39
+ ./spec/unit/step_adapters/raw_spec.rb[1:1:2:2] | passed | 0.00011 seconds |
40
+ ./spec/unit/step_adapters/raw_spec.rb[1:1:3:1] | passed | 0.00013 seconds |
41
+ ./spec/unit/step_adapters/raw_spec.rb[1:1:3:2] | passed | 0.00011 seconds |
42
+ ./spec/unit/step_adapters/tee_spec.rb[1:1:1] | passed | 0.0001 seconds |
43
+ ./spec/unit/step_adapters/tee_spec.rb[1:1:2] | passed | 0.00015 seconds |
44
+ ./spec/unit/step_adapters/try_spec.rb[1:1:1:1] | passed | 0.00015 seconds |
45
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:1] | passed | 0.00013 seconds |
46
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:2] | passed | 0.00019 seconds |
47
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:3:1] | passed | 0.00012 seconds |
48
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:1:3:2] | passed | 0.00015 seconds |
49
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:1] | passed | 0.00047 seconds |
50
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:2] | passed | 0.00011 seconds |
51
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:3:1] | passed | 0.00012 seconds |
52
+ ./spec/unit/step_adapters/try_spec.rb[1:1:2:2:3:2] | passed | 0.00051 seconds |
53
+ ./spec/unit/step_spec.rb[1:1:1:1] | passed | 0.00057 seconds |
54
+ ./spec/unit/step_spec.rb[1:1:1:2] | passed | 0.00086 seconds |
55
+ ./spec/unit/step_spec.rb[1:1:2:1] | passed | 0.00305 seconds |
56
+ ./spec/unit/step_spec.rb[1:1:2:2] | passed | 0.00432 seconds |
57
+ ./spec/unit/step_spec.rb[1:1:2:3] | passed | 0.01511 seconds |
58
+ ./spec/unit/step_spec.rb[1:2:1:1] | passed | 0.00011 seconds |
59
+ ./spec/unit/step_spec.rb[1:2:2:1] | passed | 0.00012 seconds |
60
+ ./spec/unit/step_spec.rb[1:2:3:1] | passed | 0.00013 seconds |
61
+ ./spec/unit/step_spec.rb[1:3:1:1] | passed | 0.00014 seconds |
62
+ ./spec/unit/step_spec.rb[1:3:2:1] | passed | 0.00013 seconds |
@@ -1,18 +1,12 @@
1
1
  RSpec.describe "Custom step adapters" do
2
2
  let(:transaction) {
3
- Dry.Transaction(container: container, step_adapters: Test::CustomStepAdapters) do
4
- map :process
5
- tee :persist
6
- enqueue :deliver
7
- end
8
- }
3
+ Class.new do
4
+ include Dry::Transaction(container: Test::Container, step_adapters: Test::CustomStepAdapters)
9
5
 
10
- let(:container) {
11
- {
12
- process: -> input { {name: input["name"], email: input["email"]} },
13
- persist: -> input { Test::DB << input and true },
14
- deliver: -> input { "Delivered email to #{input[:email]}" },
15
- }
6
+ map :process, with: :process
7
+ tee :persist, with: :persist
8
+ enqueue :deliver, with: :deliver
9
+ end.new
16
10
  }
17
11
 
18
12
  before do
@@ -20,6 +14,12 @@ RSpec.describe "Custom step adapters" do
20
14
  Test::QUEUE = []
21
15
 
22
16
  module Test
17
+ Container = {
18
+ process: -> input { {name: input["name"], email: input["email"]} },
19
+ persist: -> input { Test::DB << input and true },
20
+ deliver: -> input { "Delivered email to #{input[:email]}" },
21
+ }
22
+
23
23
  class CustomStepAdapters < Dry::Transaction::StepAdapters
24
24
  extend Dry::Monads::Either::Mixin
25
25
 
@@ -0,0 +1,30 @@
1
+ require "dry/transaction/operation"
2
+
3
+ RSpec.describe Dry::Transaction::Operation do
4
+ subject(:operation) {
5
+ Class.new do
6
+ include Dry::Transaction::Operation
7
+
8
+ def call(input)
9
+ Right(input)
10
+ end
11
+ end.new
12
+ }
13
+
14
+ it "mixes in the Either monad constructors" do
15
+ expect(operation.("hello")).to be_right
16
+ end
17
+
18
+ it "supports pattern matching when called with a block" do
19
+ result = operation.("hello") do |m|
20
+ m.success do |v|
21
+ "Success: #{v}"
22
+ end
23
+ m.failure do |v|
24
+ "Failure: #{v}"
25
+ end
26
+ end
27
+
28
+ expect(result).to eq "Success: hello"
29
+ end
30
+ end
@@ -1,20 +1,14 @@
1
1
  RSpec.describe "Passing additional arguments to step operations" do
2
- let(:call_transaction) { transaction.call(input, step_options) }
2
+ let(:call_transaction) { transaction.with_step_args(step_options).call(input) }
3
3
 
4
4
  let(:transaction) {
5
- Dry.Transaction(container: container) do
6
- map :process
7
- try :validate, catch: Test::NotValidError
8
- tee :persist
9
- end
10
- }
5
+ Class.new do
6
+ include Dry::Transaction(container: Test::Container)
11
7
 
12
- let(:container) {
13
- {
14
- process: -> input { {name: input["name"], email: input["email"]} },
15
- validate: -> input, allowed { !input[:email].include?(allowed) ? raise(Test::NotValidError, "email not allowed") : input },
16
- persist: -> input { Test::DB << input and true }
17
- }
8
+ map :process, with: :process
9
+ try :validate, with: :validate, catch: Test::NotValidError
10
+ tee :persist, with: :persist
11
+ end.new
18
12
  }
19
13
 
20
14
  let(:input) { {"name" => "Jane", "email" => "jane@doe.com"} }
@@ -22,6 +16,13 @@ RSpec.describe "Passing additional arguments to step operations" do
22
16
  before do
23
17
  Test::NotValidError = Class.new(StandardError)
24
18
  Test::DB = []
19
+ module Test
20
+ Container = {
21
+ process: -> input { {name: input["name"], email: input["email"]} },
22
+ validate: -> input, allowed { !input[:email].include?(allowed) ? raise(Test::NotValidError, "email not allowed") : input },
23
+ persist: -> input { Test::DB << input and true }
24
+ }
25
+ end
25
26
  end
26
27
 
27
28
  context "required arguments provided" do
@@ -1,24 +1,26 @@
1
1
  RSpec.describe "publishing step events" do
2
2
  let(:transaction) {
3
- Dry.Transaction(container: container) do
4
- map :process
5
- step :verify
6
- tee :persist
7
- end
8
- }
3
+ Class.new do
4
+ include Dry::Transaction(container: Test::Container)
9
5
 
10
- let(:container) {
11
- {
12
- process: -> input { {name: input["name"]} },
13
- verify: -> input { input[:name].to_s != "" ? Right(input) : Left("no name") },
14
- persist: -> input { Test::DB << input and true }
15
- }
6
+ map :process, with: :process
7
+ step :verify, with: :verify
8
+ tee :persist, with: :persist
9
+ end.new
16
10
  }
17
11
 
18
12
  let(:subscriber) { spy(:subscriber) }
19
13
 
20
14
  before do
21
15
  Test::DB = []
16
+
17
+ module Test
18
+ Container = {
19
+ process: -> input { {name: input["name"]} },
20
+ verify: -> input { input[:name].to_s != "" ? Dry::Monads.Right(input) : Dry::Monads.Left("no name") },
21
+ persist: -> input { Test::DB << input and true }
22
+ }
23
+ end
22
24
  end
23
25
 
24
26
  context "subscribing to all step events" do
@@ -1,31 +1,25 @@
1
1
  RSpec.describe "Transactions" do
2
2
  let(:transaction) {
3
- Dry.Transaction(container: container) do
4
- map :process
5
- step :verify
6
- try :validate, with: -> input {
7
- if input[:email].nil?
8
- raise(container[:invalid_error], "email required")
9
- else
10
- input
11
- end
12
- }, catch: Test::NotValidError
13
- tee :persist
14
- end
3
+ Class.new do
4
+ include Dry::Transaction(container: Test::Container)
5
+ map :process
6
+ step :verify
7
+ try :validate, catch: Test::NotValidError
8
+ tee :persist
9
+ end.new(**dependencies)
15
10
  }
16
11
 
17
- let(:container) {
18
- {
19
- process: -> input { {name: input["name"], email: input["email"]} },
20
- verify: -> input { Right(input) },
21
- persist: -> input { Test::DB << input and true },
22
- invalid_error: Test::NotValidError
23
- }
24
- }
12
+ let(:dependencies) { {} }
25
13
 
26
14
  before do
27
15
  Test::NotValidError = Class.new(StandardError)
28
16
  Test::DB = []
17
+ Test::Container = {
18
+ process: -> input { {name: input["name"], email: input["email"]} },
19
+ verify: -> input { Right(input) },
20
+ validate: -> input { input[:email].nil? ? raise(Test::NotValidError, "email required") : input },
21
+ persist: -> input { Test::DB << input and true },
22
+ }
29
23
  end
30
24
 
31
25
  context "successful" do
@@ -67,6 +61,130 @@ RSpec.describe "Transactions" do
67
61
  end
68
62
  end
69
63
 
64
+ context "different step names" do
65
+ before do
66
+ module Test
67
+ ContainerNames = {
68
+ process_step: -> input { {name: input["name"], email: input["email"]} },
69
+ verify_step: -> input { Dry::Monads.Right(input) },
70
+ persist_step: -> input { Test::DB << input and true },
71
+ }
72
+ end
73
+ end
74
+
75
+ let(:transaction) {
76
+ Class.new do
77
+ include Dry::Transaction(container: Test::ContainerNames)
78
+
79
+ map :process, with: :process_step
80
+ step :verify, with: :verify_step
81
+ tee :persist, with: :persist_step
82
+ end.new(**dependencies)
83
+ }
84
+
85
+ it "supports steps using differently named container operations" do
86
+ transaction.call("name" => "Jane", "email" => "jane@doe.com")
87
+ expect(Test::DB).to include(name: "Jane", email: "jane@doe.com")
88
+ end
89
+ end
90
+
91
+ describe "operation injection" do
92
+ let(:transaction) {
93
+ Class.new do
94
+ include Dry::Transaction(container: Test::Container)
95
+ map :process
96
+ step :verify_step, with: :verify
97
+ tee :persist
98
+ end.new(**dependencies)
99
+ }
100
+
101
+ let(:dependencies) {
102
+ {verify_step: -> input { Dry::Monads.Right(input.merge(foo: :bar)) }}
103
+ }
104
+
105
+ it "calls injected operations" do
106
+ transaction.call("name" => "Jane", "email" => "jane@doe.com")
107
+
108
+ expect(Test::DB).to include(name: "Jane", email: "jane@doe.com", foo: :bar)
109
+ end
110
+ end
111
+
112
+ context "wrapping operations with local methods" do
113
+ let(:transaction) do
114
+ Class.new do
115
+ include Dry::Transaction(container: Test::Container)
116
+
117
+ map :process, with: :process
118
+ step :verify, with: :verify
119
+ tee :persist, with: :persist
120
+
121
+ def verify(input)
122
+ new_input = input.merge(greeting: "hello!")
123
+ super(new_input)
124
+ end
125
+ end.new(**dependencies)
126
+ end
127
+
128
+ let(:dependencies) { {} }
129
+
130
+ it "allows local methods to run operations via super" do
131
+ transaction.call("name" => "Jane", "email" => "jane@doe.com")
132
+
133
+ expect(Test::DB).to include(name: "Jane", email: "jane@doe.com", greeting: "hello!")
134
+ end
135
+ end
136
+
137
+ context "local step definition" do
138
+ let(:transaction) do
139
+ Class.new do
140
+ include Dry::Transaction(container: Test::Container)
141
+
142
+ map :process, with: :process
143
+ step :verify
144
+ tee :persist, with: :persist
145
+
146
+ def verify(input)
147
+ Right(input.keys)
148
+ end
149
+ end.new
150
+ end
151
+
152
+ it "execute step only defined as local method" do
153
+ transaction.call("name" => "Jane", "email" => "jane@doe.com")
154
+
155
+ expect(Test::DB).to include([:name, :email])
156
+ end
157
+ end
158
+
159
+ context "all steps are local methods" do
160
+ let(:transaction) do
161
+ Class.new do
162
+ include Dry::Transaction
163
+
164
+ map :process
165
+ step :verify
166
+ tee :persist
167
+
168
+ def process(input)
169
+ input.to_a
170
+ end
171
+
172
+ def verify(input)
173
+ Dry::Monads.Right(input)
174
+ end
175
+
176
+ def persist(input)
177
+ Test::DB << input and true
178
+ end
179
+ end.new
180
+ end
181
+
182
+ it "executes succesfully" do
183
+ transaction.call("name" => "Jane", "email" => "jane@doe.com")
184
+ expect(Test::DB).to include([["name", "Jane"], ["email", "jane@doe.com"]])
185
+ end
186
+ end
187
+
70
188
  context "failed in a try step" do
71
189
  let(:input) { {"name" => "Jane"} }
72
190
 
@@ -134,7 +252,7 @@ RSpec.describe "Transactions" do
134
252
  let(:input) { {"name" => "Jane", "email" => "jane@doe.com"} }
135
253
 
136
254
  before do
137
- container[:verify] = -> input { Left("raw failure") }
255
+ Test::Container[:verify] = -> input { Left("raw failure") }
138
256
  end
139
257
 
140
258
  it "does not run subsequent operations" do
@@ -167,7 +285,7 @@ RSpec.describe "Transactions" do
167
285
  let(:input) { {"name" => "Jane", "email" => "jane@doe.com"} }
168
286
 
169
287
  before do
170
- container[:verify] = -> input { "failure" }
288
+ Test::Container[:verify] = -> input { "failure" }
171
289
  end
172
290
 
173
291
  it "raises an exception" do