teckel 0.4.0 → 0.5.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 +36 -0
- data/lib/teckel/chain.rb +11 -189
- data/lib/teckel/chain/config.rb +246 -0
- data/lib/teckel/chain/result.rb +3 -3
- data/lib/teckel/chain/runner.rb +28 -17
- data/lib/teckel/config.rb +11 -5
- data/lib/teckel/operation.rb +53 -383
- data/lib/teckel/operation/config.rb +394 -0
- data/lib/teckel/operation/runner.rb +2 -2
- data/lib/teckel/result.rb +4 -4
- data/lib/teckel/version.rb +1 -1
- data/spec/chain/default_settings_spec.rb +39 -0
- data/spec/chain/none_input_spec.rb +36 -0
- data/spec/operation/default_settings_spec.rb +94 -0
- metadata +11 -3
data/lib/teckel/chain/result.rb
CHANGED
data/lib/teckel/chain/runner.rb
CHANGED
@@ -9,6 +9,9 @@ module Teckel
|
|
9
9
|
# @!visibility private
|
10
10
|
UNDEFINED = Object.new
|
11
11
|
|
12
|
+
# @!visibility private
|
13
|
+
StepResult = Struct.new(:value, :success, :step)
|
14
|
+
|
12
15
|
def initialize(chain, settings = UNDEFINED)
|
13
16
|
@chain, @settings = chain, settings
|
14
17
|
end
|
@@ -20,29 +23,37 @@ module Teckel
|
|
20
23
|
#
|
21
24
|
# @return [Teckel::Chain::Result] The result object wrapping
|
22
25
|
# either the success or failure value.
|
23
|
-
def call(input)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
def call(input = nil)
|
27
|
+
step_result = run(input)
|
28
|
+
chain.result_constructor.call(*step_result)
|
29
|
+
end
|
30
|
+
|
31
|
+
def steps
|
32
|
+
settings == UNDEFINED ? chain.steps : steps_with_settings
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def run(input)
|
38
|
+
steps.each_with_object(StepResult.new(input)) do |step, step_result|
|
39
|
+
result = step.operation.call(step_result.value)
|
29
40
|
|
30
|
-
|
41
|
+
step_result.step = step
|
42
|
+
step_result.value = result.value
|
43
|
+
step_result.success = result.successful?
|
31
44
|
|
32
|
-
break if
|
45
|
+
break step_result if result.failure?
|
33
46
|
end
|
47
|
+
end
|
34
48
|
|
35
|
-
|
49
|
+
def step_with_settings(step)
|
50
|
+
settings.key?(step.name) ? step.with(settings[step.name]) : step
|
36
51
|
end
|
37
52
|
|
38
|
-
def
|
39
|
-
|
40
|
-
chain.steps
|
41
|
-
|
42
|
-
Enumerator.new do |yielder|
|
43
|
-
chain.steps.each do |step|
|
44
|
-
yielder << (settings.key?(step.name) ? step.with(settings[step.name]) : step)
|
45
|
-
end
|
53
|
+
def steps_with_settings
|
54
|
+
Enumerator.new do |yielder|
|
55
|
+
chain.steps.each do |step|
|
56
|
+
yielder << step_with_settings(step)
|
46
57
|
end
|
47
58
|
end
|
48
59
|
end
|
data/lib/teckel/config.rb
CHANGED
@@ -19,11 +19,7 @@ module Teckel
|
|
19
19
|
# @!visibility private
|
20
20
|
def for(key, value = nil, &block)
|
21
21
|
if value.nil?
|
22
|
-
|
23
|
-
@config[key] ||= @config.fetch(key, &block)
|
24
|
-
else
|
25
|
-
@config[key]
|
26
|
-
end
|
22
|
+
get_or_set(key, &block)
|
27
23
|
elsif @config.key?(key)
|
28
24
|
raise FrozenConfigError, "Configuration #{key} is already set"
|
29
25
|
else
|
@@ -48,5 +44,15 @@ module Teckel
|
|
48
44
|
copy.instance_variable_set(:@config, @config.dup)
|
49
45
|
end
|
50
46
|
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def get_or_set(key, &block)
|
51
|
+
if block
|
52
|
+
@config[key] ||= @config.fetch(key, &block)
|
53
|
+
else
|
54
|
+
@config[key]
|
55
|
+
end
|
56
|
+
end
|
51
57
|
end
|
52
58
|
end
|
data/lib/teckel/operation.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "operation/config"
|
3
4
|
require_relative "operation/result"
|
4
5
|
require_relative "operation/runner"
|
5
6
|
|
@@ -13,13 +14,14 @@ module Teckel
|
|
13
14
|
# +input+. +output+ and +error+ methods to point them to anonymous classes.
|
14
15
|
#
|
15
16
|
# If you like "traditional" result objects to ask +successful?+ or +failure?+ on,
|
16
|
-
# use {
|
17
|
+
# use {Teckel::Operation::Config#result! result!} and get {Teckel::Operation::Result}
|
17
18
|
#
|
18
19
|
# By default, +input+. +output+ and +error+ classes are build using +:[]+
|
19
20
|
# (eg: +Input[some: :param]+).
|
20
|
-
#
|
21
|
-
# {
|
22
|
-
# {
|
21
|
+
#
|
22
|
+
# Use {Teckel::Operation::Config#input_constructor input_constructor},
|
23
|
+
# {Teckel::Operation::Config#output_constructor output_constructor} and
|
24
|
+
# {Teckel::Operation::Config#error_constructor error_constructor} to change them.
|
23
25
|
#
|
24
26
|
# @example class definitions via methods
|
25
27
|
# class CreateUserViaMethods
|
@@ -56,309 +58,21 @@ module Teckel
|
|
56
58
|
# @!visibility public
|
57
59
|
module Operation
|
58
60
|
module ClassMethods
|
59
|
-
# @!group Contacts definition
|
60
|
-
|
61
|
-
# @overload input()
|
62
|
-
# Get the configured class wrapping the input data structure.
|
63
|
-
# @return [Class] The +input+ class
|
64
|
-
# @overload input(klass)
|
65
|
-
# Set the class wrapping the input data structure.
|
66
|
-
# @param klass [Class] The +input+ class
|
67
|
-
# @return [Class] The +input+ class
|
68
|
-
def input(klass = nil)
|
69
|
-
@config.for(:input, klass) { self::Input if const_defined?(:Input) } ||
|
70
|
-
raise(Teckel::MissingConfigError, "Missing input config for #{self}")
|
71
|
-
end
|
72
|
-
|
73
|
-
# @overload input_constructor()
|
74
|
-
# The callable constructor to build an instance of the +input+ class.
|
75
|
-
# Defaults to {Teckel::DEFAULT_CONSTRUCTOR}
|
76
|
-
# @return [Proc] A callable that will return an instance of the +input+ class.
|
77
|
-
#
|
78
|
-
# @overload input_constructor(sym_or_proc)
|
79
|
-
# Define how to build the +input+.
|
80
|
-
# @param sym_or_proc [Symbol, #call]
|
81
|
-
# - Either a +Symbol+ representing the _public_ method to call on the +input+ class.
|
82
|
-
# - Or anything that response to +#call+ (like a +Proc+).
|
83
|
-
# @return [#call] The callable constructor
|
84
|
-
#
|
85
|
-
# @example simple symbol to method constructor
|
86
|
-
# class MyOperation
|
87
|
-
# include Teckel::Operation
|
88
|
-
#
|
89
|
-
# class Input
|
90
|
-
# def initialize(name:, age:); end
|
91
|
-
# end
|
92
|
-
#
|
93
|
-
# # If you need more control over how to build a new +Input+ instance
|
94
|
-
# # MyOperation.call(name: "Bob", age: 23) # -> Input.new(name: "Bob", age: 23)
|
95
|
-
# input_constructor :new
|
96
|
-
# end
|
97
|
-
#
|
98
|
-
# MyOperation.input_constructor.is_a?(Method) #=> true
|
99
|
-
#
|
100
|
-
# @example Custom Proc constructor
|
101
|
-
# class MyOperation
|
102
|
-
# include Teckel::Operation
|
103
|
-
#
|
104
|
-
# class Input
|
105
|
-
# def initialize(*args, **opts); end
|
106
|
-
# end
|
107
|
-
#
|
108
|
-
# # If you need more control over how to build a new +Input+ instance
|
109
|
-
# # MyOperation.call("foo", opt: "bar") # -> Input.new(name: "foo", opt: "bar")
|
110
|
-
# input_constructor ->(name, options) { Input.new(name: name, **options) }
|
111
|
-
# end
|
112
|
-
#
|
113
|
-
# MyOperation.input_constructor.is_a?(Proc) #=> true
|
114
|
-
def input_constructor(sym_or_proc = nil)
|
115
|
-
get_set_counstructor(:input_constructor, input, sym_or_proc) ||
|
116
|
-
raise(MissingConfigError, "Missing input_constructor config for #{self}")
|
117
|
-
end
|
118
|
-
|
119
|
-
# @overload output()
|
120
|
-
# Get the configured class wrapping the output data structure.
|
121
|
-
# Defaults to {Teckel::DEFAULT_CONSTRUCTOR}
|
122
|
-
# @return [Class] The +output+ class
|
123
|
-
#
|
124
|
-
# @overload output(klass)
|
125
|
-
# Set the class wrapping the output data structure.
|
126
|
-
# @param klass [Class] The +output+ class
|
127
|
-
# @return [Class] The +output+ class
|
128
|
-
def output(klass = nil)
|
129
|
-
@config.for(:output, klass) { self::Output if const_defined?(:Output) } ||
|
130
|
-
raise(Teckel::MissingConfigError, "Missing output config for #{self}")
|
131
|
-
end
|
132
|
-
|
133
|
-
# @overload output_constructor()
|
134
|
-
# The callable constructor to build an instance of the +output+ class.
|
135
|
-
# Defaults to {Teckel::DEFAULT_CONSTRUCTOR}
|
136
|
-
# @return [Proc] A callable that will return an instance of +output+ class.
|
137
|
-
#
|
138
|
-
# @overload output_constructor(sym_or_proc)
|
139
|
-
# Define how to build the +output+.
|
140
|
-
# @param sym_or_proc [Symbol, #call]
|
141
|
-
# - Either a +Symbol+ representing the _public_ method to call on the +output+ class.
|
142
|
-
# - Or anything that response to +#call+ (like a +Proc+).
|
143
|
-
# @return [#call] The callable constructor
|
144
|
-
#
|
145
|
-
# @example
|
146
|
-
# class MyOperation
|
147
|
-
# include Teckel::Operation
|
148
|
-
#
|
149
|
-
# class Output
|
150
|
-
# def initialize(*args, **opts); end
|
151
|
-
# end
|
152
|
-
#
|
153
|
-
# # MyOperation.call("foo", "bar") # -> Output.new("foo", "bar")
|
154
|
-
# output_constructor :new
|
155
|
-
#
|
156
|
-
# # If you need more control over how to build a new +Output+ instance
|
157
|
-
# # MyOperation.call("foo", opt: "bar") # -> Output.new(name: "foo", opt: "bar")
|
158
|
-
# output_constructor ->(name, options) { Output.new(name: name, **options) }
|
159
|
-
# end
|
160
|
-
def output_constructor(sym_or_proc = nil)
|
161
|
-
get_set_counstructor(:output_constructor, output, sym_or_proc) ||
|
162
|
-
raise(MissingConfigError, "Missing output_constructor config for #{self}")
|
163
|
-
end
|
164
|
-
|
165
|
-
# @overload error()
|
166
|
-
# Get the configured class wrapping the error data structure.
|
167
|
-
# @return [Class] The +error+ class
|
168
|
-
#
|
169
|
-
# @overload error(klass)
|
170
|
-
# Set the class wrapping the error data structure.
|
171
|
-
# @param klass [Class] The +error+ class
|
172
|
-
# @return [Class,nil] The +error+ class or +nil+ if it does not error
|
173
|
-
def error(klass = nil)
|
174
|
-
@config.for(:error, klass) { self::Error if const_defined?(:Error) } ||
|
175
|
-
raise(Teckel::MissingConfigError, "Missing error config for #{self}")
|
176
|
-
end
|
177
|
-
|
178
|
-
# @overload error_constructor()
|
179
|
-
# The callable constructor to build an instance of the +error+ class.
|
180
|
-
# Defaults to {Teckel::DEFAULT_CONSTRUCTOR}
|
181
|
-
# @return [Proc] A callable that will return an instance of +error+ class.
|
182
|
-
#
|
183
|
-
# @overload error_constructor(sym_or_proc)
|
184
|
-
# Define how to build the +error+.
|
185
|
-
# @param sym_or_proc [Symbol, #call]
|
186
|
-
# - Either a +Symbol+ representing the _public_ method to call on the +error+ class.
|
187
|
-
# - Or anything that response to +#call+ (like a +Proc+).
|
188
|
-
# @return [#call] The callable constructor
|
189
|
-
#
|
190
|
-
# @example
|
191
|
-
# class MyOperation
|
192
|
-
# include Teckel::Operation
|
193
|
-
#
|
194
|
-
# class Error
|
195
|
-
# def initialize(*args, **opts); end
|
196
|
-
# end
|
197
|
-
#
|
198
|
-
# # MyOperation.call("foo", "bar") # -> Error.new("foo", "bar")
|
199
|
-
# error_constructor :new
|
200
|
-
#
|
201
|
-
# # If you need more control over how to build a new +Error+ instance
|
202
|
-
# # MyOperation.call("foo", opt: "bar") # -> Error.new(name: "foo", opt: "bar")
|
203
|
-
# error_constructor ->(name, options) { Error.new(name: name, **options) }
|
204
|
-
# end
|
205
|
-
def error_constructor(sym_or_proc = nil)
|
206
|
-
get_set_counstructor(:error_constructor, error, sym_or_proc) ||
|
207
|
-
raise(MissingConfigError, "Missing error_constructor config for #{self}")
|
208
|
-
end
|
209
|
-
|
210
|
-
# @!endgroup
|
211
|
-
|
212
|
-
# @overload settings()
|
213
|
-
# Get the configured class wrapping the settings data structure.
|
214
|
-
# @return [Class] The +settings+ class, or {Teckel::Contracts::None} as default
|
215
|
-
#
|
216
|
-
# @overload settings(klass)
|
217
|
-
# Set the class wrapping the settings data structure.
|
218
|
-
# @param klass [Class] The +settings+ class
|
219
|
-
# @return [Class] The +settings+ class configured
|
220
|
-
def settings(klass = nil)
|
221
|
-
@config.for(:settings, klass) { const_defined?(:Settings) ? self::Settings : none }
|
222
|
-
end
|
223
|
-
|
224
|
-
# @overload settings_constructor()
|
225
|
-
# The callable constructor to build an instance of the +settings+ class.
|
226
|
-
# Defaults to {Teckel::DEFAULT_CONSTRUCTOR}
|
227
|
-
# @return [Proc] A callable that will return an instance of +settings+ class.
|
228
|
-
#
|
229
|
-
# @overload settings_constructor(sym_or_proc)
|
230
|
-
# Define how to build the +settings+.
|
231
|
-
# @param sym_or_proc [Symbol, #call]
|
232
|
-
# - Either a +Symbol+ representing the _public_ method to call on the +settings+ class.
|
233
|
-
# - Or anything that response to +#call+ (like a +Proc+).
|
234
|
-
# @return [#call] The callable constructor
|
235
|
-
#
|
236
|
-
# @example
|
237
|
-
# class MyOperation
|
238
|
-
# include Teckel::Operation
|
239
|
-
#
|
240
|
-
# class Settings
|
241
|
-
# def initialize(*args); end
|
242
|
-
# end
|
243
|
-
#
|
244
|
-
# # MyOperation.with("foo", "bar") # -> Settings.new("foo", "bar")
|
245
|
-
# settings_constructor :new
|
246
|
-
# end
|
247
|
-
def settings_constructor(sym_or_proc = nil)
|
248
|
-
get_set_counstructor(:settings_constructor, settings, sym_or_proc) ||
|
249
|
-
raise(MissingConfigError, "Missing settings_constructor config for #{self}")
|
250
|
-
end
|
251
|
-
|
252
|
-
# @overload runner()
|
253
|
-
# @return [Class] The Runner class
|
254
|
-
# @!visibility protected
|
255
|
-
#
|
256
|
-
# @overload runner(klass)
|
257
|
-
# Overwrite the default runner
|
258
|
-
# @param klass [Class] A class like the {Runner}
|
259
|
-
# @!visibility protected
|
260
|
-
def runner(klass = nil)
|
261
|
-
@config.for(:runner, klass) { Teckel::Operation::Runner }
|
262
|
-
end
|
263
|
-
|
264
|
-
# @overload result()
|
265
|
-
# Get the configured result object class wrapping {error} or {output}.
|
266
|
-
# The {ValueResult} default will act as a pass-through and does. Any error
|
267
|
-
# or output will just returned as-is.
|
268
|
-
# @return [Class] The +result+ class, or {ValueResult} as default
|
269
|
-
#
|
270
|
-
# @overload result(klass)
|
271
|
-
# Set the result object class wrapping {error} or {output}.
|
272
|
-
# @param klass [Class] The +result+ class
|
273
|
-
# @return [Class] The +result+ class configured
|
274
|
-
def result(klass = nil)
|
275
|
-
@config.for(:result, klass) { const_defined?(:Result, false) ? self::Result : ValueResult }
|
276
|
-
end
|
277
|
-
|
278
|
-
# @overload result_constructor()
|
279
|
-
# The callable constructor to build an instance of the +result+ class.
|
280
|
-
# Defaults to {Teckel::DEFAULT_CONSTRUCTOR}
|
281
|
-
# @return [Proc] A callable that will return an instance of +result+ class.
|
282
|
-
#
|
283
|
-
# @overload result_constructor(sym_or_proc)
|
284
|
-
# Define how to build the +result+.
|
285
|
-
# @param sym_or_proc [Symbol, #call]
|
286
|
-
# - Either a +Symbol+ representing the _public_ method to call on the +result+ class.
|
287
|
-
# - Or anything that response to +#call+ (like a +Proc+).
|
288
|
-
# @return [#call] The callable constructor
|
289
|
-
#
|
290
|
-
# @example
|
291
|
-
# class MyOperation
|
292
|
-
# include Teckel::Operation
|
293
|
-
#
|
294
|
-
# class Result
|
295
|
-
# include Teckel::Result
|
296
|
-
# def initialize(value, success, opts = {}); end
|
297
|
-
# end
|
298
|
-
#
|
299
|
-
# # If you need more control over how to build a new +Settings+ instance
|
300
|
-
# result_constructor ->(value, success) { result.new(value, success, {foo: :bar}) }
|
301
|
-
# end
|
302
|
-
def result_constructor(sym_or_proc = nil)
|
303
|
-
get_set_counstructor(:result_constructor, result, sym_or_proc) ||
|
304
|
-
raise(MissingConfigError, "Missing result_constructor config for #{self}")
|
305
|
-
end
|
306
|
-
|
307
|
-
# @!group Shortcuts
|
308
|
-
|
309
|
-
# Shortcut to use {Teckel::Operation::Result} as a result object,
|
310
|
-
# wrapping any {error} or {output}.
|
311
|
-
#
|
312
|
-
# @!visibility protected
|
313
|
-
# @note Don't use in conjunction with {result} or {result_constructor}
|
314
|
-
# @return [nil]
|
315
|
-
def result!
|
316
|
-
@config.for(:result, Teckel::Operation::Result)
|
317
|
-
@config.for(:result_constructor, Teckel::Operation::Result.method(:new))
|
318
|
-
nil
|
319
|
-
end
|
320
|
-
|
321
|
-
# Convenience method for setting {#input}, {#output} or {#error} to the
|
322
|
-
# {Teckel::Contracts::None} value.
|
323
|
-
# @return [Object] The {Teckel::Contracts::None} class.
|
324
|
-
#
|
325
|
-
# @example Enforcing nil input, output or error
|
326
|
-
# class MyOperation
|
327
|
-
# include Teckel::Operation
|
328
|
-
#
|
329
|
-
# input none
|
330
|
-
#
|
331
|
-
# # same as
|
332
|
-
# output Teckel::Contracts::None
|
333
|
-
#
|
334
|
-
# error none
|
335
|
-
#
|
336
|
-
# def call(_) # you still need to take than +nil+ input when using `input none`
|
337
|
-
# # when using `error none`:
|
338
|
-
# # `fail!` works, but `fail!("data")` raises an error
|
339
|
-
#
|
340
|
-
# # when using `output none`:
|
341
|
-
# # `success!` works, but `success!("data")` raises an error
|
342
|
-
# # same thing when using simple return values as success:
|
343
|
-
# # take care to not return anything
|
344
|
-
# nil
|
345
|
-
# end
|
346
|
-
# end
|
347
|
-
#
|
348
|
-
# MyOperation.call #=> nil
|
349
|
-
def none
|
350
|
-
Teckel::Contracts::None
|
351
|
-
end
|
352
|
-
|
353
|
-
# @endgroup
|
354
|
-
|
355
61
|
# Invoke the Operation
|
356
62
|
#
|
357
|
-
# @param input Any form of input your {#input} class can handle via the given
|
358
|
-
#
|
63
|
+
# @param input Any form of input your {Teckel::Operation::Config#input input} class can handle via the given
|
64
|
+
# {Teckel::Operation::Config#input_constructor input_constructor}
|
65
|
+
# @return Either An instance of your defined {Teckel::Operation::Config#error error} class or
|
66
|
+
# {Teckel::Operation::Config#output output} class
|
359
67
|
# @!visibility public
|
360
68
|
def call(input = nil)
|
361
|
-
|
69
|
+
default_settings = self.default_settings
|
70
|
+
|
71
|
+
if default_settings
|
72
|
+
runner.new(self, default_settings.call)
|
73
|
+
else
|
74
|
+
runner.new(self)
|
75
|
+
end.call(input)
|
362
76
|
end
|
363
77
|
|
364
78
|
# Provide {InstanceMethods#settings() settings} to the running operation.
|
@@ -366,8 +80,9 @@ module Teckel
|
|
366
80
|
# This method is intended to be called on the operation class outside of
|
367
81
|
# it's definition, prior to running {#call}.
|
368
82
|
#
|
369
|
-
# @param input Any form of input your {#settings} class can handle via the given
|
370
|
-
#
|
83
|
+
# @param input Any form of input your {Teckel::Operation::Config#settings settings} class can handle via the given
|
84
|
+
# {Teckel::Operation::Config#settings_constructor settings_constructor}
|
85
|
+
# @return [Class] The configured {Teckel::Operation::Config#runner runner}
|
371
86
|
# @!visibility public
|
372
87
|
#
|
373
88
|
# @example Inject settings for an operation call
|
@@ -401,85 +116,39 @@ module Teckel
|
|
401
116
|
end
|
402
117
|
alias :set :with
|
403
118
|
|
404
|
-
#
|
405
|
-
#
|
406
|
-
|
407
|
-
|
408
|
-
input input_constructor
|
409
|
-
output output_constructor
|
410
|
-
error error_constructor
|
411
|
-
settings settings_constructor
|
412
|
-
result result_constructor
|
413
|
-
runner
|
414
|
-
].each { |e| public_send(e) }
|
415
|
-
nil
|
416
|
-
end
|
417
|
-
|
418
|
-
# Disallow any further changes to this Operation.
|
419
|
-
# Make sure all configurations are set.
|
119
|
+
# Convenience method for setting {Teckel::Operation::Config#input input},
|
120
|
+
# {Teckel::Operation::Config#output output} or
|
121
|
+
# {Teckel::Operation::Config#error error} to the
|
122
|
+
# {Teckel::Contracts::None} value.
|
420
123
|
#
|
421
|
-
# @
|
422
|
-
# @return [self] Frozen self
|
423
|
-
# @!visibility public
|
424
|
-
def finalize!
|
425
|
-
define!
|
426
|
-
@config.freeze
|
427
|
-
self
|
428
|
-
end
|
429
|
-
|
430
|
-
# Produces a shallow copy of this operation and all it's configuration.
|
124
|
+
# @return [Object] The {Teckel::Contracts::None} class.
|
431
125
|
#
|
432
|
-
# @
|
433
|
-
#
|
434
|
-
|
435
|
-
super.tap do |copy|
|
436
|
-
copy.instance_variable_set(:@config, @config.dup)
|
437
|
-
end
|
438
|
-
end
|
439
|
-
|
440
|
-
# Produces a clone of this operation and all it's configuration
|
126
|
+
# @example Enforcing nil input, output or error
|
127
|
+
# class MyOperation
|
128
|
+
# include Teckel::Operation
|
441
129
|
#
|
442
|
-
#
|
443
|
-
#
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
#
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
#
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
private
|
468
|
-
|
469
|
-
def get_set_counstructor(name, on, sym_or_proc)
|
470
|
-
constructor = build_counstructor(on, sym_or_proc) unless sym_or_proc.nil?
|
471
|
-
|
472
|
-
@config.for(name, constructor) {
|
473
|
-
build_counstructor(on, Teckel::DEFAULT_CONSTRUCTOR)
|
474
|
-
}
|
475
|
-
end
|
476
|
-
|
477
|
-
def build_counstructor(on, sym_or_proc)
|
478
|
-
if sym_or_proc.is_a?(Symbol) && on.respond_to?(sym_or_proc)
|
479
|
-
on.public_method(sym_or_proc)
|
480
|
-
elsif sym_or_proc.respond_to?(:call)
|
481
|
-
sym_or_proc
|
482
|
-
end
|
130
|
+
# input none
|
131
|
+
#
|
132
|
+
# # same as
|
133
|
+
# output Teckel::Contracts::None
|
134
|
+
#
|
135
|
+
# error none
|
136
|
+
#
|
137
|
+
# def call(_) # you still need to take than +nil+ input when using `input none`
|
138
|
+
# # when using `error none`:
|
139
|
+
# # `fail!` works, but `fail!("data")` raises an error
|
140
|
+
#
|
141
|
+
# # when using `output none`:
|
142
|
+
# # `success!` works, but `success!("data")` raises an error
|
143
|
+
# # same thing when using simple return values as success:
|
144
|
+
# # take care to not return anything
|
145
|
+
# nil
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# MyOperation.call #=> nil
|
150
|
+
def none
|
151
|
+
Teckel::Contracts::None
|
483
152
|
end
|
484
153
|
end
|
485
154
|
|
@@ -492,7 +161,7 @@ module Teckel
|
|
492
161
|
|
493
162
|
# Halt any further execution with a output value
|
494
163
|
#
|
495
|
-
# @return a thing matching your {Operation::
|
164
|
+
# @return a thing matching your {Teckel::Operation::Config#output output} definition
|
496
165
|
# @!visibility protected
|
497
166
|
def success!(*args)
|
498
167
|
throw :success, args
|
@@ -500,7 +169,7 @@ module Teckel
|
|
500
169
|
|
501
170
|
# Halt any further execution with an error value
|
502
171
|
#
|
503
|
-
# @return a thing matching your {Operation::
|
172
|
+
# @return a thing matching your {Teckel::Operation::Config#error error} definition
|
504
173
|
# @!visibility protected
|
505
174
|
def fail!(*args)
|
506
175
|
throw :failure, args
|
@@ -508,6 +177,7 @@ module Teckel
|
|
508
177
|
end
|
509
178
|
|
510
179
|
def self.included(receiver)
|
180
|
+
receiver.extend Config
|
511
181
|
receiver.extend ClassMethods
|
512
182
|
receiver.send :include, InstanceMethods
|
513
183
|
end
|