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.
@@ -38,16 +38,16 @@ module Teckel
38
38
  include Teckel::Result
39
39
 
40
40
  # @param value [Object] The result value
41
- # @param success [Boolean] whether this is a successful result
42
- def initialize(value, success)
41
+ # @param successful [Boolean] whether this is a successful result
42
+ def initialize(value, successful)
43
43
  @value = value
44
- @success = (!!success).freeze
44
+ @successful = successful
45
45
  end
46
46
 
47
47
  # Whether this is a success result
48
48
  # @return [Boolean]
49
49
  def successful?
50
- @success
50
+ @successful
51
51
  end
52
52
 
53
53
  # @!attribute [r] value
@@ -59,8 +59,8 @@ module Teckel
59
59
  # @param default [Mixed] return this default value if it's not a failure result
60
60
  # @return [Mixed] the value/payload
61
61
  def failure(default = nil, &block)
62
- return @value unless @success
63
- return yield(@value) if block
62
+ return value unless @successful
63
+ return yield(value) if block
64
64
 
65
65
  default
66
66
  end
@@ -70,8 +70,8 @@ module Teckel
70
70
  # @param default [Mixed] return this default value if it's not a success result
71
71
  # @return [Mixed] the value/payload
72
72
  def success(default = nil, &block)
73
- return @value if @success
74
- return yield(@value) if block
73
+ return value if @successful
74
+ return yield(value) if block
75
75
 
76
76
  default
77
77
  end
@@ -16,54 +16,58 @@ module Teckel
16
16
  attr_reader :operation, :settings
17
17
 
18
18
  def call(input = nil)
19
- err = catch(:failure) do
20
- simple_return = UNDEFINED
21
- out = catch(:success) do
22
- simple_return = call!(build_input(input))
23
- end
24
- return simple_return == UNDEFINED ? build_output(*out) : build_output(simple_return)
19
+ catch(:halt) do
20
+ op = instance
21
+ op_input = op.instance_exec(input, &operation.input_constructor)
22
+ op.call(op_input)
23
+ nil # return values need to go through +success!+ or +fail!+
25
24
  end
26
- build_error(*err)
27
25
  end
28
26
 
29
- # This is just here to raise a meaningful error.
30
- # @!visibility private
31
- def with(*)
32
- raise Teckel::Error, "Operation already has settings assigned."
33
- end
27
+ def instance
28
+ return @instance if instance_variable_defined?(:@instance)
34
29
 
35
- private
30
+ op = operation.new
31
+ op.runner = self
32
+ op.settings = settings unless settings.eql?(UNDEFINED)
36
33
 
37
- def call!(input)
38
- op = @operation.new
39
- op.settings = settings if settings != UNDEFINED
40
- op.call(input)
34
+ @instance = op
41
35
  end
42
36
 
43
- def build_input(input)
44
- operation.input_constructor.call(input)
37
+ # This is just here to raise a meaningful error.
38
+ # @!visibility private
39
+ def with(*)
40
+ raise Error, "Operation already has settings assigned."
45
41
  end
46
42
 
47
- def build_output(*args)
43
+ # Halt any further execution with a output value
44
+ #
45
+ # @return a thing matching your {Teckel::Operation::Config#output output} definition
46
+ # @!visibility protected
47
+ def success!(*args)
48
48
  value =
49
- if args.size == 1 && operation.output === args.first # rubocop:disable Style/CaseEquality
49
+ if args.size.equal?(1) && operation.output === args.first # rubocop:disable Style/CaseEquality
50
50
  args.first
51
51
  else
52
52
  operation.output_constructor.call(*args)
53
53
  end
54
54
 
55
- operation.result_constructor.call(value, true)
55
+ throw :halt, instance.instance_exec(value, true, &operation.result_constructor)
56
56
  end
57
57
 
