cuprum 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,36 +4,12 @@ module Cuprum
4
4
  autoload :Command, 'cuprum/command'
5
5
  autoload :Operation, 'cuprum/operation'
6
6
  autoload :Result, 'cuprum/result'
7
-
8
- DEFAULT_WARNING_PROC = ->(message) { Kernel.warn message }
9
- private_constant :DEFAULT_WARNING_PROC
7
+ autoload :Steps, 'cuprum/steps'
10
8
 
11
9
  class << self
12
- # @return [Proc] The proc called to display a warning message. By default,
13
- # delegates to Kernel#warn. Set this to configure the warning behavior
14
- # (e.g. to call a Logger).
15
- attr_writer :warning_proc
16
-
17
10
  # @return [String] The current version of the gem.
18
11
  def version
19
12
  VERSION
20
13
  end # method version
21
-
22
- # Displays a warning message. By default, delegates to Kernel#warn. The
23
- # warning behavior can be configured (e.g. to call a Logger) using the
24
- # #warning_proc= method.
25
- #
26
- # @param message [String] The warning message to display.
27
- #
28
- # @see #warning_proc=
29
- def warn message
30
- warning_proc.call(message)
31
- end # method warn
32
-
33
- private
34
-
35
- def warning_proc
36
- @warning_proc ||= DEFAULT_WARNING_PROC
37
- end # method warning_proc
38
14
  end # eigenclass
39
15
  end # module
@@ -12,15 +12,15 @@ module Cuprum::BuiltIn
12
12
  # #=> true
13
13
  #
14
14
  # @example With a result.
15
- # errors = ['errors.messages.unknown']
16
- # value = Cuprum::Result.new('result value', :errors => errors)
15
+ # error = 'errors.messages.unknown'
16
+ # value = Cuprum::Result.new(value: 'result value', error: error)
17
17
  # result = IdentityCommand.new.call(value)
18
18
  # result.value
19
19
  # #=> 'result value'
20
20
  # result.success?
21
21
  # #=> false
22
- # result.errors
23
- # #=> ['errors.messages.unknown']
22
+ # result.error
23
+ # #=> 'errors.messages.unknown'
24
24
  class IdentityCommand < Cuprum::Command
25
25
  private
26
26
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cuprum'
2
4
 
3
5
  module Cuprum
@@ -25,8 +27,8 @@ module Cuprum
25
27
  # chain(UrlSafeCommand.new).
26
28
  # chain(PrependDateCommand.new(post.created_at)).
27
29
  # call(post.title)
28
- # end # method process
29
- # end # class
30
+ # end
31
+ # end
30
32
  #
31
33
  # title = 'Greetings, programs!'
32
34
  # date = '1982-07-09'
@@ -53,50 +55,76 @@ module Cuprum
53
55
  #
54
56
  # private
55
57
  #
58
+ # def create_tag
59
+ # Command.new do |tag_name|
60
+ # tag = Tag.new(name: tag_name)
61
+ #
62
+ # return tag if tag.save
63
+ #
64
+ # Cuprum::Result.new(error: tag.errors)
65
+ # end
66
+ # end
67
+ #
68
+ # def create_tagging(taggable)
69
+ # Command.new do |tag|
70
+ # tagging = tag.build_tagging(taggable)
71
+ #
72
+ # return tagging if tagging.save
73
+ #
74
+ # Cuprum::Result.new(error: tagging.errors)
75
+ # end
76
+ # end
77
+ #
78
+ # def find_tag
79
+ # Command.new do |tag_name|
80
+ # tag = Tag.where(name: tag_name).first
81
+ #
82
+ # tag || Cuprum::Result.new(error: 'tag not found')
83
+ # end
84
+ # end
85
+ #
56
86
  # # Tries to find the tag with the given name. If that fails, creates a
57
87
  # # new tag with the given name. If the tag is found, or if the new tag is
58
88
  # # successfully created, then creates a tagging using the tag. If the tag
59
89
  # # is not found and cannot be created, then the tagging is not created
60
90
  # # and the result of the CreateTaggingCommand is a failure with the
61
91
  # # appropriate error messages.
