cuprum 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/DEVELOPMENT.md +43 -9
- data/README.md +525 -326
- data/lib/cuprum/basic_command.rb +212 -0
- data/lib/cuprum/built_in/{identity_function.rb → identity_command.rb} +4 -4
- data/lib/cuprum/built_in/identity_operation.rb +2 -2
- data/lib/cuprum/built_in/{null_function.rb → null_command.rb} +4 -4
- data/lib/cuprum/built_in/null_operation.rb +2 -2
- data/lib/cuprum/chaining.rb +142 -0
- data/lib/cuprum/command.rb +113 -0
- data/lib/cuprum/not_implemented_error.rb +14 -0
- data/lib/cuprum/operation.rb +7 -7
- data/lib/cuprum/utils/instance_spy.rb +15 -16
- data/lib/cuprum/version.rb +1 -1
- metadata +12 -8
- data/lib/cuprum/function.rb +0 -447
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c749e3c0c387227604f9ca4be639d3cabf06dcc
|
4
|
+
data.tar.gz: 779b36680827fb53d901fbe44436e679cf703cfd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95cb4d600263513ef199f4c578f45569eb62052fcd9806fe3f8195ee707fa8fddbaf3704b136192e66186751febefac90050deb51cfaeb502c39eecc75817ea4
|
7
|
+
data.tar.gz: c4571461ea2b47e78598fa46ae21273d439ea8c3b06bb1129b54135850197d5fbc80dc583547464b4d1fcbef89333dc1a042d3aba9c5323887c8abcedef6b05b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.6.0
|
4
|
+
|
5
|
+
The "By Your Command" Update.
|
6
|
+
|
7
|
+
### Commands
|
8
|
+
|
9
|
+
Refactored `Cuprum::Function` to `Cuprum::Command` to better reflect its role as an implementation of the Command pattern.
|
10
|
+
|
11
|
+
Extracted `Cuprum::BasicCommand` as a base class for all commands, implementing `#call` and its associated methods but not including methods or functionality related to command chains.
|
12
|
+
|
13
|
+
Extracted the `Cuprum::Chaining` mixin, which encapsulates all of the methods and functionality necessary to implement command chaining.
|
14
|
+
|
15
|
+
### Built In Commands
|
16
|
+
|
17
|
+
Refactored `Cuprum::BuiltIn::IdentityFunction` to `Cuprum::BuiltIn::IdentityCommand`.
|
18
|
+
|
19
|
+
Refactored `Cuprum::BuiltIn::NullFunction` to `Cuprum::BuiltIn::NullCommand`.
|
20
|
+
|
3
21
|
## 0.5.0
|
4
22
|
|
5
23
|
The "Name Not Found For NullFunction" Update.
|
data/DEVELOPMENT.md
CHANGED
@@ -1,18 +1,52 @@
|
|
1
1
|
# Development
|
2
2
|
|
3
|
-
-
|
4
|
-
- Extract Cuprum::BasicCommand (excludes chaining functionality).
|
3
|
+
- Update documentation.
|
5
4
|
|
6
5
|
## Core
|
7
6
|
|
8
|
-
##
|
7
|
+
## Command
|
9
8
|
|
10
|
-
-
|
11
|
-
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
- Chaining Methods:
|
10
|
+
- #chain:
|
11
|
+
- with a command, sets the command's #result to the last result and calls
|
12
|
+
#process with the last result's #value; returns result of calling chained
|
13
|
+
command.
|
14
|
+
- with a block creates anonymous command, then see above
|
15
|
+
- if the command does not accept any arguments (or keywords if #value is a
|
16
|
+
Hash), does not pass #value. Requires #arity, #apply_chained?
|
17
|
+
- one argument (on), values nil (default), :success, :failure, :always
|
18
|
+
- #success - as chain(:success)
|
19
|
+
- #failure - as chain(:failure)
|
20
|
+
- #tap_result:
|
21
|
+
- block form only, block is yielded and returns the last result
|
22
|
+
- same argument as #chain
|
23
|
+
- #yield_result:
|
24
|
+
- block form only, block is yielded the last result, returns the return
|
25
|
+
value of the block (wrapped in a result if needed)
|
26
|
+
- same argument as #chain
|
27
|
+
- Protected Chaining Methods:
|
28
|
+
- #chain!, #success!, #failure!, #tap_chain!, #yield_result!
|
29
|
+
- adds chained command to current command instead of a clone.
|
30
|
+
- private #build_result
|
31
|
+
|
32
|
+
### Built In
|
33
|
+
|
34
|
+
- MapCommand - wraps a command (or proc) and returns Result with value, errors
|
35
|
+
as array
|
36
|
+
- RetryCommand
|
37
|
+
|
38
|
+
### DSL
|
39
|
+
|
40
|
+
- class-level methods
|
41
|
+
- ::chain (::success, ::failure):
|
42
|
+
on #initialize, chains the given command. Can be given a command class
|
43
|
+
(if ::new takes no arguments) or a block that returns a command.
|
44
|
+
- ::process - shortcut for defining #process
|
45
|
+
- ::rescue - `rescue StandardError do ... end`, rescues matched errors in #process
|
46
|
+
|
47
|
+
### Hooks
|
48
|
+
|
49
|
+
- :before, :around, :after hooks
|
16
50
|
|
17
51
|
## Operation
|
18
52
|
|
data/README.md
CHANGED
@@ -1,441 +1,644 @@
|
|
1
1
|
# Cuprum
|
2
2
|
|
3
|
-
|
4
|
-
citizen of your application.
|
3
|
+
An opinionated implementation of the Command pattern for Ruby applications. Cuprum wraps your business logic in a consistent, object-oriented interface and features status and error management, composability and control flow management.
|
5
4
|
|
6
|
-
|
5
|
+
It defines the following concepts:
|
7
6
|
|
8
|
-
|
7
|
+
- [Commands](#label-Commands) - A function-like object that responds to `#call` and returns a `Result`.
|
8
|
+
- [Operations](#label-Operations) - A stateful `Command` that wraps and delegates to its most recent `Result`.
|
9
|
+
- [Results](#label-Results) - A data object with a `#value`, an `#errors` object, and `#success?` and `#failure?` status methods.
|
9
10
|
|
10
|
-
##
|
11
|
+
## About
|
12
|
+
|
13
|
+
[comment]: # "Status Badges will go here."
|
14
|
+
|
15
|
+
Traditional frameworks such as Rails focus on the objects of your application - the "nouns" such as User, Post, or Item. Using Cuprum or a similar library allows you the developer to make your business logic - the "verbs" such as Create User, Update Post or Ship Item - a first-class citizen of your project. This provides several advantages:
|
16
|
+
|
17
|
+
- **Consistency:** Use the same Commands to underlie controller actions, worker processes and test factories.
|
18
|
+
- **Encapsulation:** Each Command is defined and run in isolation, and dependencies must be explicitly provided to the command when it is initialized or run. This makes it easier to reason about the command's behavior and keep it insulated from changes elsewhere in the code.
|
19
|
+
- **Testability:** Because the logic is extracted from unnecessary context, testing its behavior is much cleaner and easier.
|
20
|
+
- **Composability:** Complex logic such as "find the object with this ID, update it with these attributes, and log the transaction to the reporting service" can be extracted into a series of simple Commands and composed together. The [Chaining](#label-Chaining) feature allows for complex control flows.
|
21
|
+
- **Reusability:** Logic common to multiple data models or instances in your code, such as "persist an object to the database" or "find all records with a given user and created in a date range" can be refactored into parameterized commands.
|
22
|
+
|
23
|
+
### Alternatives
|
24
|
+
|
25
|
+
If you want to extract your logic but Cuprum is not the right solution for you, here are several alternatives:
|
26
|
+
|
27
|
+
- Service objects. A common pattern used when first refactoring an application that has outgrown its abstractions. Service objects are simple and let you group related functionality, but they are harder to compose and require firm conventions to tame.
|
28
|
+
- The [Interactor](https://github.com/collectiveidea/interactor) gem. Provides an `Action` module to implement logic and an `Organizer` module to manage control flow. Supports before, around, and after hooks.
|
29
|
+
- The [Waterfall](https://github.com/apneadiving/waterfall) gem. Focused more on control flow.
|
30
|
+
- [Trailblazer](http://trailblazer.to/) Operations. A pipeline-based approach to control flow, and can integrate tightly with other Trailblazer elements.
|
31
|
+
|
32
|
+
### Compatibility
|
33
|
+
|
34
|
+
Cuprum is tested against Ruby (MRI) 2.4.
|
35
|
+
|
36
|
+
### Documentation
|
11
37
|
|
12
38
|
Method and class documentation is available courtesy of [RubyDoc](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master).
|
13
39
|
|
14
40
|
Documentation is generated using [YARD](https://yardoc.org/), and can be generated locally using the `yard` gem.
|
15
41
|
|
16
|
-
|
42
|
+
### License
|
43
|
+
|
44
|
+
Copyright (c) 2017 Rob Smith
|
17
45
|
|
18
|
-
|
46
|
+
Cuprum is released under the [MIT License](https://opensource.org/licenses/MIT).
|
47
|
+
|
48
|
+
### Contribute
|
19
49
|
|
20
50
|
The canonical repository for this gem is located at https://github.com/sleepingkingstudios/cuprum.
|
21
51
|
|
22
|
-
|
52
|
+
To report a bug or submit a feature request, please use the [Issue Tracker](https://github.com/sleepingkingstudios/cuprum/issues).
|
23
53
|
|
24
|
-
|
54
|
+
To contribute code, please fork the repository, make the desired updates, and then provide a [Pull Request](https://github.com/sleepingkingstudios/cuprum/pulls). Pull requests must include appropriate tests for consideration, and all code must be properly formatted.
|
25
55
|
|
26
|
-
|
56
|
+
### Credits
|
27
57
|
|
28
|
-
|
58
|
+
Hi, I'm Rob Smith, a Ruby Engineer and the developer of this library. I use these tools every day, but they're not just written for me. If you find this project helpful in your own work, or if you have any questions, suggestions or critiques, please feel free to get in touch! I can be reached [on GitHub](https://github.com/sleepingkingstudios/cuprum) or [via email](mailto:merlin@sleepingkingstudios.com). I look forward to hearing from you!
|
29
59
|
|
30
|
-
|
60
|
+
## Concepts
|
31
61
|
|
32
|
-
|
62
|
+
### Commands
|
33
63
|
|
34
|
-
|
64
|
+
require 'cuprum'
|
35
65
|
|
36
|
-
|
66
|
+
Commands are the core feature of Cuprum. In a nutshell, each Cuprum::Command is a functional object that encapsulates a business logic operation. A Command provides a consistent interface and tracking of result value and status. This minimizes boilerplate and allows for interchangeability between different implementations or strategies for managing your data and processes.
|
37
67
|
|
38
|
-
|
68
|
+
Each Command implements a `#call` method that wraps your defined business logic and returns an instance of Cuprum::Result. The result wraps the returned data (with the `#value` method), any `#errors` generated when running the Command, and the overall status with the `#success?` and `#failure` methods. For more details about Cuprum::Result, [see below](#label-Results).
|
39
69
|
|
40
|
-
|
70
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FCommand)
|
41
71
|
|
42
|
-
|
72
|
+
#### Defining Commands
|
43
73
|
|
44
|
-
|
74
|
+
The recommended way to define commands is to create a subclass of `Cuprum::Command` and override the `#process` method.
|
45
75
|
|
46
|
-
|
76
|
+
```ruby
|
77
|
+
class BuildBookCommand < Cuprum::Command
|
78
|
+
def process attributes
|
79
|
+
Book.new(attributes)
|
80
|
+
end # method process
|
81
|
+
end # class
|
47
82
|
|
48
|
-
|
83
|
+
command = BuildPostCommand.new
|
84
|
+
result = command.call(:title => 'The Hobbit') # an instance of Cuprum::Result
|
85
|
+
result.value #=> an instance of Book with title 'The Hobbit'
|
86
|
+
```
|
49
87
|
|
50
|
-
|
88
|
+
There are several takeaways from this example. First, we are defining a custom command class that inherits from `Cuprum::Command`. We are defining the `#process` method, which takes a single `attributes` parameter and returns an instance of `Book`. Then, we are creating an instance of the command, and invoking the `#call` method with an attributes hash. These attributes are passed to our `#process` implementation. Invoking `#call` returns a result, and the `#value` of the result is our new Book.
|
51
89
|
|
52
|
-
|
90
|
+
Because a command is just a Ruby object, we can also pass values to the constructor.
|
53
91
|
|
54
|
-
|
92
|
+
```ruby
|
93
|
+
class SaveBookCommand < Cuprum::Command
|
94
|
+
def initialize repository
|
95
|
+
@repository = repository
|
96
|
+
end # constructor
|
55
97
|
|
56
|
-
|
98
|
+
def process book
|
99
|
+
@repository.persist(book)
|
100
|
+
end # method process
|
101
|
+
end # class
|
57
102
|
|
58
|
-
|
103
|
+
books = [
|
104
|
+
Book.new(:title => 'The Fellowship of the Ring'),
|
105
|
+
Book.new(:title => 'The Two Towers'),
|
106
|
+
Book.new(:title => 'The Return of the King')
|
107
|
+
]
|
108
|
+
command = SaveBookCommand.new(books_repository)
|
109
|
+
books.each { |book| command.call(book) }
|
110
|
+
```
|
59
111
|
|
60
|
-
|
112
|
+
Here, we are reusing the same command three times, rather than creating a new save command for each book. Each book is persisted to the `books_repository`. This is also an example of how using commands can simplify code - notice that nothing about the `SaveBookCommand` is specific to the `Book` model. Thus, we could refactor this into a generic `SaveModelCommand`.
|
61
113
|
|
62
|
-
|
114
|
+
A command can also be defined by passing block to `Cuprum::Command.new`.
|
63
115
|
|
64
|
-
|
116
|
+
```ruby
|
117
|
+
increment_command = Cuprum::Command.new { |int| int + 1 }
|
65
118
|
|
66
|
-
|
119
|
+
increment_command.call(2).value #=> 3
|
120
|
+
```
|
67
121
|
|
68
|
-
|
122
|
+
Commands defined using `Cuprum::Command.new` are quick to use, but more difficult to read and to reuse. Defining your own command class is recommended if a command definition takes up more than one line, or if the command will be used in more than one place.
|
69
123
|
|
70
|
-
|
124
|
+
#### Success, Failure, and Errors
|
71
125
|
|
72
|
-
|
126
|
+
Whether defined with a block or in the `#process` method, the Command implementation can access an `#errors` object while in the `#call` method. Any errors added to the errors object will be exposed by the `#errors` method on the result object.
|
73
127
|
|
74
|
-
|
128
|
+
```ruby
|
129
|
+
class PublishBookCommand < Cuprum::Command
|
130
|
+
private
|
75
131
|
|
76
|
-
|
132
|
+
def process book
|
133
|
+
if book.cover.nil?
|
134
|
+
errors << 'This book does not have a cover.'
|
77
135
|
|
78
|
-
|
136
|
+
return
|
137
|
+
end # if
|
79
138
|
|
80
|
-
|
139
|
+
book.published = true
|
81
140
|
|
82
|
-
|
141
|
+
book
|
142
|
+
end # method process
|
143
|
+
end # class
|
144
|
+
```
|
83
145
|
|
84
|
-
|
146
|
+
In addition, the result object defines `#success?` and `#failure?` predicates. If the result has no errors, then `#success?` will return true and `#failure?` will return false.
|
85
147
|
|
86
|
-
|
148
|
+
```ruby
|
149
|
+
book = Book.new(:title => 'The Silmarillion', :cover => Cover.new)
|
150
|
+
book.published? #=> false
|
87
151
|
|
88
|
-
|
152
|
+
result = PublishBookCommand.new.call(book)
|
153
|
+
result.errors #=> []
|
154
|
+
result.success? #=> true
|
155
|
+
result.failure? #=> false
|
156
|
+
result.value #=> book
|
157
|
+
book.published? #=> true
|
158
|
+
```
|
89
159
|
|
90
|
-
|
160
|
+
If the result does have errors, `#success?` will return false and `#failure?` will return true.
|
91
161
|
|
92
|
-
|
162
|
+
```ruby
|
163
|
+
book = Book.new(:title => 'The Silmarillion', :cover => nil)
|
164
|
+
book.published? #=> false
|
93
165
|
|
94
|
-
|
166
|
+
result = PublishBookCommand.new.call(book)
|
167
|
+
result.errors #=> ['This book does not have a cover.']
|
168
|
+
result.success? #=> false
|
169
|
+
result.failure? #=> true
|
170
|
+
result.value #=> book
|
171
|
+
book.published? #=> false
|
172
|
+
```
|
95
173
|
|
96
|
-
|
174
|
+
### Chaining Commands
|
97
175
|
|
98
|
-
|
176
|
+
Because Cuprum::Command instances are proper objects, they can be composed like any other object. Cuprum::Command also defines methods for chaining commands together. When a chain of commands is called, each command in the chain is called in sequence and passed the value of the previous command. The result of the last command in the chain is returned from the chained call.
|
99
177
|
|
100
|
-
|
178
|
+
class AddCommand < Cuprum::Command
|
179
|
+
def initialize addend
|
180
|
+
@addend = addend
|
181
|
+
end # constructor
|
101
182
|
|
102
|
-
|
183
|
+
private
|
103
184
|
|
104
|
-
|
185
|
+
def process int
|
186
|
+
int + @addend
|
187
|
+
end # method process
|
188
|
+
end # class
|
105
189
|
|
106
|
-
|
190
|
+
double_and_add_one = MultiplyCommand.new(2).chain(AddCommand.new(1))
|
191
|
+
result = double_and_add_one(5)
|
107
192
|
|
108
|
-
|
193
|
+
result.value #=> 5
|
109
194
|
|
110
|
-
|
195
|
+
For finer control over the returned result, `#chain` can instead be called with a block that yields the most recent result. If the block returns a Cuprum::Result, that result is returned or passed to the next command.
|
111
196
|
|
112
|
-
|
197
|
+
MultiplyCommand.new(3).
|
198
|
+
chain { |result| Cuprum::Result.new(result + 1) }.
|
199
|
+
call(3)
|
200
|
+
#=> Returns a Cuprum::Result with a value of 10.
|
113
201
|
|
114
|
-
|
202
|
+
Otherwise, the block is still called but the previous result is returned or passed to the next command in the chain.
|
115
203
|
|
116
|
-
|
204
|
+
AddCommand.new(2).
|
205
|
+
chain { |result| puts "There are #{result.value} lights!" }.
|
206
|
+
call(2)
|
207
|
+
#=> Writes "There are 4 lights!" to STDOUT.
|
208
|
+
#=> Returns a Cuprum::Result with a value of 4.
|
117
209
|
|
118
|
-
|
210
|
+
#### Conditional Chaining
|
119
211
|
|
120
|
-
|
212
|
+
The `#chain` method can be passed an optional `:on` keyword, with values of `:success` and `:failure` accepted. If `#chain` is called with `:on => :success`, then the chained command or block will **only** be called if the previous result `#success?` returns true. Conversely, if `#chain` is called with `:on => :failure`, then the chained command will only be called if the previous result `#failure?` returns true.
|
121
213
|
|
122
|
-
|
214
|
+
In either case, execution will then pass to the next command in the chain, which may itself be called or not if it was conditionally chained. Calling a conditional command chain will return the result of the last called command.
|
123
215
|
|
124
|
-
|
125
|
-
Cuprum::Function.new do
|
126
|
-
errors << "I'm sorry, something went wrong."
|
216
|
+
The methods `#then` and `#else` serve as shortcuts for `#chain` with `:on => :success` and `:on => :failure`, respectively.
|
127
217
|
|
128
|
-
|
129
|
-
|
218
|
+
class EvenCommand < Cuprum::Command
|
219
|
+
private
|
130
220
|
|
131
|
-
|
132
|
-
|
133
|
-
#=> true
|
134
|
-
result.errors
|
135
|
-
#=> ["I'm sorry, something went wrong."]
|
221
|
+
def process int
|
222
|
+
errors << 'errors.messages.not_even' unless int.even?
|
136
223
|
|
137
|
-
|
224
|
+
int
|
225
|
+
end # method process
|
226
|
+
end # class
|
138
227
|
|
139
|
-
|
228
|
+
# The next step in a Collatz sequence is determined as follows:
|
229
|
+
# - If the number is even, divide it by 2.
|
230
|
+
# - If the number is odd, multiply it by 3 and add 1.
|
231
|
+
collatz_command =
|
232
|
+
EvenCommand.new.
|
233
|
+
then(DivideCommand.new(2)).
|
234
|
+
else(MultiplyCommand.new(3).chain(AddCommand.new(1)))
|
140
235
|
|
141
|
-
|
236
|
+
result = collatz_command.new(5)
|
237
|
+
result.value #=> 16
|
142
238
|
|
143
|
-
|
239
|
+
result = collatz_command.new(16)
|
240
|
+
result.value #=> 8
|
144
241
|
|
145
|
-
####
|
242
|
+
#### Halting A Command Chain
|
146
243
|
|
147
|
-
|
244
|
+
If the `#halt` method is called as part of a Command block or `#process` method, the command chain is halted. Any subsequent chained commands will not be called unless they were chained with the `:on => :always` option. This allows you to terminate a Command chain early without having to raise and rescue an exception.
|
148
245
|
|
149
|
-
|
246
|
+
panic_command =
|
247
|
+
Cuprum::Command.new do |value|
|
248
|
+
halt!
|
150
249
|
|
151
|
-
|
250
|
+
value
|
251
|
+
end # command
|
152
252
|
|
153
|
-
|
253
|
+
result =
|
254
|
+
double_command.
|
255
|
+
then(panic_command).
|
256
|
+
then(AddCommand.new(1)). #=> This is never executed.
|
257
|
+
chain(:on => :always) { |count| puts "There are #{count} lights!" }.
|
258
|
+
call(2)
|
259
|
+
#=> Writes "There are 4 lights!" to STDOUT.
|
154
260
|
|
155
|
-
|
261
|
+
result.value #= 4
|
262
|
+
result.halted? #=> true
|
156
263
|
|
157
|
-
###
|
264
|
+
### Results
|
158
265
|
|
159
|
-
|
266
|
+
require 'cuprum'
|
160
267
|
|
161
|
-
|
162
|
-
double_function = Cuprum::Function.new { |int| 2 * int }
|
163
|
-
result = double_function.call(5)
|
268
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FResult)
|
164
269
|
|
165
|
-
|
270
|
+
A Cuprum::Result is a data object that encapsulates the result of calling a Cuprum command. Each result has a `#value`, an `#errors` object (defaults to an Array), and status methods `#success?`, `#failure?`, and `#halted?`.
|
166
271
|
|
167
|
-
|
272
|
+
```ruby
|
273
|
+
value = 'A result value'.freeze
|
274
|
+
result = Cuprum::Result.new(value)
|
168
275
|
|
169
|
-
|
276
|
+
result.value #=> 'A result value'
|
277
|
+
result.errors #=> []
|
278
|
+
result.success? #=> true
|
279
|
+
result.failure? #=> false
|
280
|
+
result.halted? #=> false
|
281
|
+
```
|
170
282
|
|
171
|
-
|
283
|
+
Adding errors to the `#errors` object will change the status of the result.
|
172
284
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
285
|
+
```ruby
|
286
|
+
result.errors << "I'm sorry, something went wrong."
|
287
|
+
result.success? #=> false
|
288
|
+
result.failure? #=> true
|
289
|
+
```
|
178
290
|
|
179
|
-
|
291
|
+
The status can also be overriden with the `#success!` and `#failure!` methods, which will set the status regardless of the presence or absence of errors.
|
180
292
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
293
|
+
```ruby
|
294
|
+
result.success!
|
295
|
+
result.errors #=> ["I'm sorry, something went wrong."]
|
296
|
+
result.success? #=> true
|
297
|
+
result.failure? #=> false
|
298
|
+
```
|
185
299
|
|
186
|
-
|
187
|
-
result = triple_function.call(5)
|
300
|
+
### Operations
|
188
301
|
|
189
|
-
|
302
|
+
require 'cuprum'
|
190
303
|
|
191
|
-
|
304
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FOperation)
|
192
305
|
|
193
|
-
|
306
|
+
An Operation is like a Command, but with two key differences. First, an Operation retains a reference to the result object from the most recent time the operation was called, and delegates the methods defined by `Cuprum::Result` to the most recent result. This allows a called Operation to replace a `Cuprum::Result` in any code that expects or returns a result. Second, the `#call` method returns the operation instance, rather than the result itself.
|
194
307
|
|
195
|
-
|
308
|
+
These two features allow developers to simplify logic around calling and using the results of operations, and reduce the need for boilerplate code (particularly when using an operation as part of an existing framework, such as inside of an asynchronous worker or a Rails controller action).
|
196
309
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
310
|
+
```ruby
|
311
|
+
class CreateBookOperation < Cuprum::Operation
|
312
|
+
def process
|
313
|
+
# Implementation here.
|
314
|
+
end # method process
|
315
|
+
end # class
|
202
316
|
|
203
|
-
|
317
|
+
# Defining a controller action using an operation.
|
318
|
+
def create
|
319
|
+
operation = CreateBookOperation.new.call(book_params)
|
204
320
|
|
205
|
-
|
206
|
-
|
207
|
-
|
321
|
+
if operation.success?
|
322
|
+
redirect_to(operation.value)
|
323
|
+
else
|
324
|
+
@book = operation.value
|
208
325
|
|
209
|
-
|
210
|
-
|
326
|
+
render :new
|
327
|
+
end # if-else
|
328
|
+
end # create
|
329
|
+
```
|
211
330
|
|
212
|
-
|
213
|
-
end # method process
|
214
|
-
end # class
|
331
|
+
Like a Command, an Operation can be defined directly by passing an implementation block to the constructor or by creating a subclass that overwrites the #process method.
|
215
332
|
|
216
|
-
|
333
|
+
An operation inherits the `#call` method from Cuprum::Command (see above), and delegates the `#value`, `#errors`, `#success?`, and `#failure` methods to the most recent result. If the operation has not been called, these methods will return default values.
|
217
334
|
|
218
|
-
|
219
|
-
result = halve_function.call(10)
|
335
|
+
#### The Operation Mixin
|
220
336
|
|
221
|
-
|
222
|
-
result.success? #=> true
|
223
|
-
result.failure? #=> false
|
224
|
-
result.value #=> 5
|
337
|
+
[Module Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FOperation%2FMixin)
|
225
338
|
|
226
|
-
|
339
|
+
The implementation of `Cuprum::Operation` is defined by the `Cuprum::Operation::Mixin` module, which provides the methods defined above. Any command class or instance can be converted to an operation by including (for a class) or extending (for an instance) the operation mixin.
|
227
340
|
|
228
|
-
|
229
|
-
result = function_with_errors.call(10)
|
341
|
+
Finally, the result can be halted using the `#halt` method, which indicates that further chained commands should not be executed.
|
230
342
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
343
|
+
```ruby
|
344
|
+
result.halt!
|
345
|
+
result.halted? #=> true
|
346
|
+
```
|
235
347
|
|
236
|
-
###
|
348
|
+
### Built In Commands
|
237
349
|
|
238
|
-
|
350
|
+
Cuprum includes a small number of predefined commands and their equivalent operations.
|
239
351
|
|
240
|
-
|
241
|
-
def initialize addend
|
242
|
-
@addend = addend
|
243
|
-
end # constructor
|
352
|
+
#### IdentityCommand
|
244
353
|
|
245
|
-
|
354
|
+
require 'cuprum/built_in/identity_command'
|
246
355
|
|
247
|
-
|
248
|
-
int + @addend
|
249
|
-
end # method process
|
250
|
-
end # class
|
356
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FIdentityCommand)
|
251
357
|
|
252
|
-
|
253
|
-
result = double_and_add_one(5)
|
358
|
+
A pregenerated command that returns the value or result with which it was called.
|
254
359
|
|
255
|
-
|
360
|
+
```ruby
|
361
|
+
command = Cuprum::BuiltIn::IdentityCommand.new
|
362
|
+
result = command.call('expected value')
|
363
|
+
result.value #=> 'expected value'
|
364
|
+
result.success? #=> true
|
365
|
+
```
|
256
366
|
|
257
|
-
|
367
|
+
#### IdentityOperation
|
258
368
|
|
259
|
-
|
260
|
-
chain { |result| Cuprum::Result.new(result + 1) }.
|
261
|
-
call(3)
|
262
|
-
#=> Returns a Cuprum::Result with a value of 10.
|
369
|
+
require 'cuprum/built_in/identity_operation'
|
263
370
|
|
264
|
-
|
371
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FIdentityOperation)
|
265
372
|
|
266
|
-
|
267
|
-
chain { |result| puts "There are #{result.value} lights!" }.
|
268
|
-
call(2)
|
269
|
-
#=> Writes "There are 4 lights!" to STDOUT.
|
270
|
-
#=> Returns a Cuprum::Result with a value of 4.
|
373
|
+
A pregenerated operation that sets its result to the value or result with which it was called.
|
271
374
|
|
272
|
-
|
375
|
+
```ruby
|
376
|
+
operation = Cuprum::BuiltIn::IdentityOperation.new.call('expected value')
|
377
|
+
operation.value #=> 'expected value'
|
378
|
+
operation.success? #=> true
|
379
|
+
```
|
273
380
|
|
274
|
-
|
381
|
+
#### NullCommand
|
275
382
|
|
276
|
-
|
383
|
+
require 'cuprum/built_in/null_command'
|
277
384
|
|
278
|
-
|
385
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FNullCommand)
|
279
386
|
|
280
|
-
|
281
|
-
private
|
387
|
+
A pregenerated command that does nothing when called. Accepts any arguments.
|
282
388
|
|
283
|
-
|
284
|
-
|
389
|
+
```ruby
|
390
|
+
command = Cuprum::BuiltIn::NullCommand.new
|
391
|
+
result = command.call
|
392
|
+
result.value #=> nil
|
393
|
+
result.success? #=> true
|
394
|
+
```
|
285
395
|
|
286
|
-
|
287
|
-
end # method process
|
288
|
-
end # class
|
396
|
+
#### NullOperation
|
289
397
|
|
290
|
-
|
291
|
-
# - If the number is even, divide it by 2.
|
292
|
-
# - If the number is odd, multiply it by 3 and add 1.
|
293
|
-
collatz_function =
|
294
|
-
EvenFunction.new.
|
295
|
-
then(DivideFunction.new(2)).
|
296
|
-
else(MultiplyFunction.new(3).chain(AddFunction.new(1)))
|
398
|
+
require 'cuprum/built_in/null_operation'
|
297
399
|
|
298
|
-
|
299
|
-
result.value #=> 16
|
400
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FNullOperation)
|
300
401
|
|
301
|
-
|
302
|
-
result.value #=> 8
|
402
|
+
A pregenerated operation that does nothing when called. Accepts any arguments.
|
303
403
|
|
304
|
-
|
404
|
+
```ruby
|
405
|
+
operation = Cuprum::BuiltIn::NullOperation.new.call
|
406
|
+
operation.value #=> nil
|
407
|
+
operation.success? #=> true
|
408
|
+
```
|
305
409
|
|
306
|
-
|
410
|
+
## Reference
|
307
411
|
|
308
|
-
|
309
|
-
Cuprum::Function.new do |value|
|
310
|
-
halt!
|
412
|
+
### Cuprum::BuiltIn::IdentityCommand
|
311
413
|
|
312
|
-
|
313
|
-
end # function
|
414
|
+
require 'cuprum/built_in/identity_command'
|
314
415
|
|
315
|
-
|
316
|
-
double_function.
|
317
|
-
then(panic_function).
|
318
|
-
then(AddFunction.new(1)). #=> This is never executed.
|
319
|
-
chain(:on => :always) { |count| puts "There are #{count} lights!" }.
|
320
|
-
call(2)
|
321
|
-
#=> Writes "There are 4 lights!" to STDOUT.
|
416
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FIdentityCommand)
|
322
417
|
|
323
|
-
|
324
|
-
result.halted? #=> true
|
418
|
+
Cuprum::BuiltIn::IdentityCommand defines the following methods:
|
325
419
|
|
326
|
-
|
420
|
+
#### `#call`
|
327
421
|
|
328
|
-
|
422
|
+
call(value) #=> Cuprum::Result
|
329
423
|
|
330
|
-
|
424
|
+
Returns a result, whose `#value` is equal to the given value.
|
331
425
|
|
332
|
-
|
426
|
+
### Cuprum::BuiltIn::IdentityOperation
|
333
427
|
|
334
|
-
|
428
|
+
require 'cuprum/built_in/identity_operation'
|
335
429
|
|
336
|
-
|
337
|
-
def process
|
338
|
-
# Implementation here.
|
339
|
-
end # method process
|
340
|
-
end # class
|
430
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FIdentityOperation)
|
341
431
|
|
342
|
-
|
343
|
-
operation = CreateBookOperation.new.call(book_params)
|
432
|
+
Cuprum::BuiltIn::IdentityOperation defines the following methods:
|
344
433
|
|
345
|
-
|
346
|
-
redirect_to(operation.value)
|
347
|
-
else
|
348
|
-
@book = operation.value
|
434
|
+
#### `#call`
|
349
435
|
|
350
|
-
|
351
|
-
end # if-else
|
352
|
-
end # create
|
436
|
+
call(value) #=> Cuprum::BuiltIn::IdentityOperation
|
353
437
|
|
354
|
-
|
438
|
+
Sets the last result to a new result, whose `#value` is equal to the given value.
|
355
439
|
|
356
|
-
|
440
|
+
### Cuprum::BuiltIn::NullCommand
|
357
441
|
|
358
|
-
|
442
|
+
require 'cuprum/built_in/null_command'
|
359
443
|
|
360
|
-
|
444
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FNullCommand)
|
361
445
|
|
362
|
-
|
446
|
+
Cuprum::BuiltIn::NullCommand defines the following methods:
|
363
447
|
|
364
|
-
|
448
|
+
#### `#call`
|
365
449
|
|
366
|
-
|
450
|
+
call(*args, **keywords) { ... } #=> Cuprum::Result
|
367
451
|
|
368
|
-
|
452
|
+
Returns a result with nil value. Any arguments or keywords are ignored.
|
369
453
|
|
370
|
-
|
454
|
+
### Cuprum::BuiltIn::NullOperation
|
371
455
|
|
372
|
-
|
456
|
+
require 'cuprum/built_in/null_operation'
|
373
457
|
|
374
|
-
|
458
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FBuiltIn%2FNullOperation)
|
375
459
|
|
376
|
-
|
460
|
+
Cuprum::BuiltIn::NullOperation defines the following methods:
|
377
461
|
|
378
|
-
#### `#
|
462
|
+
#### `#call`
|
379
463
|
|
380
|
-
|
464
|
+
call(*args, **keywords) { ... } #=> Cuprum::BuiltIn::NullOperation
|
381
465
|
|
382
|
-
|
466
|
+
Sets the last result to a result with nil value. Any arguments or keywords are ignored.
|
383
467
|
|
384
|
-
|
468
|
+
### Cuprum::Command
|
385
469
|
|
386
|
-
|
470
|
+
require 'cuprum'
|
387
471
|
|
388
|
-
[
|
472
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FCommand)
|
389
473
|
|
390
|
-
|
474
|
+
A Cuprum::Command defines the following methods:
|
391
475
|
|
392
|
-
|
476
|
+
#### `#initialize`
|
393
477
|
|
394
|
-
|
478
|
+
initialize { |*arguments, **keywords, &block| ... } #=> Cuprum::Command
|
395
479
|
|
396
|
-
|
480
|
+
Returns a new instance of Cuprum::Command. If a block is given, the `#call` method will wrap the block and set the result `#value` to the return value of the block. This overrides the implementation in `#process`, if any.
|
397
481
|
|
398
|
-
|
399
|
-
result = Cuprum::Result.new(value)
|
482
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#initialize-instance_method)
|
400
483
|
|
401
|
-
|
402
|
-
#=> 'A result value'
|
484
|
+
#### `#build_errors`
|
403
485
|
|
404
|
-
|
486
|
+
*(Private Method)*
|
405
487
|
|
406
|
-
|
488
|
+
build_errors() #=> Array
|
407
489
|
|
408
|
-
|
490
|
+
Generates an empty errors object. When the command is called, the result will have its `#errors` property initialized to the value returned by `#build_errors`. By default, this is an array. If you want to use a custom errors object type, override this method in a subclass.
|
409
491
|
|
410
|
-
|
492
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#build_errors-instance_method)
|
411
493
|
|
412
|
-
|
494
|
+
#### #call
|
413
495
|
|
414
|
-
|
496
|
+
call(*arguments, **keywords) { ... } #=> Cuprum::Result
|
497
|
+
|
498
|
+
Executes the logic encoded in the constructor block, or the #process method if no block was passed to the constructor.
|
499
|
+
|
500
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#call-instance_method)
|
501
|
+
|
502
|
+
#### #chain
|
503
|
+
|
504
|
+
chain(on: nil) { |result| ... } #=> Cuprum::Command
|
505
|
+
|
506
|
+
Registers a command or block to run after the current command, or after the last chained command if the current command already has one or more chained command(s). This creates and modifies a copy of the current command. See Chaining Commands, below.
|
507
|
+
|
508
|
+
chain(command, on: nil) #=> Cuprum::Command
|
509
|
+
|
510
|
+
The command will be passed the `#value` of the previous command result as its parameter, and the result of the chained command will be returned (or passed to the next chained command, if any).
|
511
|
+
|
512
|
+
The block will be passed the #result of the previous command as its parameter. If your use case depends on the status of the previous command or on any errors generated, use the block form of #chain.
|
513
|
+
|
514
|
+
If the block returns a Cuprum::Result (or an object responding to #value and #success?), the block result will be returned (or passed to the next chained command, if any). If the block returns any other value (including nil), the #result of the previous command will be returned or passed to the next command.
|
515
|
+
|
516
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#chain-instance_method)
|
517
|
+
|
518
|
+
#### `#else`
|
519
|
+
|
520
|
+
else(command) #=> Cuprum::Command
|
521
|
+
|
522
|
+
Shorthand for `command.chain(:on => :failure)`. Registers a command or block to run after the current command. The chained command will only run if the previous command was unsuccessfully run.
|
523
|
+
|
524
|
+
The command will be passed the `#value` of the previous command result as its parameter, and the result of the chained command will be returned (or passed to the next chained command, if any).
|
525
|
+
|
526
|
+
else() { |result| ... } #=> Cuprum::Command
|
527
|
+
|
528
|
+
The block will be passed the #result of the previous command as its parameter. If your use case depends on the status of the previous command or on any errors generated, use the block form of #chain.
|
529
|
+
|
530
|
+
If the block returns a Cuprum::Result (or an object responding to #value and #success?), the block result will be returned (or passed to the next chained command, if any). If the block returns any other value (including nil), the #result of the previous command will be returned or passed to the next command.
|
531
|
+
|
532
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#else-instance_method)
|
415
533
|
|
416
534
|
#### `#errors`
|
417
535
|
|
536
|
+
*(Private Method)*
|
537
|
+
|
418
538
|
errors() #=> Array
|
419
539
|
|
420
|
-
|
540
|
+
Only available while the Command is being called. Provides access to the errors object of the generated Cuprum::Result, which is by default an instance of Array.
|
421
541
|
|
422
|
-
|
542
|
+
Inside of the Command block or the `#process` method, you can add errors to the result.
|
423
543
|
|
424
|
-
|
544
|
+
command =
|
545
|
+
Cuprum::Command.new do
|
546
|
+
errors << "I'm sorry, something went wrong."
|
425
547
|
|
426
|
-
|
548
|
+
nil
|
549
|
+
end # command
|
427
550
|
|
428
|
-
|
551
|
+
result = command.call
|
552
|
+
result.failure?
|
553
|
+
#=> true
|
554
|
+
result.errors
|
555
|
+
#=> ["I'm sorry, something went wrong."]
|
429
556
|
|
430
|
-
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/
|
557
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#errors-instance_method)
|
431
558
|
|
432
|
-
#### `#failure
|
559
|
+
#### `#failure!`
|
433
560
|
|
434
|
-
failure
|
561
|
+
failure!() #=> NilClass
|
435
562
|
|
436
|
-
|
563
|
+
*(Private Method)*
|
437
564
|
|
438
|
-
|
565
|
+
Only available while the Command is being called. If called, marks the result object as failing, even if the result does not have errors.
|
566
|
+
|
567
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#failure!-instance_method)
|
568
|
+
|
569
|
+
#### `#halt!`
|
570
|
+
|
571
|
+
halt!() #=> NilClass
|
572
|
+
|
573
|
+
*(Private Method)*
|
574
|
+
|
575
|
+
Only available while the Command is being called. If called, halts the command chain (see Chaining Commands, below). Subsequent chained commands will not be called unless they were chained with the `:on => :always` option.
|
576
|
+
|
577
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#halt!-instance_method)
|
578
|
+
|
579
|
+
#### `#success!`
|
580
|
+
|
581
|
+
success!() #=> NilClass
|
582
|
+
|
583
|
+
*(Private Method)*
|
584
|
+
|
585
|
+
Only available while the Command is being called. If called, marks the result object as passing, even if the result has errors.
|
586
|
+
|
587
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#success!-instance_method)
|
588
|
+
|
589
|
+
#### `#then`
|
590
|
+
|
591
|
+
then(command) #=> Cuprum::Command
|
592
|
+
|
593
|
+
Shorthand for `command.chain(:on => :success)`. Registers a command or block to run after the current command. The chained command will only run if the previous command was successfully run.
|
594
|
+
|
595
|
+
The command will be passed the `#value` of the previous command result as its parameter, and the result of the chained command will be returned (or passed to the next chained command, if any).
|
596
|
+
|
597
|
+
then() { |result| ... } #=> Cuprum::Command
|
598
|
+
|
599
|
+
The block will be passed the #result of the previous command as its parameter. If your use case depends on the status of the previous command or on any errors generated, use the block form of #chain.
|
600
|
+
|
601
|
+
If the block returns a Cuprum::Result (or an object responding to #value and #success?), the block result will be returned (or passed to the next chained command, if any). If the block returns any other value (including nil), the #result of the previous command will be returned or passed to the next command.
|
602
|
+
|
603
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Command#then-instance_method)
|
604
|
+
|
605
|
+
### Cuprum::Operation
|
606
|
+
|
607
|
+
require 'cuprum'
|
608
|
+
|
609
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FOperation)
|
610
|
+
|
611
|
+
A Cuprum::Operation inherits the methods from Cuprum::Command (see above), and defines the following additional methods:
|
612
|
+
|
613
|
+
#### `#called?`
|
614
|
+
|
615
|
+
called?() #=> true, false
|
616
|
+
|
617
|
+
True if the operation has been called and there is a result available by calling `#result` or one of the delegated methods, otherwise false.
|
618
|
+
|
619
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Operation#called%3F-instance_method)
|
620
|
+
|
621
|
+
#### `#reset!`
|
622
|
+
|
623
|
+
reset!()
|
624
|
+
|
625
|
+
Clears the most recent result and resets `#called?` to false. This frees the result and any linked data for garbage collection. It also clears any internal state from the operation.
|
626
|
+
|
627
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Operation#reset!-instance_method)
|
628
|
+
|
629
|
+
#### `#result`
|
630
|
+
|
631
|
+
result() #=> Cuprum::Result
|
632
|
+
|
633
|
+
The most recent result, from the previous time `#call` was executed for the operation.
|
634
|
+
|
635
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Operation#result-instance_method)
|
636
|
+
|
637
|
+
### Cuprum::Result
|
638
|
+
|
639
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FResult)
|
640
|
+
|
641
|
+
A Cuprum::Result defines the following methods:
|
439
642
|
|
440
643
|
#### `#==`
|
441
644
|
|
@@ -449,118 +652,114 @@ Performs a fuzzy comparison with the other object. At a minimum, the other objec
|
|
449
652
|
|
450
653
|
Helper method that returns true for a new result. The method returns false if `result.value` is not nil, if `result.errors` is not empty, if the status has been manually set with `#success!` or `#failure!`, or if the result has been halted.
|
451
654
|
|
452
|
-
|
655
|
+
#### `#errors`
|
453
656
|
|
454
|
-
|
657
|
+
errors() #=> Array
|
455
658
|
|
456
|
-
|
659
|
+
The errors generated by the command, or an empty array if no errors were generated.
|
457
660
|
|
458
|
-
|
661
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Result#errors-instance_method)
|
459
662
|
|
460
|
-
|
663
|
+
#### `#failure!`
|
461
664
|
|
462
|
-
|
665
|
+
failure!() #=> Cuprum::Result
|
463
666
|
|
464
|
-
|
667
|
+
Marks the result as failing and returns the result. Calling `#failure?` will return true, even if the result has no errors.
|
465
668
|
|
466
|
-
|
467
|
-
spy_on(function_class) { |spy| ... } #=> nil
|
669
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Result#failure!-instance_method)
|
468
670
|
|
469
|
-
|
671
|
+
#### `#failure?`
|
470
672
|
|
471
|
-
|
472
|
-
spy = Cuprum::Utils::InstanceSpy.spy_on(CustomFunction)
|
673
|
+
failure?() #=> true, false
|
473
674
|
|
474
|
-
|
675
|
+
True if the command generated one or more errors or was marked as failing. Otherwise false.
|
475
676
|
|
476
|
-
|
677
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Result#failure%3F-instance_method)
|
477
678
|
|
478
|
-
|
479
|
-
spy = Cuprum::Utils::InstanceSpy.spy_on(ChainedFunction)
|
679
|
+
#### `#halt!`
|
480
680
|
|
481
|
-
|
681
|
+
halt!() #=> Cuprum::Result
|
482
682
|
|
483
|
-
|
484
|
-
chain { |result| ChainedFunction.new.call(result) }.
|
485
|
-
call
|
683
|
+
Marks the result as halted and returns the result. Calling `#halted?` will return true.
|
486
684
|
|
487
|
-
|
488
|
-
Cuprum::Utils::InstanceSpy.spy_on(CustomFunction) do |spy|
|
489
|
-
expect(spy).to receive(:call)
|
685
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Result#halt!-instance_method)
|
490
686
|
|
491
|
-
|
492
|
-
end # spy_on
|
687
|
+
#### `#halted?`
|
493
688
|
|
494
|
-
|
689
|
+
halted?() #=> true, false
|
495
690
|
|
496
|
-
|
691
|
+
True if the result is halted, which prevents chained commands from executing.
|
497
692
|
|
498
|
-
|
693
|
+
#### `#success!`
|
499
694
|
|
500
|
-
|
695
|
+
success!() #=> Cuprum::Result
|
501
696
|
|
502
|
-
|
697
|
+
Marks the result as passing and returns the result. Calling `#success?` will return true, even if the result has errors.
|
503
698
|
|
504
|
-
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/
|
699
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Result#success!-instance_method)
|
505
700
|
|
506
|
-
|
701
|
+
#### `#success?`
|
507
702
|
|
508
|
-
|
703
|
+
success?() #=> true, false
|
509
704
|
|
510
|
-
|
705
|
+
True if the command did not generate any errors, or the result has errors but was marked as passing. Otherwise false.
|
511
706
|
|
512
|
-
|
707
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Result#success%3F-instance_method)
|
513
708
|
|
514
|
-
|
709
|
+
#### `#value`
|
515
710
|
|
516
|
-
|
711
|
+
value() #=> Object
|
517
712
|
|
518
|
-
|
519
|
-
result = function.call('expected value')
|
520
|
-
result.value
|
521
|
-
#=> 'expected value'
|
522
|
-
result.success?
|
523
|
-
#=> true
|
713
|
+
The value returned by the command. For example, for an increment command that added 1 to a given integer, the `#value` of the result object would be the incremented integer.
|
524
714
|
|
525
|
-
|
715
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Result#value-instance_method)
|
526
716
|
|
527
|
-
|
717
|
+
### Cuprum::Utilities::InstanceSpy
|
528
718
|
|
529
|
-
|
719
|
+
require 'cuprum/utils/instance_spy'
|
530
720
|
|
531
|
-
|
721
|
+
[Class Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum%2FUtils%2FInstanceSpy)
|
532
722
|
|
533
|
-
|
534
|
-
operation.value
|
535
|
-
#=> 'expected value'
|
536
|
-
operation.success?
|
537
|
-
#=> true
|
723
|
+
Utility module for instrumenting calls to the #call method of any instance of a command class. This can be used to unobtrusively test the functionality of code that calls a command without providing a reference to the command instance, such as chained commands or methods that create and call a command instance.
|
538
724
|
|
539
|
-
|
725
|
+
#### `::clear_spies`
|
540
726
|
|
541
|
-
|
727
|
+
clear_spies() #=> nil
|
542
728
|
|
543
|
-
|
729
|
+
Retires all spies. Subsequent calls to the #call method on command instances will not be mirrored to existing spy objects. Calling this method after each test or example that uses an instance spy is recommended.
|
544
730
|
|
545
|
-
|
731
|
+
after(:example) { Cuprum::Utils::InstanceSpy.clear_spies }
|
546
732
|
|
547
|
-
|
548
|
-
result = function.call
|
549
|
-
result.value
|
550
|
-
#=> nil
|
551
|
-
result.success?
|
552
|
-
#=> true
|
733
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Utils/InstanceSpy#clear_spies%3F-instance_method)
|
553
734
|
|
554
|
-
|
735
|
+
#### `::spy_on`
|
555
736
|
|
556
|
-
|
737
|
+
spy_on(command_class) #=> InstanceSpy
|
738
|
+
spy_on(command_class) { |spy| ... } #=> nil
|
557
739
|
|
558
|
-
|
740
|
+
Finds or creates a spy object for the given module or class. Each time that the #call method is called for an object of the given type, the spy's #call method will be invoked with the same arguments and block. If `#spy_on` is called with a block, the instance spy will be yielded to the block; otherwise, the spy will be returned.
|
559
741
|
|
560
|
-
|
742
|
+
# Observing calls to instances of a command.
|
743
|
+
spy = Cuprum::Utils::InstanceSpy.spy_on(CustomCommand)
|
561
744
|
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
745
|
+
expect(spy).to receive(:call).with(1, 2, 3, :four => '4')
|
746
|
+
|
747
|
+
CustomCommand.new.call(1, 2, 3, :four => '4')
|
748
|
+
|
749
|
+
# Observing calls to a chained command.
|
750
|
+
spy = Cuprum::Utils::InstanceSpy.spy_on(ChainedCommand)
|
751
|
+
|
752
|
+
expect(spy).to receive(:call)
|
753
|
+
|
754
|
+
Cuprum::Command.new {}.
|
755
|
+
chain { |result| ChainedCommand.new.call(result) }.
|
756
|
+
call
|
757
|
+
|
758
|
+
# Block syntax
|
759
|
+
Cuprum::Utils::InstanceSpy.spy_on(CustomCommand) do |spy|
|
760
|
+
expect(spy).to receive(:call)
|
761
|
+
|
762
|
+
CustomCommand.new.call
|
763
|
+
end # spy_on
|
764
|
+
|
765
|
+
[Method Documentation](http://www.rubydoc.info/github/sleepingkingstudios/cuprum/master/Cuprum/Utils/InstanceSpy#spy_on%3F-instance_method)
|