cuprum 0.9.1 → 0.11.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 +70 -0
- data/DEVELOPMENT.md +42 -53
- data/README.md +728 -536
- data/lib/cuprum.rb +12 -6
- data/lib/cuprum/built_in.rb +3 -1
- data/lib/cuprum/built_in/identity_command.rb +6 -4
- data/lib/cuprum/built_in/identity_operation.rb +4 -2
- data/lib/cuprum/built_in/null_command.rb +5 -3
- data/lib/cuprum/built_in/null_operation.rb +4 -2
- data/lib/cuprum/command.rb +37 -59
- data/lib/cuprum/command_factory.rb +50 -24
- data/lib/cuprum/currying.rb +79 -0
- data/lib/cuprum/currying/curried_command.rb +116 -0
- data/lib/cuprum/error.rb +44 -10
- data/lib/cuprum/errors.rb +2 -0
- data/lib/cuprum/errors/command_not_implemented.rb +6 -3
- data/lib/cuprum/errors/operation_not_called.rb +6 -6
- data/lib/cuprum/errors/uncaught_exception.rb +55 -0
- data/lib/cuprum/exception_handling.rb +50 -0
- data/lib/cuprum/matcher.rb +90 -0
- data/lib/cuprum/matcher_list.rb +150 -0
- data/lib/cuprum/matching.rb +232 -0
- data/lib/cuprum/matching/match_clause.rb +65 -0
- data/lib/cuprum/middleware.rb +210 -0
- data/lib/cuprum/operation.rb +17 -15
- data/lib/cuprum/processing.rb +10 -14
- data/lib/cuprum/result.rb +2 -4
- data/lib/cuprum/result_helpers.rb +22 -0
- data/lib/cuprum/rspec/be_a_result.rb +10 -1
- data/lib/cuprum/rspec/be_a_result_matcher.rb +5 -7
- data/lib/cuprum/rspec/be_callable.rb +14 -0
- data/lib/cuprum/steps.rb +233 -0
- data/lib/cuprum/utils.rb +3 -1
- data/lib/cuprum/utils/instance_spy.rb +37 -30
- data/lib/cuprum/version.rb +13 -10
- metadata +34 -19
- data/lib/cuprum/chaining.rb +0 -420
data/lib/cuprum/operation.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cuprum/command'
|
2
4
|
require 'cuprum/errors/operation_not_called'
|
3
5
|
|
@@ -26,8 +28,8 @@ module Cuprum
|
|
26
28
|
# @book = operation.value
|
27
29
|
#
|
28
30
|
# render :new
|
29
|
-
# end
|
30
|
-
# end
|
31
|
+
# end
|
32
|
+
# end
|
31
33
|
#
|
32
34
|
# Like a Command, an Operation can be defined directly by passing an
|
33
35
|
# implementation block to the constructor or by creating a subclass that
|
@@ -41,7 +43,7 @@ module Cuprum
|
|
41
43
|
# @example
|
42
44
|
# class CustomOperation < CustomCommand
|
43
45
|
# include Cuprum::Operation::Mixin
|
44
|
-
# end
|
46
|
+
# end
|
45
47
|
module Mixin
|
46
48
|
# @return [Cuprum::Result] The result from the most recent call of the
|
47
49
|
# operation.
|
@@ -62,32 +64,32 @@ module Cuprum
|
|
62
64
|
# implementation.
|
63
65
|
#
|
64
66
|
# @see Cuprum::Command#call
|
65
|
-
def call
|
67
|
+
def call(*args, **kwargs, &block)
|
66
68
|
reset! if called? # Clear reference to most recent result.
|
67
69
|
|
68
70
|
@result = super
|
69
71
|
|
70
72
|
self
|
71
|
-
end
|
73
|
+
end
|
72
74
|
|
73
75
|
# @return [Boolean] true if the operation has been called and has a
|
74
76
|
# reference to the most recent result; otherwise false.
|
75
77
|
def called?
|
76
78
|
!result.nil?
|
77
|
-
end
|
79
|
+
end
|
78
80
|
|
79
81
|
# @return [Object] the error (if any) from the most recent result, or nil
|
80
82
|
# if the operation has not been called.
|
81
83
|
def error
|
82
84
|
called? ? result.error : nil
|
83
|
-
end
|
85
|
+
end
|
84
86
|
|
85
87
|
# @return [Boolean] true if the most recent result had an error, or false
|
86
88
|
# if the most recent result had no error or if the operation has not
|
87
89
|
# been called.
|
88
90
|
def failure?
|
89
91
|
called? ? result.failure? : false
|
90
|
-
end
|
92
|
+
end
|
91
93
|
|
92
94
|
# Clears the reference to the most recent call of the operation, if any.
|
93
95
|
# This allows the result and any referenced data to be garbage collected.
|
@@ -99,7 +101,7 @@ module Cuprum
|
|
99
101
|
# an error.
|
100
102
|
def reset!
|
101
103
|
@result = nil
|
102
|
-
end
|
104
|
+
end
|
103
105
|
|
104
106
|
# @return [Symbol, nil] the status of the most recent result, or nil if
|
105
107
|
# the operation has not been called.
|
@@ -112,7 +114,7 @@ module Cuprum
|
|
112
114
|
# been called.
|
113
115
|
def success?
|
114
116
|
called? ? result.success? : false
|
115
|
-
end
|
117
|
+
end
|
116
118
|
|
117
119
|
# Returns the most result if the operation was previously called.
|
118
120
|
# Otherwise, returns a failing result.
|
@@ -130,8 +132,8 @@ module Cuprum
|
|
130
132
|
# operation has not been called.
|
131
133
|
def value
|
132
134
|
called? ? result.value : nil
|
133
|
-
end
|
134
|
-
end
|
135
|
+
end
|
136
|
+
end
|
135
137
|
include Mixin
|
136
138
|
|
137
139
|
# @!method call
|
@@ -156,9 +158,9 @@ module Cuprum
|
|
156
158
|
# (see Cuprum::Operation::Mixin#success?)
|
157
159
|
|
158
160
|
# @!method to_cuprum_result
|
159
|
-
# (see Cuprum::Operation::Mixin#to_cuprum_result
|
161
|
+
# (see Cuprum::Operation::Mixin#to_cuprum_result)
|
160
162
|
|
161
163
|
# @!method value
|
162
164
|
# (see Cuprum::Operation::Mixin#value)
|
163
|
-
end
|
164
|
-
end
|
165
|
+
end
|
166
|
+
end
|
data/lib/cuprum/processing.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'cuprum/errors/command_not_implemented'
|
4
|
+
require 'cuprum/result_helpers'
|
4
5
|
|
5
6
|
module Cuprum
|
6
7
|
# Functional implementation for creating a command object. Cuprum::Processing
|
@@ -57,6 +58,8 @@ module Cuprum
|
|
57
58
|
#
|
58
59
|
# @see Cuprum::Command
|
59
60
|
module Processing
|
61
|
+
include Cuprum::ResultHelpers
|
62
|
+
|
60
63
|
# Returns a nonnegative integer for commands that take a fixed number of
|
61
64
|
# arguments. For commands that take a variable number of arguments, returns
|
62
65
|
# -n-1, where n is the number of required arguments.
|
@@ -87,8 +90,13 @@ module Cuprum
|
|
87
90
|
#
|
88
91
|
# @yield If a block argument is given, it will be passed to the
|
89
92
|
# implementation.
|
90
|
-
def call(*args, &block)
|
91
|
-
value =
|
93
|
+
def call(*args, **kwargs, &block)
|
94
|
+
value =
|
95
|
+
if kwargs.empty?
|
96
|
+
process(*args, &block)
|
97
|
+
else
|
98
|
+
process(*args, **kwargs, &block)
|
99
|
+
end
|
92
100
|
|
93
101
|
return value.to_cuprum_result if value_is_result?(value)
|
94
102
|
|
@@ -97,14 +105,6 @@ module Cuprum
|
|
97
105
|
|
98
106
|
private
|
99
107
|
|
100
|
-
def build_result(error: nil, status: nil, value: nil)
|
101
|
-
Cuprum::Result.new(error: error, status: status, value: value)
|
102
|
-
end
|
103
|
-
|
104
|
-
def failure(error)
|
105
|
-
build_result(error: error)
|
106
|
-
end
|
107
|
-
|
108
108
|
# @!visibility public
|
109
109
|
# @overload process(*arguments, **keywords, &block)
|
110
110
|
# The implementation of the command, to be executed when the #call method
|
@@ -128,10 +128,6 @@ module Cuprum
|
|
128
128
|
build_result(error: error)
|
129
129
|
end
|
130
130
|
|
131
|
-
def success(value)
|
132
|
-
build_result(value: value)
|
133
|
-
end
|
134
|
-
|
135
131
|
def value_is_result?(value)
|
136
132
|
value.respond_to?(:to_cuprum_result)
|
137
133
|
end
|
data/lib/cuprum/result.rb
CHANGED
@@ -5,6 +5,7 @@ require 'cuprum'
|
|
5
5
|
module Cuprum
|
6
6
|
# Data object that encapsulates the result of calling a Cuprum command.
|
7
7
|
class Result
|
8
|
+
# Enumerates the default permitted values for a Result#status.
|
8
9
|
STATUSES = %i[success failure].freeze
|
9
10
|
|
10
11
|
# @param value [Object] The value returned by calling the command.
|
@@ -28,8 +29,6 @@ module Cuprum
|
|
28
29
|
# @return [Symbol] the status of the result, either :success or :failure.
|
29
30
|
attr_reader :status
|
30
31
|
|
31
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
32
|
-
|
33
32
|
# Compares the other object to the result.
|
34
33
|
#
|
35
34
|
# @param other [#value, #success?] An object responding to, at minimum,
|
@@ -45,7 +44,6 @@ module Cuprum
|
|
45
44
|
|
46
45
|
true
|
47
46
|
end
|
48
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
49
47
|
|
50
48
|
# @return [Boolean] true if the result status is :failure, otherwise false.
|
51
49
|
def failure?
|
@@ -71,7 +69,7 @@ module Cuprum
|
|
71
69
|
def normalize_status(status)
|
72
70
|
return status unless status.is_a?(String) || status.is_a?(Symbol)
|
73
71
|
|
74
|
-
tools.
|
72
|
+
tools.string_tools.underscore(status).intern
|
75
73
|
end
|
76
74
|
|
77
75
|
def resolve_status(status)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum'
|
4
|
+
|
5
|
+
module Cuprum
|
6
|
+
# Helper methods for generating Cuprum result objects.
|
7
|
+
module ResultHelpers
|
8
|
+
private
|
9
|
+
|
10
|
+
def build_result(error: nil, status: nil, value: nil)
|
11
|
+
Cuprum::Result.new(error: error, status: status, value: value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure(error)
|
15
|
+
build_result(error: error)
|
16
|
+
end
|
17
|
+
|
18
|
+
def success(value)
|
19
|
+
build_result(value: value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -2,16 +2,25 @@
|
|
2
2
|
|
3
3
|
require 'cuprum/rspec/be_a_result_matcher'
|
4
4
|
|
5
|
-
module RSpec
|
5
|
+
module Cuprum::RSpec
|
6
6
|
module Matchers # rubocop:disable Style/Documentation
|
7
|
+
# Asserts that the object is a Cuprum::Result with status: :failure.
|
8
|
+
#
|
9
|
+
# @return [Cuprum::RSpec::BeAResultMatcher] the generated matcher.
|
7
10
|
def be_a_failing_result
|
8
11
|
be_a_result.with_status(:failure)
|
9
12
|
end
|
10
13
|
|
14
|
+
# Asserts that the object is a Cuprum::Result with status: :success.
|
15
|
+
#
|
16
|
+
# @return [Cuprum::RSpec::BeAResultMatcher] the generated matcher.
|
11
17
|
def be_a_passing_result
|
12
18
|
be_a_result.with_status(:success).and_error(nil)
|
13
19
|
end
|
14
20
|
|
21
|
+
# Asserts that the object is a Cuprum::Result.
|
22
|
+
#
|
23
|
+
# @return [Cuprum::RSpec::BeAResultMatcher] the generated matcher.
|
15
24
|
def be_a_result
|
16
25
|
Cuprum::RSpec::BeAResultMatcher.new
|
17
26
|
end
|
@@ -46,9 +46,9 @@ module Cuprum::RSpec
|
|
46
46
|
message = "expected #{actual.inspect} to #{description}"
|
47
47
|
|
48
48
|
if !actual_is_result?
|
49
|
-
message
|
49
|
+
"#{message}, but the object is not a result"
|
50
50
|
elsif actual_is_uncalled_operation?
|
51
|
-
message
|
51
|
+
"#{message}, but the object is an uncalled operation"
|
52
52
|
elsif !properties_match?
|
53
53
|
message + properties_failure_message
|
54
54
|
else
|
@@ -182,7 +182,6 @@ module Cuprum::RSpec
|
|
182
182
|
' positives, since any other result will match.'
|
183
183
|
end
|
184
184
|
|
185
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
186
185
|
# rubocop:disable Metrics/AbcSize
|
187
186
|
def properties_description
|
188
187
|
msg = ''
|
@@ -191,7 +190,7 @@ module Cuprum::RSpec
|
|
191
190
|
ary << 'error' if expected_error? && !expected_error.nil?
|
192
191
|
|
193
192
|
unless ary.empty?
|
194
|
-
msg = "with the expected #{tools.
|
193
|
+
msg = "with the expected #{tools.array_tools.humanize_list(ary)}"
|
195
194
|
end
|
196
195
|
|
197
196
|
return msg unless expected_status?
|
@@ -200,7 +199,6 @@ module Cuprum::RSpec
|
|
200
199
|
|
201
200
|
msg + " and status: #{expected_status.inspect}"
|
202
201
|
end
|
203
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
204
202
|
# rubocop:enable Metrics/AbcSize
|
205
203
|
|
206
204
|
def properties_failure_message
|
@@ -220,8 +218,8 @@ module Cuprum::RSpec
|
|
220
218
|
ary << 'value' unless value_matches?
|
221
219
|
ary << 'error' unless error_matches?
|
222
220
|
|
223
|
-
", but the #{tools.
|
224
|
-
" #{tools.
|
221
|
+
", but the #{tools.array_tools.humanize_list(ary)}" \
|
222
|
+
" #{tools.integer_tools.pluralize(ary.size, 'does', 'do')} not match:"
|
225
223
|
end
|
226
224
|
|
227
225
|
def properties_warning
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/rspec'
|
4
|
+
|
5
|
+
module Cuprum::RSpec
|
6
|
+
module Matchers # rubocop:disable Style/Documentation
|
7
|
+
# Asserts that the command defines a :process method.
|
8
|
+
#
|
9
|
+
# @return [RSpec::Matchers::BuiltIn::RespondTo] the generated matcher.
|
10
|
+
def be_callable
|
11
|
+
respond_to(:process, true)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/cuprum/steps.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/result_helpers'
|
4
|
+
|
5
|
+
module Cuprum
|
6
|
+
# The Steps supports step by step processes that halt on a failed step.
|
7
|
+
#
|
8
|
+
# After including Cuprum::Steps, use the #steps instance method to wrap a
|
9
|
+
# series of instructions. Each instruction is then defined using the #step
|
10
|
+
# method. Steps can be defined either as a block or as a method invocation.
|
11
|
+
#
|
12
|
+
# When the steps block is evaluated, each step is called in sequence. If the
|
13
|
+
# step resolves to a passing result, the result value is returned and
|
14
|
+
# execution continues to the next step. If all of the steps pass, then the
|
15
|
+
# result of the final step is returned from the #steps block.
|
16
|
+
#
|
17
|
+
# Conversely, if any step resolves to a failing result, that failing result is
|
18
|
+
# immediately returned from the #steps block. No further steps will be called.
|
19
|
+
#
|
20
|
+
# For example, consider updating a database record using a primary key and an
|
21
|
+
# attributes hash. Broken down into its basics, this requires the following
|
22
|
+
# instructions:
|
23
|
+
#
|
24
|
+
# - Using the primary key, find the existing record in the database.
|
25
|
+
# - Update the record object with the given attributes.
|
26
|
+
# - Save the updated record back to the database.
|
27
|
+
#
|
28
|
+
# Note that each of these steps can fail for different reasons. For example,
|
29
|
+
# if a record with the given primary key does not exist in the database, then
|
30
|
+
# the first instruction will fail, and the follow up steps should not be
|
31
|
+
# executed. Further, whatever context is executing these steps probably wants
|
32
|
+
# to know which step failed, and why.
|
33
|
+
#
|
34
|
+
# @example Defining Methods As Steps
|
35
|
+
# def assign_attributes(record, attributes); end
|
36
|
+
#
|
37
|
+
# def find_record(primary_key); end
|
38
|
+
#
|
39
|
+
# def save_record(record); end
|
40
|
+
#
|
41
|
+
# def update_record(primary_key, attributes)
|
42
|
+
# steps do
|
43
|
+
# record = step :find_record, primary_key
|
44
|
+
# record = step :assign_attributes, record, attributes
|
45
|
+
# step :save_record, record
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# @example Defining Blocks As Steps
|
50
|
+
# class AssignAttributes < Cuprum::Command; end
|
51
|
+
#
|
52
|
+
# class FindRecord < Cuprum::Command; end
|
53
|
+
#
|
54
|
+
# class SaveRecord < Cuprum::Command; end
|
55
|
+
#
|
56
|
+
# def update_record(primary_key, attributes)
|
57
|
+
# steps do
|
58
|
+
# record = step { FindRecord.new.call(primary_key) }
|
59
|
+
# record = step { AssignAttributes.new.call(record, attributes) }
|
60
|
+
# step { SaveRecord.new.call(record) }
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
module Steps
|
64
|
+
include Cuprum::ResultHelpers
|
65
|
+
|
66
|
+
UNDEFINED = Object.new.freeze
|
67
|
+
private_constant :UNDEFINED
|
68
|
+
|
69
|
+
class << self
|
70
|
+
# @!visibility private
|
71
|
+
def execute_method(receiver, method_name, *args, **kwargs, &block)
|
72
|
+
if block_given? && kwargs.empty?
|
73
|
+
receiver.send(method_name, *args, &block)
|
74
|
+
elsif block_given?
|
75
|
+
receiver.send(method_name, *args, **kwargs, &block)
|
76
|
+
elsif kwargs.empty?
|
77
|
+
receiver.send(method_name, *args)
|
78
|
+
else
|
79
|
+
receiver.send(method_name, *args, **kwargs)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @!visibility private
|
84
|
+
def extract_result_value(result)
|
85
|
+
return result unless result.respond_to?(:to_cuprum_result)
|
86
|
+
|
87
|
+
result = result.to_cuprum_result
|
88
|
+
|
89
|
+
return result.value if result.success?
|
90
|
+
|
91
|
+
throw :cuprum_failed_step, result
|
92
|
+
end
|
93
|
+
|
94
|
+
# rubocop:disable Metrics/MethodLength
|
95
|
+
# @!visibility private
|
96
|
+
def validate_method_name(method_name)
|
97
|
+
if method_name.nil?
|
98
|
+
raise ArgumentError,
|
99
|
+
'expected a block or a method name',
|
100
|
+
caller(1..-1)
|
101
|
+
end
|
102
|
+
|
103
|
+
unless method_name.is_a?(String) || method_name.is_a?(Symbol)
|
104
|
+
raise ArgumentError,
|
105
|
+
'expected method name to be a String or Symbol',
|
106
|
+
caller(1..-1)
|
107
|
+
end
|
108
|
+
|
109
|
+
return unless method_name.empty?
|
110
|
+
|
111
|
+
raise ArgumentError, "method name can't be blank", caller(1..-1)
|
112
|
+
end
|
113
|
+
# rubocop:enable Metrics/MethodLength
|
114
|
+
end
|
115
|
+
|
116
|
+
# Executes the block and returns the value, or halts on a failure.
|
117
|
+
#
|
118
|
+
# @yield Called with no parameters.
|
119
|
+
#
|
120
|
+
# @return [Object] the #value of the result, or the returned object.
|
121
|
+
#
|
122
|
+
# The #step method is used to evaluate a sequence of processes, and to
|
123
|
+
# fail fast and halt processing if any of the steps returns a failing
|
124
|
+
# result. Each invocation of #step should be wrapped in a #steps block,
|
125
|
+
# or used inside the #process method of a Command.
|
126
|
+
#
|
127
|
+
# If the object returned by the block is a Cuprum result or compatible
|
128
|
+
# object (such as a called operation), the value is converted to a Cuprum
|
129
|
+
# result via the #to_cuprum_result method. Otherwise, the object is
|
130
|
+
# returned directly from #step.
|
131
|
+
#
|
132
|
+
# If the returned object is a passing result, the #value of the result is
|
133
|
+
# returned by #step.
|
134
|
+
#
|
135
|
+
# If the returned object is a failing result, then #step will throw
|
136
|
+
# :cuprum_failed_result and the failing result. This is caught by the
|
137
|
+
# #steps block, and halts execution of any subsequent steps.
|
138
|
+
#
|
139
|
+
# @example Calling a Step
|
140
|
+
# # The #do_something method returns the string 'some value'.
|
141
|
+
# step { do_something() } #=> 'some value'
|
142
|
+
#
|
143
|
+
# value = step { do_something() }
|
144
|
+
# value #=> 'some value'
|
145
|
+
#
|
146
|
+
# @example Calling a Step with a Passing Result
|
147
|
+
# # The #do_something_else method returns a Cuprum result with a value
|
148
|
+
# # of 'another value'.
|
149
|
+
# step { do_something_else() } #=> 'another value'
|
150
|
+
#
|
151
|
+
# # The result is passing, so the value is extracted and returned.
|
152
|
+
# value = step { do_something_else() }
|
153
|
+
# value #=> 'another value'
|
154
|
+
#
|
155
|
+
# @example Calling a Step with a Failing Result
|
156
|
+
# # The #do_something_wrong method returns a failing Cuprum result.
|
157
|
+
# step { do_something_wrong() } # Throws the :cuprum_failed_step symbol.
|
158
|
+
def step(method_name = UNDEFINED, *args, **kwargs, &block) # rubocop:disable Metrics/MethodLength
|
159
|
+
result =
|
160
|
+
if method_name != UNDEFINED || !args.empty? || !kwargs.empty?
|
161
|
+
SleepingKingStudios::Tools::CoreTools.deprecate(
|
162
|
+
"#{self.class}#step(method_name)",
|
163
|
+
message: 'Use the block form: step { method_name(*args, **kwargs) }'
|
164
|
+
)
|
165
|
+
|
166
|
+
Cuprum::Steps.validate_method_name(method_name)
|
167
|
+
|
168
|
+
Cuprum::Steps
|
169
|
+
.execute_method(self, method_name, *args, **kwargs, &block)
|
170
|
+
elsif !block_given?
|
171
|
+
raise ArgumentError, 'expected a block'
|
172
|
+
else
|
173
|
+
block.call
|
174
|
+
end
|
175
|
+
|
176
|
+
Cuprum::Steps.extract_result_value(result)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Returns the first failing #step result, or the final result if none fail.
|
180
|
+
#
|
181
|
+
# The #steps method is used to wrap a series of #step calls. Each step is
|
182
|
+
# executed in sequence. If any of the steps returns a failing result, that
|
183
|
+
# result is immediately returned from #steps. Otherwise, #steps wraps the
|
184
|
+
# value returned by a block in a Cuprum result.
|
185
|
+
#
|
186
|
+
# @yield Called with no parameters.
|
187
|
+
#
|
188
|
+
# @yieldreturn A Cuprum result, or an object to be wrapped in a result.
|
189
|
+
#
|
190
|
+
# @return [Cuprum::Result] the result or object returned by the block,
|
191
|
+
# wrapped in a Cuprum result.
|
192
|
+
#
|
193
|
+
# @example With A Passing Step
|
194
|
+
# result = steps do
|
195
|
+
# step { success('some value') }
|
196
|
+
# end
|
197
|
+
# result.class #=> Cuprum::Result
|
198
|
+
# result.success? #=> true
|
199
|
+
# result.value #=> 'some value'
|
200
|
+
#
|
201
|
+
# @example With A Failing Step
|
202
|
+
# result = steps do
|
203
|
+
# step { failure('something went wrong') }
|
204
|
+
# end
|
205
|
+
# result.class #=> Cuprum::Result
|
206
|
+
# result.success? #=> false
|
207
|
+
# result.error #=> 'something went wrong'
|
208
|
+
#
|
209
|
+
# @example With Multiple Steps
|
210
|
+
# result = steps do
|
211
|
+
# # This step is passing, so execution continues on to the next step.
|
212
|
+
# step { success('first step') }
|
213
|
+
#
|
214
|
+
# # This step is failing, so execution halts and returns this result.
|
215
|
+
# step { failure('second step') }
|
216
|
+
#
|
217
|
+
# # This step will never be called.
|
218
|
+
# step { success('third step') }
|
219
|
+
# end
|
220
|
+
# result.class #=> Cuprum::Result
|
221
|
+
# result.success? #=> false
|
222
|
+
# result.error #=> 'second step'
|
223
|
+
def steps(&block)
|
224
|
+
raise ArgumentError, 'no block given' unless block_given?
|
225
|
+
|
226
|
+
result = catch(:cuprum_failed_step) { block.call }
|
227
|
+
|
228
|
+
return result if result.respond_to?(:to_cuprum_result)
|
229
|
+
|
230
|
+
success(result)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|