58
- def build_error(*args)
58
+ # Halt any further execution with an error value
59
+ #
60
+ # @return a thing matching your {Teckel::Operation::Config#error error} definition
61
+ # @!visibility protected
62
+ def fail!(*args)
59
63
  value =
60
- if args.size == 1 && operation.error === args.first # rubocop:disable Style/CaseEquality
64
+ if args.size.equal?(1) && operation.error === args.first # rubocop:disable Style/CaseEquality
61
65
  args.first
62
66
  else
63
67
  operation.error_constructor.call(*args)
64
68
  end
65
69
 
66
- operation.result_constructor.call(value, false)
70
+ throw :halt, instance.instance_exec(value, false, &operation.result_constructor)
67
71
  end
68
72
  end
69
73
  end
@@ -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 {.result!} and get {Teckel::Operation::Result}
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
- # Use {ClassMethods#input_constructor input_constructor},
21
- # {ClassMethods#output_constructor output_constructor} and
22
- # {ClassMethods#error_constructor error_constructor} to change them.
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,318 +58,28 @@ 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
61
+ # @!visibility private
62
+ UNDEFINED = Object.new
354
63
 
355
64
  # Invoke the Operation
356
65
  #
357
- # @param input Any form of input your {#input} class can handle via the given {#input_constructor}
358
- # @return Either An instance of your defined {#error} class or {#output} class
66
+ # @param input Any form of input your {Teckel::Operation::Config#input input} class can handle via the given
67
+ # {Teckel::Operation::Config#input_constructor input_constructor}
68
+ # @return Either An instance of your defined {Teckel::Operation::Config#error error} class or
69
+ # {Teckel::Operation::Config#output output} class
359
70
  # @!visibility public
360
71
  def call(input = nil)
361
- runner.new(self).call(input)
72
+ runable.call(input)
362
73
  end
363
74
 
364
- # Provide {InstanceMethods#settings() settings} to the running operation.
75
+ # Provide {InstanceMethods#settings() settings} to the operation.
365
76
  #
366
77
  # This method is intended to be called on the operation class outside of
367
- # it's definition, prior to running {#call}.
78
+ # it's definition, prior to invoking {#call}.
368
79
  #
369
- # @param input Any form of input your {#settings} class can handle via the given {#settings_constructor}
370
- # @return [Class] The configured {runner}
80
+ # @param settings Any form of settings your {Teckel::Operation::Config#settings settings} class can handle via the given
81
+ # {Teckel::Operation::Config#settings_constructor settings_constructor}
82
+ # @return [Class] The configured {Teckel::Operation::Config#runner runner}
371
83
  # @!visibility public
372
84
  #
373
85
  # @example Inject settings for an operation call
@@ -396,120 +108,107 @@ module Teckel
396
108
  # MyOperation.with(false).call
397
109
  # MyOperation.call
398
110
  # LOG #=> []
399
- def with(input)
400
- runner.new(self, settings_constructor.call(input))
111
+ def with(settings)
112
+ runable(settings_constructor.call(settings))
401
113
  end
402
114
  alias :set :with
403
115
 
