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.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -6
- data/README.md +11 -7
- data/lib/dry/transaction.rb +35 -43
- data/lib/dry/transaction/builder.rb +26 -0
- data/lib/dry/transaction/dsl.rb +30 -38
- data/lib/dry/transaction/instance_methods.rb +95 -0
- data/lib/dry/transaction/operation.rb +16 -0
- data/lib/dry/transaction/operation_resolver.rb +19 -0
- data/lib/dry/transaction/result_matcher.rb +2 -2
- data/lib/dry/transaction/step.rb +19 -8
- data/lib/dry/transaction/step_adapters.rb +1 -1
- data/lib/dry/transaction/step_adapters/map.rb +1 -1
- data/lib/dry/transaction/step_adapters/raw.rb +1 -1
- data/lib/dry/transaction/step_adapters/tee.rb +1 -1
- data/lib/dry/transaction/step_adapters/try.rb +1 -1
- data/lib/dry/transaction/step_failure.rb +1 -3
- data/lib/dry/transaction/version.rb +2 -2
- data/spec/examples.txt +60 -75
- data/spec/integration/custom_step_adapters_spec.rb +12 -12
- data/spec/integration/operation_spec.rb +30 -0
- data/spec/integration/passing_step_arguments_spec.rb +14 -13
- data/spec/integration/publishing_step_events_spec.rb +14 -12
- data/spec/integration/transaction_spec.rb +140 -22
- data/spec/spec_helper.rb +6 -2
- data/spec/unit/step_spec.rb +29 -0
- metadata +10 -10
- data/lib/dry/transaction/api.rb +0 -301
- data/lib/dry/transaction/step_definition.rb +0 -23
- data/spec/integration/custom_matcher_spec.rb +0 -59
- data/spec/unit/step_definition_spec.rb +0 -32
- data/spec/unit/transaction_spec.rb +0 -209
@@ -1,59 +0,0 @@
|
|
1
|
-
require "dry-matcher"
|
2
|
-
require "dry-monads"
|
3
|
-
|
4
|
-
RSpec.describe "Custom matcher" do
|
5
|
-
let(:transaction) {
|
6
|
-
Dry.Transaction(container: container, matcher: Test::CustomMatcher) do
|
7
|
-
step :process
|
8
|
-
step :validate, failure: :bad_value
|
9
|
-
step :persist
|
10
|
-
end
|
11
|
-
}
|
12
|
-
|
13
|
-
let(:container) {
|
14
|
-
{
|
15
|
-
process: -> input { Dry::Monads.Right(name: input["name"], email: input["email"]) },
|
16
|
-
validate: -> input { input[:email].nil? ? Dry::Monads.Left(:email_required) : Dry::Monads.Right(input) },
|
17
|
-
persist: -> input { Test::DB << input and Dry::Monads.Right(input) }
|
18
|
-
}
|
19
|
-
}
|
20
|
-
|
21
|
-
before do
|
22
|
-
Test::DB = []
|
23
|
-
Test::QUEUE = []
|
24
|
-
|
25
|
-
module Test
|
26
|
-
CustomMatcher = Dry::Matcher.new(
|
27
|
-
yep: Dry::Matcher::Case.new(
|
28
|
-
match: -> result { result.right? },
|
29
|
-
resolve: -> result { result.value }
|
30
|
-
),
|
31
|
-
nup: Dry::Matcher::Case.new(
|
32
|
-
match: -> result, failure = nil {
|
33
|
-
if failure
|
34
|
-
result.left? && result.value.step.options[:failure] == failure
|
35
|
-
else
|
36
|
-
result.left?
|
37
|
-
end
|
38
|
-
},
|
39
|
-
resolve: -> result { result.value.value }
|
40
|
-
)
|
41
|
-
)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
it "supports a custom matcher" do
|
46
|
-
matches = -> m {
|
47
|
-
m.yep { |v| "Yep! #{v[:email]}" }
|
48
|
-
m.nup(:bad_value) { |v| "Nup. #{v.to_s}" }
|
49
|
-
}
|
50
|
-
|
51
|
-
input = {"name" => "Jane", "email" => "jane@doe.com"}
|
52
|
-
result = transaction.(input, &matches)
|
53
|
-
expect(result).to eq "Yep! jane@doe.com"
|
54
|
-
|
55
|
-
input = {"name" => "Jane"}
|
56
|
-
result = transaction.(input, &matches)
|
57
|
-
expect(result).to eq "Nup. email_required"
|
58
|
-
end
|
59
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::Transaction::StepDefinition do
|
2
|
-
let(:container) do
|
3
|
-
{ test: -> input { "This is a test with input: #{input.inspect}" } }
|
4
|
-
end
|
5
|
-
|
6
|
-
let(:step_definition) do
|
7
|
-
Dry::Transaction::StepDefinition.new(container) do |input|
|
8
|
-
Right(container[:test].call(input))
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
it { expect(step_definition).to be_kind_of(Dry::Monads::Either::Mixin) }
|
13
|
-
|
14
|
-
describe '#initialize' do
|
15
|
-
subject! { step_definition }
|
16
|
-
|
17
|
-
it { is_expected.to be_frozen }
|
18
|
-
end
|
19
|
-
|
20
|
-
describe '#call' do
|
21
|
-
let(:input) { { test: 'test' } }
|
22
|
-
|
23
|
-
subject!(:result) { step_definition.call(input) }
|
24
|
-
|
25
|
-
it do
|
26
|
-
expect(result.value).to eq(
|
27
|
-
"This is a test with input: {:test=>\"test\"}"
|
28
|
-
)
|
29
|
-
end
|
30
|
-
it { is_expected.to be_a(Dry::Monads::Either::Right) }
|
31
|
-
end
|
32
|
-
end
|
@@ -1,209 +0,0 @@
|
|
1
|
-
RSpec.describe Dry::Transaction do
|
2
|
-
subject(:container) {
|
3
|
-
{
|
4
|
-
upcase: -> input { input.upcase },
|
5
|
-
reverse: -> input { input.reverse },
|
6
|
-
exclaim_all: -> input { input.split(" ").map { |str| str + "!" }.join(" ") },
|
7
|
-
}
|
8
|
-
}
|
9
|
-
|
10
|
-
describe "#prepend" do
|
11
|
-
let(:initial_transaction) {
|
12
|
-
Dry.Transaction(container: container) do
|
13
|
-
map :exclaim_all
|
14
|
-
end
|
15
|
-
}
|
16
|
-
|
17
|
-
it "prepends the transaction" do
|
18
|
-
other_transaction = Dry.Transaction(container: container) do
|
19
|
-
map :reverse
|
20
|
-
end
|
21
|
-
new_transaction = initial_transaction.prepend(other_transaction)
|
22
|
-
|
23
|
-
expect(new_transaction.call("hello world").right).to eq "dlrow! olleh!"
|
24
|
-
end
|
25
|
-
|
26
|
-
it "accepts a transaction defined in a block" do
|
27
|
-
new_transaction = initial_transaction.prepend(container: container) do
|
28
|
-
map :reverse
|
29
|
-
end
|
30
|
-
|
31
|
-
expect(new_transaction.call("hello world").right).to eq "dlrow! olleh!"
|
32
|
-
end
|
33
|
-
|
34
|
-
it "raises an argument error if a transaction is neither passed nor defined" do
|
35
|
-
expect { initial_transaction.prepend }.to raise_error(ArgumentError)
|
36
|
-
end
|
37
|
-
|
38
|
-
it "leaves the original transaction unmodified" do
|
39
|
-
_new_transaction = initial_transaction.prepend(container: container) do
|
40
|
-
map :reverse
|
41
|
-
end
|
42
|
-
|
43
|
-
expect(initial_transaction.call("the quick brown fox").right).to eq "the! quick! brown! fox!"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe "#append" do
|
48
|
-
let(:initial_transaction) {
|
49
|
-
Dry.Transaction(container: container) do
|
50
|
-
map :exclaim_all
|
51
|
-
end
|
52
|
-
}
|
53
|
-
|
54
|
-
it "appends the transaction" do
|
55
|
-
other_transaction = Dry.Transaction(container: container) do
|
56
|
-
map :reverse
|
57
|
-
end
|
58
|
-
new_transaction = initial_transaction.append(other_transaction)
|
59
|
-
|
60
|
-
expect(new_transaction.call("hello world").right).to eq "!dlrow !olleh"
|
61
|
-
end
|
62
|
-
|
63
|
-
it "accepts a transaction defined in a block" do
|
64
|
-
new_transaction = initial_transaction.append(container: container) do
|
65
|
-
map :reverse
|
66
|
-
end
|
67
|
-
|
68
|
-
expect(new_transaction.call("hello world").right).to eq "!dlrow !olleh"
|
69
|
-
end
|
70
|
-
|
71
|
-
it "raises an argument error if a transaction is neither passed nor defined" do
|
72
|
-
expect { initial_transaction.insert(before: :reverse) }.to raise_error(ArgumentError)
|
73
|
-
end
|
74
|
-
|
75
|
-
it "leaves the original transaction unmodified" do
|
76
|
-
_new_transaction = initial_transaction.append(container: container) do
|
77
|
-
map :reverse
|
78
|
-
end
|
79
|
-
|
80
|
-
expect(initial_transaction.call("hello world").right).to eq "hello! world!"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
describe "#remove" do
|
85
|
-
let(:initial_transaction) {
|
86
|
-
Dry.Transaction(container: container) do
|
87
|
-
map :upcase
|
88
|
-
map :exclaim_all
|
89
|
-
map :reverse
|
90
|
-
end
|
91
|
-
}
|
92
|
-
|
93
|
-
it "removes the specified steps" do
|
94
|
-
new_transaction = initial_transaction.remove(:exclaim_all, :reverse)
|
95
|
-
expect(new_transaction.call("hello world").right).to eq "HELLO WORLD"
|
96
|
-
end
|
97
|
-
|
98
|
-
it "leaves the original transaction unmodified" do
|
99
|
-
_new_transaction = initial_transaction.remove(:exclaim_all, :reverse)
|
100
|
-
expect(initial_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "#insert" do
|
105
|
-
let(:initial_transaction) {
|
106
|
-
Dry.Transaction(container: container) do
|
107
|
-
map :upcase
|
108
|
-
map :reverse
|
109
|
-
end
|
110
|
-
}
|
111
|
-
|
112
|
-
it "accepts a transaction passed as an argument" do
|
113
|
-
other_transaction = Dry.Transaction(container: container) do
|
114
|
-
map :exclaim_all
|
115
|
-
end
|
116
|
-
new_transaction = initial_transaction.insert(other_transaction, before: :reverse)
|
117
|
-
|
118
|
-
expect(new_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
|
119
|
-
end
|
120
|
-
|
121
|
-
it "accepts a transaction defined in a block" do
|
122
|
-
new_transaction = initial_transaction.insert(before: :reverse, container: container) do
|
123
|
-
map :exclaim_all
|
124
|
-
end
|
125
|
-
|
126
|
-
expect(new_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
|
127
|
-
end
|
128
|
-
|
129
|
-
it "raises an argument error if a transaction is neither passed nor defined" do
|
130
|
-
expect { initial_transaction.insert(before: :reverse) }.to raise_error(ArgumentError)
|
131
|
-
end
|
132
|
-
|
133
|
-
it "raises an argument error if an invalid step name is provided" do
|
134
|
-
expect {
|
135
|
-
initial_transaction.insert(before: :non_existent, container: container) do
|
136
|
-
map :exclaim_all
|
137
|
-
end
|
138
|
-
}.to raise_error(ArgumentError)
|
139
|
-
end
|
140
|
-
|
141
|
-
context "before" do
|
142
|
-
let!(:new_transaction) {
|
143
|
-
initial_transaction.insert(before: :reverse, container: container) do
|
144
|
-
map :exclaim_all
|
145
|
-
end
|
146
|
-
}
|
147
|
-
|
148
|
-
it "inserts the new steps before the specified one" do
|
149
|
-
expect(new_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
|
150
|
-
end
|
151
|
-
|
152
|
-
it "leaves the original transaction unmodified" do
|
153
|
-
expect(initial_transaction.call("hello world").right).to eq "DLROW OLLEH"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
context "after" do
|
158
|
-
let!(:new_transaction) {
|
159
|
-
initial_transaction.insert(after: :reverse, container: container) do
|
160
|
-
map :exclaim_all
|
161
|
-
end
|
162
|
-
}
|
163
|
-
|
164
|
-
it "inserts the new steps after the specified one" do
|
165
|
-
expect(new_transaction.call("hello world").right).to eq "DLROW! OLLEH!"
|
166
|
-
end
|
167
|
-
|
168
|
-
it "leaves the original transaction unmodified" do
|
169
|
-
expect(initial_transaction.call("hello world").right).to eq "DLROW OLLEH"
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
context "with code block explicitly passed to step" do
|
174
|
-
class WithBlockStepAdapters < ::Dry::Transaction::StepAdapters # :nodoc:
|
175
|
-
class WithBlock
|
176
|
-
include Dry::Monads::Either::Mixin
|
177
|
-
def call(step, input, *args, &cb)
|
178
|
-
Right(step.operation.((block_given? ? yield(input) : input), *args))
|
179
|
-
end
|
180
|
-
end
|
181
|
-
register :with_block, WithBlock.new
|
182
|
-
end
|
183
|
-
let!(:with_block_container) {
|
184
|
-
{ exclaim_all: -> input { input.split(" ").map { |str| "#{str}!" }.join(" ") } }
|
185
|
-
}
|
186
|
-
|
187
|
-
let!(:no_block_transaction) {
|
188
|
-
Dry.Transaction(container: with_block_container, step_adapters: WithBlockStepAdapters) do
|
189
|
-
with_block :exclaim_all
|
190
|
-
end
|
191
|
-
}
|
192
|
-
let!(:with_block_transaction) {
|
193
|
-
Dry.Transaction(container: with_block_container, step_adapters: WithBlockStepAdapters) do
|
194
|
-
with_block :exclaim_all do |input|
|
195
|
-
input.gsub(/(?<=\s|\A)/, '¡')
|
196
|
-
end
|
197
|
-
end
|
198
|
-
}
|
199
|
-
|
200
|
-
it "inserts normal bangs without block given" do
|
201
|
-
expect(no_block_transaction.call("hello world").right).to eq "hello! world!"
|
202
|
-
end
|
203
|
-
|
204
|
-
it "inserts spanish bangs with block given" do
|
205
|
-
expect(with_block_transaction.call("hello world").right).to eq "¡hello! ¡world!"
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|