62
- # def process taggable, tag_name
63
- # FindTag.new.call(tag_name).
64
- # # The chained command is called with the value of the previous
65
- # # command, in this case the Tag or nil returned by FindTag.
66
- # chain(:on => :failure) do |tag|
67
- # # Chained commands share a result object, including errors. To
68
- # # rescue a command chain and return the execution to the "happy
69
- # # path", use on: :failure and clear the errors.
70
- # result.errors.clear
71
- #
72
- # Tag.create(tag_name)
73
- # end.
74
- # chain(:on => :success) do |tag|
92
+ # def process(taggable, tag_name)
93
+ # find_tag
94
+ # .chain(on: :failure) do
95
+ # # If the finding the tag fails, this step is called, returning a
96
+ # # result with a newly created tag.
97
+ # create_tag.call(tag_name)
98
+ # end
99
+ # .chain(:on => :success) do |tag|
100
+ # # Finally, the tag has been either found or created, so we can
101
+ # # create the tagging relation.
75
102
  # tag.create_tagging(taggable)
76
103
  # end
77
- # end # method process
78
- # end # method class
104
+ # .call(tag_name)
105
+ # end
106
+ # end
79
107
  #
80
108
  # post = Post.create(:title => 'Tagging Example')
81
109
  # example_tag = Tag.create(:name => 'Example Tag')
82
110
  #
83
111
  # result = CreateTaggingCommand.new.call(post, 'Example Tag')
84
112
  # result.success? #=> true
85
- # result.errors #=> []
113
+ # result.error #=> nil
86
114
  # result.value #=> an instance of Tagging
87
115
  # post.tags.map(&:name)
88
116
  # #=> ['Example Tag']
89
117
  #
90
118
  # result = CreateTaggingCommand.new.call(post, 'Another Tag')
91
119
  # result.success? #=> true
92
- # result.errors #=> []
120
+ # result.error #=> nil
93
121
  # result.value #=> an instance of Tagging
94
122
  # post.tags.map(&:name)
95
123
  # #=> ['Example Tag', 'Another Tag']
96
124
  #
97
125
  # result = CreateTaggingCommand.new.call(post, 'An Invalid Tag Name')
98
126
  # result.success? #=> false
99
- # result.errors #=> [{ tag: { name: ['is invalid'] }}]
127
+ # result.error #=> [{ tag: { name: ['is invalid'] }}]
100
128
  # post.tags.map(&:name)
101
129
  # #=> ['Example Tag', 'Another Tag']
102
130
  #
@@ -123,12 +151,8 @@ module Cuprum
123
151
  # Find.new(Post).call(id).
124
152
  # yield_result(:on => :failure) do |result|
125
153
  # redirect_to posts_path
126
- #
127
- # # A halted result prevents further :on => :failure commands from
128
- # # being called.
129
- # result.halt!
130
154
  # end.
131
- # yield_result do |result|
155
+ # yield_result(on: :success) do |result|
132
156
  # # Assign our attributes and save the post.
133
157
  # UpdateAttributes.new.call(result.value, attributes)
134
158
  # end.
@@ -140,11 +164,11 @@ module Cuprum
140
164
  # end.
141
165
  # tap_result(:on => :always) do |result|
142
166
  # # Chaining :on => :always ensures that the command will be run,
143
- # # even if the previous result is failing or halted.
167
+ # # even if the previous result is failing.
144
168
  # if result.failure?
145
169
  # log_errors(
146
170
  # :command => UpdatePostCommand,
147
- # :errors => result.errors
171
+ # :error => result.error
148
172
  # )
149
173
  # end
150
174
  # end
@@ -172,6 +196,11 @@ module Cuprum
172
196
  #
173
197
  # @see Cuprum::Command
174
198
  module Chaining
199
+ # (see Cuprum::Processing#call)
200
+ def call(*args, **kwargs, &block)
201
+ yield_chain(super)
202
+ end
203
+
175
204
  # Creates a copy of the first command, and then chains the given command or
176
205
  # block to execute after the first command's implementation. When #call is
177
206
  # executed, each chained command will be called with the previous result
