teckel 0.7.0 → 0.9.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/CHANGELOG.md +48 -7
- data/README.md +3 -3
- data/lib/teckel/chain/config.rb +35 -23
- data/lib/teckel/chain/result.rb +5 -9
- data/lib/teckel/chain/runner.rb +9 -7
- data/lib/teckel/chain.rb +19 -13
- data/lib/teckel/config.rb +15 -9
- data/lib/teckel/contracts.rb +3 -3
- data/lib/teckel/operation/config.rb +55 -48
- data/lib/teckel/operation/result.rb +16 -16
- data/lib/teckel/operation/runner.rb +5 -5
- data/lib/teckel/operation.rb +37 -18
- data/lib/teckel/result.rb +5 -3
- data/lib/teckel/version.rb +2 -1
- data/lib/teckel.rb +4 -1
- metadata +34 -53
- data/spec/chain/around_hook_spec.rb +0 -100
- data/spec/chain/default_settings_spec.rb +0 -39
- data/spec/chain/inheritance_spec.rb +0 -116
- data/spec/chain/none_input_spec.rb +0 -36
- data/spec/chain/results_spec.rb +0 -53
- data/spec/chain_spec.rb +0 -180
- data/spec/config_spec.rb +0 -26
- data/spec/doctest_helper.rb +0 -8
- data/spec/operation/contract_trace_spec.rb +0 -116
- data/spec/operation/default_settings_spec.rb +0 -94
- data/spec/operation/fail_on_input_spec.rb +0 -103
- data/spec/operation/inheritance_spec.rb +0 -94
- data/spec/operation/result_spec.rb +0 -55
- data/spec/operation/results_spec.rb +0 -117
- data/spec/operation_spec.rb +0 -483
- data/spec/rb27/pattern_matching_spec.rb +0 -193
- data/spec/result_spec.rb +0 -22
- data/spec/spec_helper.rb +0 -28
- data/spec/support/dry_base.rb +0 -8
- data/spec/support/fake_db.rb +0 -12
- data/spec/support/fake_models.rb +0 -20
- data/spec/teckel_spec.rb +0 -7
data/spec/operation_spec.rb
DELETED
@@ -1,483 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'support/dry_base'
|
4
|
-
require 'support/fake_models'
|
5
|
-
|
6
|
-
module TeckelOperationPredefinedClassesTest
|
7
|
-
class CreateUserInput < Dry::Struct
|
8
|
-
attribute :name, Types::String
|
9
|
-
attribute :age, Types::Coercible::Integer
|
10
|
-
end
|
11
|
-
|
12
|
-
CreateUserOutput = Types.Instance(User)
|
13
|
-
|
14
|
-
class CreateUserError < Dry::Struct
|
15
|
-
attribute :message, Types::String
|
16
|
-
attribute :status_code, Types::Integer
|
17
|
-
attribute :meta, Types::Hash.optional
|
18
|
-
end
|
19
|
-
|
20
|
-
class CreateUser
|
21
|
-
include Teckel::Operation
|
22
|
-
|
23
|
-
input CreateUserInput
|
24
|
-
output CreateUserOutput
|
25
|
-
error CreateUserError
|
26
|
-
|
27
|
-
def call(input)
|
28
|
-
user = User.new(**input.attributes)
|
29
|
-
if user.save
|
30
|
-
success!(user)
|
31
|
-
else
|
32
|
-
fail!(
|
33
|
-
message: "Could not create User",
|
34
|
-
status_code: 400,
|
35
|
-
meta: { validation: user.errors }
|
36
|
-
)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
module TeckelOperationInlineClassesTest
|
43
|
-
class CreateUser
|
44
|
-
include Teckel::Operation
|
45
|
-
|
46
|
-
class Input < Dry::Struct
|
47
|
-
attribute :name, Types::String
|
48
|
-
attribute :age, Types::Coercible::Integer
|
49
|
-
end
|
50
|
-
|
51
|
-
Output = Types.Instance(User)
|
52
|
-
|
53
|
-
class Error < Dry::Struct
|
54
|
-
attribute :message, Types::String
|
55
|
-
attribute :status_code, Types::Integer
|
56
|
-
attribute :meta, Types::Hash.optional
|
57
|
-
end
|
58
|
-
|
59
|
-
def call(input)
|
60
|
-
user = User.new(**input.attributes)
|
61
|
-
if user.save
|
62
|
-
success!(user)
|
63
|
-
else
|
64
|
-
fail!(
|
65
|
-
message: "Could not create User",
|
66
|
-
status_code: 400,
|
67
|
-
meta: { validation: user.errors }
|
68
|
-
)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
module TeckelOperationAnnonClassesTest
|
75
|
-
class CreateUser
|
76
|
-
include ::Teckel::Operation
|
77
|
-
|
78
|
-
input Types::Hash.schema(name: Types::String, age: Types::Coercible::Integer)
|
79
|
-
output Types.Instance(User)
|
80
|
-
error Types::Hash.schema(message: Types::String, errors: Types::Array.of(Types::Hash))
|
81
|
-
|
82
|
-
def call(input)
|
83
|
-
user = User.new(name: input[:name], age: input[:age])
|
84
|
-
if user.save
|
85
|
-
success!(user)
|
86
|
-
else
|
87
|
-
fail!(message: "Could not save User", errors: user.errors)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
module TeckelOperationKeywordContracts
|
94
|
-
class MyOperation
|
95
|
-
include Teckel::Operation
|
96
|
-
|
97
|
-
class Input
|
98
|
-
def initialize(name:, age:)
|
99
|
-
@name, @age = name, age
|
100
|
-
end
|
101
|
-
attr_reader :name, :age
|
102
|
-
end
|
103
|
-
|
104
|
-
input_constructor ->(data) { Input.new(**data) }
|
105
|
-
|
106
|
-
Output = ::User
|
107
|
-
|
108
|
-
class Error
|
109
|
-
def initialize(message, errors)
|
110
|
-
@message, @errors = message, errors
|
111
|
-
end
|
112
|
-
attr_reader :message, :errors
|
113
|
-
end
|
114
|
-
error_constructor :new
|
115
|
-
|
116
|
-
def call(input)
|
117
|
-
user = ::User.new(name: input.name, age: input.age)
|
118
|
-
if user.save
|
119
|
-
success!(user)
|
120
|
-
else
|
121
|
-
fail!(message: "Could not save User", errors: user.errors)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
module TeckelOperationCreateUserSplatInit
|
128
|
-
class MyOperation
|
129
|
-
include Teckel::Operation
|
130
|
-
|
131
|
-
input Struct.new(:name, :age)
|
132
|
-
input_constructor ->(data) { self.class.input.new(*data) }
|
133
|
-
|
134
|
-
Output = ::User
|
135
|
-
|
136
|
-
class Error
|
137
|
-
def initialize(message, errors)
|
138
|
-
@message, @errors = message, errors
|
139
|
-
end
|
140
|
-
attr_reader :message, :errors
|
141
|
-
end
|
142
|
-
error_constructor :new
|
143
|
-
|
144
|
-
def call(input)
|
145
|
-
user = ::User.new(name: input.name, age: input.age)
|
146
|
-
if user.save
|
147
|
-
success!(user)
|
148
|
-
else
|
149
|
-
fail!(message: "Could not save User", errors: user.errors)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
module TeckelOperationGeneratedOutputTest
|
156
|
-
class MyOperation
|
157
|
-
include ::Teckel::Operation
|
158
|
-
|
159
|
-
input none
|
160
|
-
output Struct.new(:some_key)
|
161
|
-
output_constructor ->(data) { output.new(*data.values_at(*output.members)) } # ruby 2.4 way for `keyword_init: true`
|
162
|
-
error none
|
163
|
-
|
164
|
-
def call(_input)
|
165
|
-
success!(some_key: "some_value")
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
module TeckelOperationNoSettingsTest
|
171
|
-
class MyOperation
|
172
|
-
include ::Teckel::Operation
|
173
|
-
|
174
|
-
input none
|
175
|
-
output none
|
176
|
-
error none
|
177
|
-
|
178
|
-
def call(_input); end
|
179
|
-
end
|
180
|
-
MyOperation.finalize!
|
181
|
-
end
|
182
|
-
|
183
|
-
module TeckelOperationNoneDataTest
|
184
|
-
class MyOperation
|
185
|
-
include ::Teckel::Operation
|
186
|
-
|
187
|
-
settings Struct.new(:fail_it, :fail_data, :success_it, :success_data)
|
188
|
-
settings_constructor ->(data) { settings.new(*data.values_at(*settings.members)) }
|
189
|
-
|
190
|
-
input none
|
191
|
-
output none
|
192
|
-
error none
|
193
|
-
|
194
|
-
def call(_input)
|
195
|
-
if settings&.fail_it
|
196
|
-
if settings&.fail_data
|
197
|
-
fail!(settings.fail_data)
|
198
|
-
else
|
199
|
-
fail!
|
200
|
-
end
|
201
|
-
elsif settings&.success_it
|
202
|
-
if settings&.success_data
|
203
|
-
success!(settings.success_data)
|
204
|
-
else
|
205
|
-
success!
|
206
|
-
end
|
207
|
-
else
|
208
|
-
settings&.success_data
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
module TeckelOperationInjectSettingsTest
|
215
|
-
class MyOperation
|
216
|
-
include ::Teckel::Operation
|
217
|
-
|
218
|
-
settings Struct.new(:injected)
|
219
|
-
settings_constructor ->(data) { settings.new(*data.values_at(*settings.members)) }
|
220
|
-
|
221
|
-
input none
|
222
|
-
output Array
|
223
|
-
error none
|
224
|
-
|
225
|
-
def call(_input)
|
226
|
-
success!((settings&.injected || []) << :operation_data)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
RSpec.describe Teckel::Operation do
|
232
|
-
context "predefined classes" do
|
233
|
-
specify "Input" do
|
234
|
-
expect(TeckelOperationPredefinedClassesTest::CreateUser.input).to eq(TeckelOperationPredefinedClassesTest::CreateUserInput)
|
235
|
-
end
|
236
|
-
|
237
|
-
specify "Output" do
|
238
|
-
expect(TeckelOperationPredefinedClassesTest::CreateUser.output).to eq(TeckelOperationPredefinedClassesTest::CreateUserOutput)
|
239
|
-
end
|
240
|
-
|
241
|
-
specify "Error" do
|
242
|
-
expect(TeckelOperationPredefinedClassesTest::CreateUser.error).to eq(TeckelOperationPredefinedClassesTest::CreateUserError)
|
243
|
-
end
|
244
|
-
|
245
|
-
context "success" do
|
246
|
-
specify do
|
247
|
-
result = TeckelOperationPredefinedClassesTest::CreateUser.call(name: "Bob", age: 23)
|
248
|
-
expect(result).to be_a(User)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
context "error" do
|
253
|
-
specify do
|
254
|
-
result = TeckelOperationPredefinedClassesTest::CreateUser.call(name: "Bob", age: 7)
|
255
|
-
expect(result).to be_a(TeckelOperationPredefinedClassesTest::CreateUserError)
|
256
|
-
expect(result).to have_attributes(
|
257
|
-
message: "Could not create User",
|
258
|
-
status_code: 400,
|
259
|
-
meta: { validation: [{ age: "underage" }] }
|
260
|
-
)
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
context "inline classes" do
|
266
|
-
specify "Input" do
|
267
|
-
expect(TeckelOperationInlineClassesTest::CreateUser.input).to be <= Dry::Struct
|
268
|
-
end
|
269
|
-
|
270
|
-
specify "Output" do
|
271
|
-
expect(TeckelOperationInlineClassesTest::CreateUser.output).to be_a Dry::Types::Constrained
|
272
|
-
end
|
273
|
-
|
274
|
-
specify "Error" do
|
275
|
-
expect(TeckelOperationInlineClassesTest::CreateUser.error).to be <= Dry::Struct
|
276
|
-
end
|
277
|
-
|
278
|
-
context "success" do
|
279
|
-
specify do
|
280
|
-
result = TeckelOperationInlineClassesTest::CreateUser.call(name: "Bob", age: 23)
|
281
|
-
expect(result).to be_a(User)
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
context "error" do
|
286
|
-
specify do
|
287
|
-
result = TeckelOperationInlineClassesTest::CreateUser.call(name: "Bob", age: 7)
|
288
|
-
expect(result).to have_attributes(
|
289
|
-
message: "Could not create User",
|
290
|
-
status_code: 400,
|
291
|
-
meta: { validation: [{ age: "underage" }] }
|
292
|
-
)
|
293
|
-
end
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
context "annon classes" do
|
298
|
-
specify "output" do
|
299
|
-
expect(TeckelOperationAnnonClassesTest::CreateUser.call(name: "Bob", age: 23)).to be_a(User)
|
300
|
-
end
|
301
|
-
|
302
|
-
specify "errors" do
|
303
|
-
expect(TeckelOperationAnnonClassesTest::CreateUser.call(name: "Bob", age: 10)).to eq(message: "Could not save User", errors: [{ age: "underage" }])
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
context "keyword contracts" do
|
308
|
-
specify do
|
309
|
-
expect(TeckelOperationKeywordContracts::MyOperation.call(name: "Bob", age: 23)).to be_a(User)
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
context "splat contracts" do
|
314
|
-
specify do
|
315
|
-
expect(TeckelOperationCreateUserSplatInit::MyOperation.call(["Bob", 23])).to be_a(User)
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
context "generated output" do
|
320
|
-
specify "result" do
|
321
|
-
result = TeckelOperationGeneratedOutputTest::MyOperation.call
|
322
|
-
expect(result).to be_a(Struct)
|
323
|
-
expect(result.some_key).to eq("some_value")
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
context "inject settings" do
|
328
|
-
it "settings in operation instances are nil by default" do
|
329
|
-
op = TeckelOperationInjectSettingsTest::MyOperation.new
|
330
|
-
expect(op.settings).to be_nil
|
331
|
-
end
|
332
|
-
|
333
|
-
it "uses injected data" do
|
334
|
-
result =
|
335
|
-
TeckelOperationInjectSettingsTest::MyOperation.
|
336
|
-
with(injected: [:stuff]).
|
337
|
-
call
|
338
|
-
|
339
|
-
expect(result).to eq([:stuff, :operation_data])
|
340
|
-
|
341
|
-
expect(TeckelOperationInjectSettingsTest::MyOperation.call).to eq([:operation_data])
|
342
|
-
end
|
343
|
-
|
344
|
-
specify "calling `with` multiple times raises an error" do
|
345
|
-
op = TeckelOperationInjectSettingsTest::MyOperation.with(injected: :stuff_1)
|
346
|
-
|
347
|
-
expect {
|
348
|
-
op.with(more: :stuff_2)
|
349
|
-
}.to raise_error(Teckel::Error, "Operation already has settings assigned.")
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
context "operation with no settings" do
|
354
|
-
it "uses None as default settings class" do
|
355
|
-
expect(TeckelOperationNoSettingsTest::MyOperation.settings).to eq(Teckel::Contracts::None)
|
356
|
-
expect(TeckelOperationNoSettingsTest::MyOperation.new.settings).to be_nil
|
357
|
-
end
|
358
|
-
|
359
|
-
it "raises error when trying to set settings" do
|
360
|
-
expect {
|
361
|
-
TeckelOperationNoSettingsTest::MyOperation.with(any: :thing)
|
362
|
-
}.to raise_error(ArgumentError, "None called with arguments")
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
context "None in, out, err" do
|
367
|
-
let(:operation) { TeckelOperationNoneDataTest::MyOperation }
|
368
|
-
|
369
|
-
it "raises error when called with input data" do
|
370
|
-
expect { operation.call("stuff") }.to raise_error(ArgumentError)
|
371
|
-
end
|
372
|
-
|
373
|
-
it "raises error when fail! with data" do
|
374
|
-
expect {
|
375
|
-
operation.with(fail_it: true, fail_data: "stuff").call
|
376
|
-
}.to raise_error(ArgumentError)
|
377
|
-
end
|
378
|
-
|
379
|
-
it "returns nil as failure result when fail! without arguments" do
|
380
|
-
expect(operation.with(fail_it: true).call).to be_nil
|
381
|
-
end
|
382
|
-
|
383
|
-
it "raises error when success! with data" do
|
384
|
-
expect {
|
385
|
-
operation.with(success_it: true, success_data: "stuff").call
|
386
|
-
}.to raise_error(ArgumentError)
|
387
|
-
end
|
388
|
-
|
389
|
-
it "returns nil as success result when success! without arguments" do
|
390
|
-
expect(operation.with(success_it: true).call).to be_nil
|
391
|
-
end
|
392
|
-
|
393
|
-
it "returns nil as success result when returning nil" do
|
394
|
-
expect(operation.call).to be_nil
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
describe "#finalize!" do
|
399
|
-
let(:frozen_error) do
|
400
|
-
# different ruby versions raise different errors
|
401
|
-
defined?(FrozenError) ? FrozenError : RuntimeError
|
402
|
-
end
|
403
|
-
|
404
|
-
subject do
|
405
|
-
Class.new do
|
406
|
-
include ::Teckel::Operation
|
407
|
-
|
408
|
-
input Struct.new(:input_data)
|
409
|
-
output Struct.new(:output_data)
|
410
|
-
|
411
|
-
def call(input)
|
412
|
-
success!(input.input_data * 2)
|
413
|
-
end
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
it "fails b/c error config is missing" do
|
418
|
-
expect {
|
419
|
-
subject.finalize!
|
420
|
-
}.to raise_error(Teckel::MissingConfigError, "Missing error config for #{subject}")
|
421
|
-
end
|
422
|
-
|
423
|
-
specify "#dup" do
|
424
|
-
new_operation = subject.dup
|
425
|
-
new_operation.error Struct.new(:error)
|
426
|
-
expect { new_operation.finalize! }.to_not raise_error
|
427
|
-
|
428
|
-
expect {
|
429
|
-
subject.finalize!
|
430
|
-
}.to raise_error(Teckel::MissingConfigError, "Missing error config for #{subject}")
|
431
|
-
end
|
432
|
-
|
433
|
-
specify "#clone" do
|
434
|
-
new_operation = subject.clone
|
435
|
-
new_operation.error Struct.new(:error)
|
436
|
-
expect { new_operation.finalize! }.to_not raise_error
|
437
|
-
|
438
|
-
expect {
|
439
|
-
subject.finalize!
|
440
|
-
}.to raise_error(Teckel::MissingConfigError, "Missing error config for #{subject}")
|
441
|
-
end
|
442
|
-
|
443
|
-
it "rejects any config changes" do
|
444
|
-
subject.error Struct.new(:error)
|
445
|
-
expect { subject.finalize! }.to_not raise_error
|
446
|
-
|
447
|
-
# no more after finalize!
|
448
|
-
subject.finalize!
|
449
|
-
|
450
|
-
expect {
|
451
|
-
subject.error Struct.new(:other_error)
|
452
|
-
}.to raise_error(Teckel::FrozenConfigError, "Configuration error is already set")
|
453
|
-
end
|
454
|
-
|
455
|
-
it "runs" do
|
456
|
-
subject.error Struct.new(:error)
|
457
|
-
subject.finalize!
|
458
|
-
|
459
|
-
result = subject.call("test")
|
460
|
-
expect(result.output_data).to eq("testtest")
|
461
|
-
end
|
462
|
-
|
463
|
-
it "accepts mocks" do
|
464
|
-
subject.error Struct.new(:error)
|
465
|
-
subject.finalize!
|
466
|
-
|
467
|
-
allow(subject).to receive(:call) { :mocked }
|
468
|
-
expect(subject.call).to eq(:mocked)
|
469
|
-
end
|
470
|
-
end
|
471
|
-
|
472
|
-
describe "overwriting configs is not allowed" do
|
473
|
-
it "raises" do
|
474
|
-
expect {
|
475
|
-
Class.new do
|
476
|
-
include ::Teckel::Operation
|
477
|
-
input none
|
478
|
-
input Struct.new(:name)
|
479
|
-
end
|
480
|
-
}.to raise_error Teckel::FrozenConfigError, "Configuration input is already set"
|
481
|
-
end
|
482
|
-
end
|
483
|
-
end
|
@@ -1,193 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
@warning = Warning[:experimental]
|
3
|
-
Warning[:experimental] = false
|
4
|
-
|
5
|
-
require 'support/dry_base'
|
6
|
-
require 'support/fake_models'
|
7
|
-
|
8
|
-
RSpec.describe "Ruby 2.7 pattern matches for Result and Chain" do
|
9
|
-
module TeckelChainPatternMatchingTest
|
10
|
-
class CreateUser
|
11
|
-
include ::Teckel::Operation
|
12
|
-
|
13
|
-
result!
|
14
|
-
|
15
|
-
input Types::Hash.schema(name: Types::String, age: Types::Coercible::Integer.optional)
|
16
|
-
output Types.Instance(User)
|
17
|
-
error Types::Hash.schema(message: Types::String, errors: Types::Array.of(Types::Hash))
|
18
|
-
|
19
|
-
def call(input)
|
20
|
-
user = User.new(name: input[:name], age: input[:age])
|
21
|
-
if user.save
|
22
|
-
success!(user)
|
23
|
-
else
|
24
|
-
fail!(message: "Could not save User", errors: user.errors)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class LogUser
|
30
|
-
include ::Teckel::Operation
|
31
|
-
|
32
|
-
result!
|
33
|
-
|
34
|
-
input Types.Instance(User)
|
35
|
-
error none
|
36
|
-
output input
|
37
|
-
|
38
|
-
def call(usr)
|
39
|
-
Logger.new(File::NULL).info("User #{usr.name} created")
|
40
|
-
success! usr
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class AddFriend
|
45
|
-
include ::Teckel::Operation
|
46
|
-
|
47
|
-
result!
|
48
|
-
|
49
|
-
settings Struct.new(:fail_befriend)
|
50
|
-
|
51
|
-
input Types.Instance(User)
|
52
|
-
output Types::Hash.schema(user: Types.Instance(User), friend: Types.Instance(User))
|
53
|
-
error Types::Hash.schema(message: Types::String)
|
54
|
-
|
55
|
-
def call(user)
|
56
|
-
if settings&.fail_befriend
|
57
|
-
fail!(message: "Did not find a friend.")
|
58
|
-
else
|
59
|
-
success!(user: user, friend: User.new(name: "A friend", age: 42))
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
class Chain
|
65
|
-
include Teckel::Chain
|
66
|
-
|
67
|
-
step :create, CreateUser
|
68
|
-
step :log, LogUser
|
69
|
-
step :befriend, AddFriend
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe "Operation Result" do
|
74
|
-
context "success" do
|
75
|
-
specify "pattern matching with keys" do
|
76
|
-
x =
|
77
|
-
case TeckelChainPatternMatchingTest::AddFriend.call(User.new(name: "bob", age: 23))
|
78
|
-
in { success: false, value: value }
|
79
|
-
["Failed", value]
|
80
|
-
in { success: true, value: value }
|
81
|
-
["Success result", value]
|
82
|
-
else
|
83
|
-
raise "Unexpected Result"
|
84
|
-
end
|
85
|
-
|
86
|
-
expect(x).to contain_exactly("Success result", hash_including(:friend, :user))
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
context "failure" do
|
91
|
-
specify "pattern matching with keys" do
|
92
|
-
result =
|
93
|
-
TeckelChainPatternMatchingTest::AddFriend.
|
94
|
-
with(befriend: :fail).
|
95
|
-
call(User.new(name: "bob", age: 23))
|
96
|
-
|
97
|
-
x =
|
98
|
-
case result
|
99
|
-
in { success: false, value: value }
|
100
|
-
["Failed", value]
|
101
|
-
in { success: true, value: value }
|
102
|
-
["Success result", value]
|
103
|
-
else
|
104
|
-
raise "Unexpected Result"
|
105
|
-
end
|
106
|
-
|
107
|
-
expect(x).to contain_exactly("Failed", hash_including(:message))
|
108
|
-
end
|
109
|
-
|
110
|
-
specify "pattern matching array" do
|
111
|
-
result =
|
112
|
-
TeckelChainPatternMatchingTest::AddFriend.
|
113
|
-
with(befriend: :fail).
|
114
|
-
call(User.new(name: "bob", age: 23))
|
115
|
-
|
116
|
-
x =
|
117
|
-
case result
|
118
|
-
in [false, value]
|
119
|
-
["Failed", value]
|
120
|
-
in [true, value]
|
121
|
-
["Success result", value]
|
122
|
-
else
|
123
|
-
raise "Unexpected Result"
|
124
|
-
end
|
125
|
-
expect(x).to contain_exactly("Failed", hash_including(:message))
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
describe "Chain" do
|
131
|
-
context "success" do
|
132
|
-
specify "pattern matching with keys" do
|
133
|
-
x =
|
134
|
-
case TeckelChainPatternMatchingTest::Chain.call(name: "Bob", age: 23)
|
135
|
-
in { success: false, step: :befriend, value: value }
|
136
|
-
["Failed", value]
|
137
|
-
in { success: true, value: value }
|
138
|
-
["Success result", value]
|
139
|
-
else
|
140
|
-
raise "Unexpected Result"
|
141
|
-
end
|
142
|
-
expect(x).to contain_exactly("Success result", hash_including(:friend, :user))
|
143
|
-
end
|
144
|
-
|
145
|
-
specify "pattern matching array" do
|
146
|
-
x =
|
147
|
-
case TeckelChainPatternMatchingTest::Chain.call(name: "Bob", age: 23)
|
148
|
-
in [false, :befriend, value]
|
149
|
-
"Failed in befriend with #{value}"
|
150
|
-
in [true, _, value]
|
151
|
-
"Success result"
|
152
|
-
end
|
153
|
-
expect(x).to eq("Success result")
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
context "failure" do
|
158
|
-
specify "pattern matching with keys" do
|
159
|
-
result =
|
160
|
-
TeckelChainPatternMatchingTest::Chain.
|
161
|
-
with(befriend: :fail).
|
162
|
-
call(name: "bob", age: 23)
|
163
|
-
|
164
|
-
x =
|
165
|
-
case result
|
166
|
-
in { success: false, step: :befriend, value: value }
|
167
|
-
"Failed in befriend with #{value}"
|
168
|
-
in { success: true, value: value }
|
169
|
-
"Success result"
|
170
|
-
end
|
171
|
-
expect(x).to eq("Failed in befriend with #{ {message: "Did not find a friend."} }")
|
172
|
-
end
|
173
|
-
|
174
|
-
specify "pattern matching array" do
|
175
|
-
result =
|
176
|
-
TeckelChainPatternMatchingTest::Chain.
|
177
|
-
with(befriend: :fail).
|
178
|
-
call(name: "Bob", age: 23)
|
179
|
-
|
180
|
-
x =
|
181
|
-
case result
|
182
|
-
in [false, :befriend, value]
|
183
|
-
"Failed in befriend with #{value}"
|
184
|
-
in [true, value]
|
185
|
-
"Success result"
|
186
|
-
end
|
187
|
-
expect(x).to eq("Failed in befriend with #{ {message: "Did not find a friend."} }")
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
Warning[:experimental] = @warning
|
data/spec/result_spec.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'support/dry_base'
|
4
|
-
require 'support/fake_models'
|
5
|
-
|
6
|
-
module TeckelResultTest
|
7
|
-
class MissingResultImplementation
|
8
|
-
include Teckel::Result
|
9
|
-
def initialize(value, success); end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
RSpec.describe Teckel::Result do
|
14
|
-
describe "missing initialize" do
|
15
|
-
specify "raises NotImplementedError" do
|
16
|
-
result = TeckelResultTest::MissingResultImplementation["value", true]
|
17
|
-
expect { result.successful? }.to raise_error(NotImplementedError, "Result object does not implement `successful?`")
|
18
|
-
expect { result.failure? }.to raise_error(NotImplementedError, "Result object does not implement `successful?`")
|
19
|
-
expect { result.value }.to raise_error(NotImplementedError, "Result object does not implement `value`")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|