cuprum 0.8.0 → 0.10.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.
@@ -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