teckel 0.4.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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