teckel 0.4.0 → 0.8.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 +71 -0
- data/README.md +3 -3
- data/lib/teckel/chain/config.rb +286 -0
- data/lib/teckel/chain/result.rb +3 -3
- data/lib/teckel/chain/runner.rb +28 -17
- data/lib/teckel/chain.rb +14 -190
- data/lib/teckel/config.rb +13 -7
- data/lib/teckel/operation/config.rb +400 -0
- data/lib/teckel/operation/result.rb +8 -8
- data/lib/teckel/operation/runner.rb +29 -25
- data/lib/teckel/operation.rb +87 -388
- data/lib/teckel/result.rb +8 -6
- data/lib/teckel/version.rb +1 -1
- data/lib/teckel.rb +0 -1
- data/spec/chain/around_hook_spec.rb +100 -0
- data/spec/chain/default_settings_spec.rb +39 -0
- data/spec/chain/inheritance_spec.rb +44 -44
- data/spec/chain/none_input_spec.rb +36 -0
- data/spec/chain/results_spec.rb +28 -28
- data/spec/chain_spec.rb +132 -57
- data/spec/doctest_helper.rb +1 -0
- data/spec/operation/config_spec.rb +227 -0
- data/spec/operation/contract_trace_spec.rb +118 -0
- data/spec/operation/default_settings_spec.rb +120 -0
- data/spec/operation/fail_on_input_spec.rb +103 -0
- data/spec/operation/inheritance_spec.rb +38 -38
- data/spec/operation/result_spec.rb +27 -12
- data/spec/operation/results_spec.rb +67 -67
- data/spec/operation_spec.rb +276 -230
- data/spec/rb27/pattern_matching_spec.rb +2 -2
- data/spec/result_spec.rb +12 -10
- data/spec/spec_helper.rb +10 -0
- metadata +41 -12
- data/spec/chain_around_hook_spec.rb +0 -100
data/spec/operation_spec.rb
CHANGED
@@ -3,44 +3,238 @@
|
|
3
3
|
require 'support/dry_base'
|
4
4
|
require 'support/fake_models'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
+
)
|
12
37
|
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
13
41
|
|
14
|
-
|
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
|
15
58
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
+
)
|
20
69
|
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
21
73
|
|
22
|
-
|
23
|
-
|
74
|
+
module TeckelOperationAnnonClassesTest
|
75
|
+
class CreateUser
|
76
|
+
include ::Teckel::Operation
|
24
77
|
|
25
|
-
|
26
|
-
|
27
|
-
|
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))
|
28
81
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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!
|
40
206
|
end
|
207
|
+
else
|
208
|
+
settings&.success_data
|
41
209
|
end
|
42
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
|
43
230
|
|
231
|
+
RSpec.describe Teckel::Operation do
|
232
|
+
let(:frozen_error) do
|
233
|
+
# different ruby versions raise different errors
|
234
|
+
defined?(FrozenError) ? FrozenError : RuntimeError
|
235
|
+
end
|
236
|
+
|
237
|
+
context "predefined classes" do
|
44
238
|
specify "Input" do
|
45
239
|
expect(TeckelOperationPredefinedClassesTest::CreateUser.input).to eq(TeckelOperationPredefinedClassesTest::CreateUserInput)
|
46
240
|
end
|
@@ -74,38 +268,6 @@ RSpec.describe Teckel::Operation do
|
|
74
268
|
end
|
75
269
|
|
76
270
|
context "inline classes" do
|
77
|
-
module TeckelOperationInlineClassesTest
|
78
|
-
class CreateUser
|
79
|
-
include Teckel::Operation
|
80
|
-
|
81
|
-
class Input < Dry::Struct
|
82
|
-
attribute :name, Types::String
|
83
|
-
attribute :age, Types::Coercible::Integer
|
84
|
-
end
|
85
|
-
|
86
|
-
Output = Types.Instance(User)
|
87
|
-
|
88
|
-
class Error < Dry::Struct
|
89
|
-
attribute :message, Types::String
|
90
|
-
attribute :status_code, Types::Integer
|
91
|
-
attribute :meta, Types::Hash.optional
|
92
|
-
end
|
93
|
-
|
94
|
-
def call(input)
|
95
|
-
user = User.new(**input.attributes)
|
96
|
-
if user.save
|
97
|
-
user
|
98
|
-
else
|
99
|
-
fail!(
|
100
|
-
message: "Could not create User",
|
101
|
-
status_code: 400,
|
102
|
-
meta: { validation: user.errors }
|
103
|
-
)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
271
|
specify "Input" do
|
110
272
|
expect(TeckelOperationInlineClassesTest::CreateUser.input).to be <= Dry::Struct
|
111
273
|
end
|
@@ -138,25 +300,6 @@ RSpec.describe Teckel::Operation do
|
|
138
300
|
end
|
139
301
|
|
140
302
|
context "annon classes" do
|
141
|
-
module TeckelOperationAnnonClassesTest
|
142
|
-
class CreateUser
|
143
|
-
include ::Teckel::Operation
|
144
|
-
|
145
|
-
input Types::Hash.schema(name: Types::String, age: Types::Coercible::Integer)
|
146
|
-
output Types.Instance(User)
|
147
|
-
error Types::Hash.schema(message: Types::String, errors: Types::Array.of(Types::Hash))
|
148
|
-
|
149
|
-
def call(input)
|
150
|
-
user = User.new(name: input[:name], age: input[:age])
|
151
|
-
if user.save
|
152
|
-
user
|
153
|
-
else
|
154
|
-
fail!(message: "Could not save User", errors: user.errors)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
303
|
specify "output" do
|
161
304
|
expect(TeckelOperationAnnonClassesTest::CreateUser.call(name: "Bob", age: 23)).to be_a(User)
|
162
305
|
end
|
@@ -167,91 +310,18 @@ RSpec.describe Teckel::Operation do
|
|
167
310
|
end
|
168
311
|
|
169
312
|
context "keyword contracts" do
|
170
|
-
class CreateUserKeywordInit
|
171
|
-
include Teckel::Operation
|
172
|
-
|
173
|
-
class Input
|
174
|
-
def initialize(name:, age:)
|
175
|
-
@name, @age = name, age
|
176
|
-
end
|
177
|
-
attr_reader :name, :age
|
178
|
-
end
|
179
|
-
|
180
|
-
input_constructor ->(data) { input.new(**data) }
|
181
|
-
|
182
|
-
Output = ::User
|
183
|
-
|
184
|
-
class Error
|
185
|
-
def initialize(message, errors)
|
186
|
-
@message, @errors = message, errors
|
187
|
-
end
|
188
|
-
attr_reader :message, :errors
|
189
|
-
end
|
190
|
-
error_constructor :new
|
191
|
-
|
192
|
-
def call(input)
|
193
|
-
user = ::User.new(name: input.name, age: input.age)
|
194
|
-
if user.save
|
195
|
-
user
|
196
|
-
else
|
197
|
-
fail!(message: "Could not save User", errors: user.errors)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
313
|
specify do
|
203
|
-
expect(
|
314
|
+
expect(TeckelOperationKeywordContracts::MyOperation.call(name: "Bob", age: 23)).to be_a(User)
|
204
315
|
end
|
205
316
|
end
|
206
317
|
|
207
318
|
context "splat contracts" do
|
208
|
-
class CreateUserSplatInit
|
209
|
-
include Teckel::Operation
|
210
|
-
|
211
|
-
input Struct.new(:name, :age)
|
212
|
-
input_constructor ->(data) { input.new(*data) }
|
213
|
-
|
214
|
-
Output = ::User
|
215
|
-
|
216
|
-
class Error
|
217
|
-
def initialize(message, errors)
|
218
|
-
@message, @errors = message, errors
|
219
|
-
end
|
220
|
-
attr_reader :message, :errors
|
221
|
-
end
|
222
|
-
error_constructor :new
|
223
|
-
|
224
|
-
def call(input)
|
225
|
-
user = ::User.new(name: input.name, age: input.age)
|
226
|
-
if user.save
|
227
|
-
user
|
228
|
-
else
|
229
|
-
fail!(message: "Could not save User", errors: user.errors)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
319
|
specify do
|
235
|
-
expect(
|
320
|
+
expect(TeckelOperationCreateUserSplatInit::MyOperation.call(["Bob", 23])).to be_a(User)
|
236
321
|
end
|
237
322
|
end
|
238
323
|
|
239
324
|
context "generated output" do
|
240
|
-
module TeckelOperationGeneratedOutputTest
|
241
|
-
class MyOperation
|
242
|
-
include ::Teckel::Operation
|
243
|
-
|
244
|
-
input none
|
245
|
-
output Struct.new(:some_key)
|
246
|
-
output_constructor ->(data) { output.new(*data.values_at(*output.members)) } # ruby 2.4 way for `keyword_init: true`
|
247
|
-
error none
|
248
|
-
|
249
|
-
def call(_input)
|
250
|
-
{ some_key: "some_value" }
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
325
|
specify "result" do
|
256
326
|
result = TeckelOperationGeneratedOutputTest::MyOperation.call
|
257
327
|
expect(result).to be_a(Struct)
|
@@ -260,31 +330,13 @@ RSpec.describe Teckel::Operation do
|
|
260
330
|
end
|
261
331
|
|
262
332
|
context "inject settings" do
|
263
|
-
module TeckelOperationInjectSettingsTest
|
264
|
-
class MyOperation
|
265
|
-
include ::Teckel::Operation
|
266
|
-
|
267
|
-
settings Struct.new(:injected)
|
268
|
-
settings_constructor ->(data) { settings.new(*data.values_at(*settings.members)) }
|
269
|
-
|
270
|
-
input none
|
271
|
-
output Array
|
272
|
-
error none
|
273
|
-
|
274
|
-
def call(_input)
|
275
|
-
(settings&.injected || []) << :operation_data
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
333
|
it "settings in operation instances are nil by default" do
|
281
334
|
op = TeckelOperationInjectSettingsTest::MyOperation.new
|
282
335
|
expect(op.settings).to be_nil
|
283
336
|
end
|
284
337
|
|
285
338
|
it "uses injected data" do
|
286
|
-
result =
|
287
|
-
TeckelOperationInjectSettingsTest::MyOperation.
|
339
|
+
result = TeckelOperationInjectSettingsTest::MyOperation.
|
288
340
|
with(injected: [:stuff]).
|
289
341
|
call
|
290
342
|
|
@@ -294,28 +346,15 @@ RSpec.describe Teckel::Operation do
|
|
294
346
|
end
|
295
347
|
|
296
348
|
specify "calling `with` multiple times raises an error" do
|
297
|
-
op = TeckelOperationInjectSettingsTest::MyOperation.with(injected: :
|
349
|
+
op = TeckelOperationInjectSettingsTest::MyOperation.with(injected: :stuff1)
|
298
350
|
|
299
351
|
expect {
|
300
|
-
op.with(more: :
|
301
|
-
}.to raise_error(Teckel::Error)
|
352
|
+
op.with(more: :stuff2)
|
353
|
+
}.to raise_error(Teckel::Error, "Operation already has settings assigned.")
|
302
354
|
end
|
303
355
|
end
|
304
356
|
|
305
357
|
context "operation with no settings" do
|
306
|
-
module TeckelOperationNoSettingsTest
|
307
|
-
class MyOperation
|
308
|
-
include ::Teckel::Operation
|
309
|
-
|
310
|
-
input none
|
311
|
-
output none
|
312
|
-
error none
|
313
|
-
|
314
|
-
def call(_input); end
|
315
|
-
end
|
316
|
-
MyOperation.finalize!
|
317
|
-
end
|
318
|
-
|
319
358
|
it "uses None as default settings class" do
|
320
359
|
expect(TeckelOperationNoSettingsTest::MyOperation.settings).to eq(Teckel::Contracts::None)
|
321
360
|
expect(TeckelOperationNoSettingsTest::MyOperation.new.settings).to be_nil
|
@@ -329,37 +368,6 @@ RSpec.describe Teckel::Operation do
|
|
329
368
|
end
|
330
369
|
|
331
370
|
context "None in, out, err" do
|
332
|
-
module TeckelOperationNoneDataTest
|
333
|
-
class MyOperation
|
334
|
-
include ::Teckel::Operation
|
335
|
-
|
336
|
-
settings Struct.new(:fail_it, :fail_data, :success_it, :success_data)
|
337
|
-
settings_constructor ->(data) { settings.new(*data.values_at(*settings.members)) }
|
338
|
-
|
339
|
-
input none
|
340
|
-
output none
|
341
|
-
error none
|
342
|
-
|
343
|
-
def call(_input)
|
344
|
-
if settings&.fail_it
|
345
|
-
if settings&.fail_data
|
346
|
-
fail!(settings.fail_data)
|
347
|
-
else
|
348
|
-
fail!
|
349
|
-
end
|
350
|
-
elsif settings&.success_it
|
351
|
-
if settings&.success_data
|
352
|
-
success!(settings.success_data)
|
353
|
-
else
|
354
|
-
success!
|
355
|
-
end
|
356
|
-
else
|
357
|
-
settings&.success_data
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
371
|
let(:operation) { TeckelOperationNoneDataTest::MyOperation }
|
364
372
|
|
365
373
|
it "raises error when called with input data" do
|
@@ -386,23 +394,12 @@ RSpec.describe Teckel::Operation do
|
|
386
394
|
expect(operation.with(success_it: true).call).to be_nil
|
387
395
|
end
|
388
396
|
|
389
|
-
it "raises error when returning data" do
|
390
|
-
expect {
|
391
|
-
operation.with(success_it: false, success_data: "stuff").call
|
392
|
-
}.to raise_error(ArgumentError)
|
393
|
-
end
|
394
|
-
|
395
397
|
it "returns nil as success result when returning nil" do
|
396
398
|
expect(operation.call).to be_nil
|
397
399
|
end
|
398
400
|
end
|
399
401
|
|
400
402
|
describe "#finalize!" do
|
401
|
-
let(:frozen_error) do
|
402
|
-
# different ruby versions raise different errors
|
403
|
-
defined?(FrozenError) ? FrozenError : RuntimeError
|
404
|
-
end
|
405
|
-
|
406
403
|
subject do
|
407
404
|
Class.new do
|
408
405
|
include ::Teckel::Operation
|
@@ -482,4 +479,53 @@ RSpec.describe Teckel::Operation do
|
|
482
479
|
}.to raise_error Teckel::FrozenConfigError, "Configuration input is already set"
|
483
480
|
end
|
484
481
|
end
|
482
|
+
|
483
|
+
describe "frozen" do
|
484
|
+
subject do
|
485
|
+
Class.new do
|
486
|
+
include ::Teckel::Operation
|
487
|
+
|
488
|
+
input none
|
489
|
+
output none
|
490
|
+
error none
|
491
|
+
|
492
|
+
def call(_input); end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
it "also freezes the config" do
|
497
|
+
expect { subject.freeze }.to change {
|
498
|
+
[
|
499
|
+
subject.frozen?,
|
500
|
+
subject.instance_variable_get(:@config).frozen?
|
501
|
+
]
|
502
|
+
}.from([false, false]).to([true, true])
|
503
|
+
end
|
504
|
+
|
505
|
+
it "prevents changes to config" do
|
506
|
+
subject.freeze
|
507
|
+
expect { subject.settings Struct.new(:test) }.to raise_error(frozen_error)
|
508
|
+
end
|
509
|
+
|
510
|
+
describe '#clone' do
|
511
|
+
it 'clones the class' do
|
512
|
+
subject.freeze
|
513
|
+
klone = subject.clone
|
514
|
+
|
515
|
+
expect(klone).to be_frozen
|
516
|
+
expect(klone.object_id).not_to be_eql(subject.object_id)
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'cloned class uses the same, frozen config' do
|
520
|
+
subject.freeze
|
521
|
+
klone = subject.clone
|
522
|
+
|
523
|
+
orig_config = subject.instance_variable_get(:@config)
|
524
|
+
klone_config = klone.instance_variable_get(:@config)
|
525
|
+
|
526
|
+
expect(klone_config).to be_frozen
|
527
|
+
expect(klone_config.object_id).to be_eql(orig_config.object_id)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
end
|
485
531
|
end
|
@@ -37,7 +37,7 @@ RSpec.describe "Ruby 2.7 pattern matches for Result and Chain" do
|
|
37
37
|
|
38
38
|
def call(usr)
|
39
39
|
Logger.new(File::NULL).info("User #{usr.name} created")
|
40
|
-
usr
|
40
|
+
success! usr
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -56,7 +56,7 @@ RSpec.describe "Ruby 2.7 pattern matches for Result and Chain" do
|
|
56
56
|
if settings&.fail_befriend
|
57
57
|
fail!(message: "Did not find a friend.")
|
58
58
|
else
|
59
|
-
|
59
|
+
success!(user: user, friend: User.new(name: "A friend", age: 42))
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
data/spec/result_spec.rb
CHANGED
@@ -3,18 +3,20 @@
|
|
3
3
|
require 'support/dry_base'
|
4
4
|
require 'support/fake_models'
|
5
5
|
|
6
|
+
module TeckelResultTest
|
7
|
+
class MissingResultImplementation
|
8
|
+
include Teckel::Result
|
9
|
+
def initialize(value, success); end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
6
13
|
RSpec.describe Teckel::Result do
|
7
14
|
describe "missing initialize" do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
specify do
|
14
|
-
result = MissingResultImplementation["value", true]
|
15
|
-
expect { result.successful? }.to raise_error(NotImplementedError)
|
16
|
-
expect { result.failure? }.to raise_error(NotImplementedError)
|
17
|
-
expect { result.value }.to raise_error(NotImplementedError)
|
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`")
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,12 +3,22 @@
|
|
3
3
|
require "bundler/setup"
|
4
4
|
if ENV['COVERAGE'] == 'true'
|
5
5
|
require 'simplecov'
|
6
|
+
|
7
|
+
SimpleCov.formatter = case ENV['SIMPLECOV']&.downcase
|
8
|
+
when 'html'
|
9
|
+
SimpleCov::Formatter::HTMLFormatter
|
10
|
+
else
|
11
|
+
require 'simplecov_json_formatter'
|
12
|
+
SimpleCov::Formatter::JSONFormatter
|
13
|
+
end
|
14
|
+
|
6
15
|
SimpleCov.start do
|
7
16
|
add_filter %r{^/spec/}
|
8
17
|
end
|
9
18
|
end
|
10
19
|
|
11
20
|
require "teckel"
|
21
|
+
require "teckel/chain"
|
12
22
|
|
13
23
|
RSpec.configure do |config|
|
14
24
|
# Enable flags like --only-failures and --next-failure
|