@@ -190,13 +219,11 @@ module Cuprum
190
219
  # @param on [Symbol] Sets a condition on when the chained block can run,
191
220
  # based on the previous result. Valid values are :success, :failure, and
192
221
  # :always. If the value is :success, the block will be called only if
193
- # the previous result succeeded and is not halted. If the value is
194
- # :failure, the block will be called only if the previous result failed
195
- # and is not halted. If the value is :always, the block will be called
196
- # regardless of the previous result status, even if the previous result
197
- # is halted. If no value is given, the command will run whether the
198
- # previous command was a success or a failure, but not if the command
199
- # chain has been halted.
222
+ # the previous result succeeded. If the value is :failure, the block
223
+ # will be called only if the previous result failed. If the value is
224
+ # :always, the block will be called regardless of the previous result
225
+ # status. If no value is given, the command will run whether the
226
+ # previous command was a success or a failure.
200
227
  #
201
228
  # @overload chain(on: nil) { |value| }
202
229
  # Creates an anonymous command from the given block. The command will be
@@ -205,62 +232,16 @@ module Cuprum
205
232
  # @param on [Symbol] Sets a condition on when the chained block can run,
206
233
  # based on the previous result. Valid values are :success, :failure, and
207
234
  # :always. If the value is :success, the block will be called only if
208
- # the previous result succeeded and is not halted. If the value is
209
- # :failure, the block will be called only if the previous result failed
210
- # and is not halted. If the value is :always, the block will be called
211
- # regardless of the previous result status, even if the previous result
212
- # is halted. If no value is given, the command will run whether the
213
- # previous command was a success or a failure, but not if the command
214
- # chain has been halted.
215
- #
216
- # @yieldparam value [Object] The value of the previous result.
217
- def chain command = nil, on: nil, &block
218
- clone.chain!(command, :on => on, &block)
219
- end # method chain
220
-
221
- # Shorthand for command.chain(:on => :failure). Creates a copy of the first
222
- # command, and then chains the given command or block to execute after the
223
- # first command's implementation, but only if the previous command is
224
- # failing.
225
- #
226
- # @return [Cuprum::Chaining] A copy of the command, with the chained
227
- # command.
228
- #
229
- # @see #chain
230
- #
231
- # @overload failure(command)
232
- # @param command [Cuprum::Command] The command to chain.
233
- #
234
- # @overload failure() { |value| }
235
- # Creates an anonymous command from the given block. The command will be
236
- # passed the value of the previous result.
235
+ # the previous result succeeded. If the value is :failure, the block
236
+ # will be called only if the previous result failed. If the value is
237
+ # :always, the block will be called regardless of the previous result
238
+ # status. If no value is given, the command will run whether the
239
+ # previous command was a success or a failure.
237
240
  #
238
241
  # @yieldparam value [Object] The value of the previous result.
239
- def failure command = nil, &block
240
- clone.chain!(command, :on => :failure, &block)
241
- end # method failure
242
-
243
- # Shorthand for command.chain(:on => :success). Creates a copy of the first
244
- # command, and then chains the given command or block to execute after the
245
- # first command's implementation, but only if the previous command is
246
- # failing.
247
- #
248
- # @return [Cuprum::Chaining] A copy of the command, with the chained
249
- # command.
250
- #
251
- # @see #chain
252
- #
253
- # @overload success(command)
254
- # @param command [Cuprum::Command] The command to chain.
255
- #
256
- # @overload success() { |value| }
257
- # Creates an anonymous command from the given block. The command will be
258
- # passed the value of the previous result.
259
- #
260
- # @yieldparam value [Object] The value of the previous result.
261
- def success command = nil, &block
262
- clone.chain!(command, :on => :success, &block)
263
- end # method success
242
+ def chain(command = nil, on: nil, &block)
243
+ clone.chain!(command, on: on, &block)
244
+ end
264
245
 
265
246
  # As #yield_result, but always returns the previous result when the block is
266
247
  # called. The return value of the block is discarded.
@@ -272,9 +253,9 @@ module Cuprum
272
253
  # @return (see #yield_result)
273
254
  #
274
255
  # @see #yield_result