404
- # @!visibility private
405
- # @return [void]
406
- def define!
407
- %i[
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.
420
- #
421
- # @raise [MissingConfigError]
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.
116
+ # Constructs a Runner instance for {call} and {with}.
431
117
  #
432
- # @return [self]
433
- # @!visibility public
434
- def dup
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
118
+ # @note This method is public to make testing, stubbing and mocking easier.
119
+ # Your normal application code should use {with} and/or {call}
441
120
  #
442
- # @return [self]
121
+ # @param settings Optional. Any form of settings your
122
+ # {Teckel::Operation::Config#settings settings} class can handle via the
123
+ # given {Teckel::Operation::Config#settings_constructor settings_constructor}
124
+ # @return [Class] The configured {Teckel::Operation::Config#runner runner}
443
125
  # @!visibility public
444
- def clone
445
- if frozen?
446
- super
126
+ def runable(settings = UNDEFINED)
127
+ if settings != UNDEFINED
128
+ runner.new(self, settings)
129
+ elsif default_settings
130
+ runner.new(self, default_settings.call)
447
131
  else
448
- super.tap do |copy|
449
- copy.instance_variable_set(:@config, @config.dup)
450
- end
132
+ runner.new(self)
451
133
  end
452
134
  end
453
135
 
454
- # @!visibility private
455
- def inherited(subclass)
456
- subclass.instance_variable_set(:@config, @config.dup)
457
- end
458
-
459
- # @!visibility private
460
- def self.extended(base)
461
- base.instance_exec do
462
- @config = Config.new
463
- attr_accessor :settings
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
136
+ # Convenience method for setting {Teckel::Operation::Config#input input},
137
+ # {Teckel::Operation::Config#output output} or
138
+ # {Teckel::Operation::Config#error error} to the
139
+ # {Teckel::Contracts::None} value.
140
+ #
141
+ # @return [Object] The {Teckel::Contracts::None} class.
142
+ #
143
+ # @example Enforcing nil input, output or error
144
+ # class MyOperation
145
+ # include Teckel::Operation
146
+ #
147
+ # input none
148
+ #
149
+ # # same as
150
+ # output Teckel::Contracts::None
151
+ #
152
+ # error none
153
+ #
154
+ # def call(_) # you still need to take than +nil+ input when using `input none`
155
+ # # when using `error none`:
156
+ # # `fail!` works, but `fail!("data")` raises an error
157
+ #
158
+ # # when using `output none`:
159
+ # # `success!` works, but `success!("data")` raises an error
160
+ # end
161
+ # end
162
+ #
163
+ # MyOperation.call #=> nil
164
+ def none
165
+ Contracts::None
483
166
  end
484
167
  end
485
168
 
486
169
  module InstanceMethods
170
+ # @!method call(input)
171
+ # @abstract
172
+ # @see Operation
173
+ # @see ClassMethods#call
174
+ #
175
+ # The entry point for your operation. It needs to always accept an input value, even when
176
+ # using +input none+.
177
+ # If your Operation expects to generate success or failure outputs, you need to use either
178
+ # {.success!} or {.fail!} respectively. Simple return values will get ignored by default. See
179
+ # {Teckel::Operation::Config#runner} and {Teckel::Operation::Runner} on how to overwrite.
180
+
487
181
  # @!attribute [r] settings()
488
182
  # @return [Class,nil] When executed with settings, an instance of the
489
183
  # configured {.settings} class. Otherwise +nil+
490
184
  # @see ClassMethods#settings
491
185
  # @!visibility public
492
186
 
493
- # Halt any further execution with a output value
187
+ # Delegates to the configured Runner.
188
+ # The default behavior is to halt any further execution with a output value.
494
189
  #
495
- # @return a thing matching your {Operation::ClassMethods#output Operation#output} definition
190
+ # @see Teckel::Operation::Runner#success!
496
191
  # @!visibility protected
497
192
  def success!(*args)
498
- throw :success, args
193
+ runner.success!(*args)
499
194
  end
500
195
 
501
- # Halt any further execution with an error value
196
+ # Delegates to the configured Runner.
197
+ # The default behavior is to halt any further execution with an error value.
502
198
  #
503
- # @return a thing matching your {Operation::ClassMethods#error Operation#error} definition
199
+ # @see Teckel::Operation::Runner#fail!
504
200
  # @!visibility protected
505
201
  def fail!(*args)
506
- throw :failure, args
202
+ runner.fail!(*args)
507
203
  end
508
204
  end
509
205
 
510
206
  def self.included(receiver)
511
- receiver.extend ClassMethods
512
- receiver.send :include, InstanceMethods
207
+ receiver.class_eval do
208
+ extend Config
209
+ extend ClassMethods
210
+ include InstanceMethods
211
+ end
513
212
  end
514
213
  end
515
214
  end