275
- def tap_result on: nil, &block
276
- clone.tap_result!(:on => on, &block)
277
- end # method tap_result
256
+ def tap_result(on: nil, &block)
257
+ clone.tap_result!(on: on, &block)
258
+ end
278
259
 
279
260
  # Creates a copy of the command, and then chains the block to execute after
280
261
  # the command implementation. When #call is executed, each chained block
@@ -284,24 +265,25 @@ module Cuprum
284
265
  # @param on [Symbol] Sets a condition on when the chained block can run,
285
266
  # based on the previous result. Valid values are :success, :failure, and
286
267
  # :always. If the value is :success, the block will be called only if the
287
- # previous result succeeded and is not halted. If the value is :failure,
288
- # the block will be called only if the previous result failed and is not
289
- # halted. If the value is :always, the block will be called regardless of
290
- # the previous result status, even if the previous result is halted. If no
268
+ # previous result succeeded. If the value is :failure, the block will be
269
+ # called only if the previous result failed. If the value is :always, the
270
+ # block will be called regardless of the previous result status. If no
291
271
  # value is given, the command will run whether the previous command was a
292
- # success or a failure, but not if the command chain has been halted.
272
+ # success or a failure.
293
273
  #
294
274
  # @yieldparam result [Cuprum::Result] The #result of the previous command.
295
275
  #
296
276
  # @return [Cuprum::Chaining] A copy of the command, with the chained block.
297
277
  #
298
278
  # @see #tap_result
299
- def yield_result on: nil, &block
300
- clone.yield_result!(:on => on, &block)
301
- end # method yield_result
279
+ def yield_result(on: nil, &block)
280
+ clone.yield_result!(on: on, &block)
281
+ end
302
282
 
303
283
  protected
304
284
 
285
+ # rubocop:disable Metrics/MethodLength
286
+
305
287
  # @!visibility public
306
288
  #
307
289
  # As #chain, but modifies the current command instead of creating a clone.
@@ -318,13 +300,11 @@ module Cuprum
318
300
  # @param on [Symbol] Sets a condition on when the chained block can run,
319
301
  # based on the previous result. Valid values are :success, :failure, and
320
302
  # :always. If the value is :success, the block will be called only if
321
- # the previous result succeeded and is not halted. If the value is
322
- # :failure, the block will be called only if the previous result failed
323
- # and is not halted. If the value is :always, the block will be called
324
- # regardless of the previous result status, even if the previous result
325
- # is halted. If no value is given, the command will run whether the
326
- # previous command was a success or a failure, but not if the command
327
- # chain has been halted.
303
+ # the previous result succeeded. If the value is :failure, the block
304
+ # will be called only if the previous result failed. If the value is
305
+ # :always, the block will be called regardless of the previous result
306
+ # status. If no value is given, the command will run whether the
307
+ # previous command was a success or a failure.
328
308
  #
329
309
  # @overload chain!(on: nil) { |value| }
330
310
  # Creates an anonymous command from the given block. The command will be
@@ -333,34 +313,36 @@ module Cuprum
333
313
  # @param on [Symbol] Sets a condition on when the chained block can run,
334
314
  # based on the previous result. Valid values are :success, :failure, and
335
315
  # :always. If the value is :success, the block will be called only if
336
- # the previous result succeeded and is not halted. If the value is
337
- # :failure, the block will be called only if the previous result failed
338
- # and is not halted. If the value is :always, the block will be called
339
- # regardless of the previous result status, even if the previous result
340
- # is halted. If no value is given, the command will run whether the
341
- # previous command was a success or a failure, but not if the command
342
- # chain has been halted.
316
+ # the previous result succeeded. If the value is :failure, the block
317
+ # will be called only if the previous result failed. If the value is
318
+ # :always, the block will be called regardless of the previous result
319
+ # status. If no value is given, the command will run whether the
320
+ # previous command was a success or a failure.
343
321
  #
344
322
  # @yieldparam value [Object] The value of the previous result.
345
- def chain! command = nil, on: nil, &block
323
+ def chain!(command = nil, on: nil, &block)
324
+ SleepingKingStudios::Tools::CoreTools.deprecate(
325
+ "#{self.class}#chain",
326
+ message: 'Use the #step method to compose commands.'
327
+ )
328
+
346
329
  command ||= Cuprum::Command.new(&block)
347
330
 
348
331
  chained_procs <<
349
332
  {
350
- :proc => chain_command(command),
351
- :on => on
333
+ proc: chain_command(command),
334
+ on: on
352
335
  } # end hash
353
336
 
354
337
  self
355
- end # method chain!
338
+ end
339
+ # rubocop:enable Metrics/MethodLength
356
340
 
357
341
  def chained_procs
358
342
  @chained_procs ||= []
359
- end # method chained_procs
343
+ end
360
344
 
361
- def process_with_result *args, &block
362
- yield_chain(super)
363
- end # method call
345
+ # rubocop:disable Metrics/MethodLength
364
346
 
365
347
  # @!visibility public
366
348
  #
@@ -375,17 +357,23 @@ module Cuprum
375
357
  # @return (see #tap_result)
376
358
  #
377
359
  # @see #tap_result
378
- def tap_result! on: nil, &block
360
+ def tap_result!(on: nil, &block)
361
+ SleepingKingStudios::Tools::CoreTools.deprecate(
362
+ "#{self.class}#tap_result",
363
+ message: 'Use the #step method to compose commands.'
364
+ )
365
+
379
366
  tapped = ->(result) { result.tap { block.call(result) } }
380
367
 
381
368
  chained_procs <<
382
369
  {
383
- :proc => tapped,
384
- :on => on
370
+ proc: tapped,
371
+ on: on
385
372
  } # end hash
386
373
 
387
374
  self
388
- end # method tap_result!
375
+ end
376
+ # rubocop:enable Metrics/MethodLength
389
377
 
390
378
  # @!visibility public
391
379
  #
@@ -400,51 +388,54 @@ module Cuprum
400
388
  # @return (see #yield_result)
401
389
  #
402
390
  # @see #yield_result
403
- def yield_result! on: nil, &block
391
+ def yield_result!(on: nil, &block)
392
+ SleepingKingStudios::Tools::CoreTools.deprecate(
393
+ "#{self.class}#yield_result",
394
+ message: 'Use the #step method to compose commands.'
395
+ )
396
+
404
397
  chained_procs <<
405
398
  {
406
- :proc => block,
407
- :on => on
399
+ proc: block,
400
+ on: on
408
401
  } # end hash
409
402
 
410
403
  self
411
- end # method yield_result!
404
+ end
412
405
 
413
406
  private
414
407
 
415
- def chain_command command
408
+ def chain_command(command)
416
409
  if command.arity.zero?
417
- ->(result) { command.process_with_result(result) }
410
+ ->(_result) { command.call }
418
411
  else
419
- ->(result) { command.process_with_result(result, result.value) }
420
- end # if-else
421
- end # method chain_command
412
+ ->(result) { command.call(result.value) }
413
+ end
414
+ end
422
415
 
423
- def skip_chained_proc? last_result, on:
416
+ def skip_chained_proc?(last_result, on:)
424
417
  return false if on == :always
425
418
 
426
- return true if last_result.respond_to?(:halted?) && last_result.halted?
427
-
428
419
  case on
429
420
  when :success
430
421
  !last_result.success?
431
422
  when :failure
432
423
  !last_result.failure?
433
- end # case
434
- end # method skip_chained_proc?
424
+ end
425
+ end
435
426
 
436
- def yield_chain first_result
427
+ def yield_chain(first_result)
437
428
  chained_procs.reduce(first_result) do |result, hsh|
438
- next result if skip_chained_proc?(result, :on => hsh[:on])
429
+ next result if skip_chained_proc?(result, on: hsh[:on])
439
430
 
440
431
  value = hsh.fetch(:proc).call(result)
441
432
 
442
433
  if value_is_result?(value)
443
- value.to_result
434
+ value.to_cuprum_result
444
435
  else
445
- build_result(value)
446
- end # if-else
447
- end # reduce
448
- end # method yield_chain
449
- end # module
450
- end # modue
436
+ build_result(value: value)
437
+ end
438
+ end
439
+ end
440
+ end
441
+ end