cuprum 0.5.0 → 0.6.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 +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
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'cuprum/not_implemented_error'
|
2
|
+
|
3
|
+
module Cuprum
|
4
|
+
# Functional object that encapsulates a business logic operation with a
|
5
|
+
# standardized interface and returns a result object.
|
6
|
+
class BasicCommand
|
7
|
+
# Returns a new instance of Cuprum::BasicCommand.
|
8
|
+
#
|
9
|
+
# @yield [*arguments, **keywords, &block] If a block is given, the
|
10
|
+
# #call method will wrap the block and set the result #value to the return
|
11
|
+
# value of the block. This overrides the implementation in #process, if
|
12
|
+
# any.
|
13
|
+
def initialize &implementation
|
14
|
+
define_singleton_method :process, &implementation if implementation
|
15
|
+
end # method initialize
|
16
|
+
|
17
|
+
# @overload call(*arguments, **keywords, &block)
|
18
|
+
# Executes the logic encoded in the constructor block, or the #process
|
19
|
+
# method if no block was passed to the constructor, and returns a
|
20
|
+
# Cuprum::Result object with the return value of the block or #process,
|
21
|
+
# the success or failure status, and any errors generated.
|
22
|
+
#
|
23
|
+
# @param arguments [Array] Arguments to be passed to the implementation.
|
24
|
+
#
|
25
|
+
# @param keywords [Hash] Keywords to be passed to the implementation.
|
26
|
+
#
|
27
|
+
# @return [Cuprum::Result] The result object for the command.
|
28
|
+
#
|
29
|
+
# @yield If a block argument is given, it will be passed to the
|
30
|
+
# implementation.
|
31
|
+
#
|
32
|
+
# @raise [Cuprum::NotImplementedError] Unless a block was passed to the
|
33
|
+
# constructor or the #process method was overriden by a Command
|
34
|
+
# subclass.
|
35
|
+
def call *args, &block
|
36
|
+
wrap_result { |result| merge_results(result, process(*args, &block)) }
|
37
|
+
end # method call
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @!visibility public
|
42
|
+
#
|
43
|
+
# Generates an empty errors object. When the function is called, the result
|
44
|
+
# will have its #errors property initialized to the value returned by
|
45
|
+
# #build_errors. By default, this is an array. If you want to use a custom
|
46
|
+
# errors object type, override this method in a subclass.
|
47
|
+
#
|
48
|
+
# @return [Array] An empty errors object.
|
49
|
+
def build_errors
|
50
|
+
[]
|
51
|
+
end # method build_errors
|
52
|
+
|
53
|
+
def convert_value_to_result value
|
54
|
+
return nil unless value_is_result?(value)
|
55
|
+
|
56
|
+
if value.respond_to?(:result) && value_is_result?(value.result)
|
57
|
+
return value.result
|
58
|
+
end # if
|
59
|
+
|
60
|
+
value
|
61
|
+
end # method convert_value_to_result
|
62
|
+
|
63
|
+
# @!visibility public
|
64
|
+
#
|
65
|
+
# Provides a reference to the current result's errors object. Messages or
|
66
|
+
# error objects added to this will be included in the #errors method of the
|
67
|
+
# returned result object.
|
68
|
+
#
|
69
|
+
# @return [Array, Object] The errors object.
|
70
|
+
#
|
71
|
+
# @see Cuprum::Result#errors.
|
72
|
+
#
|
73
|
+
# @note This is a private method, and only available when executing the
|
74
|
+
# function implementation as defined in the constructor block or the
|
75
|
+
# #process method.
|
76
|
+
def errors
|
77
|
+
@result&.errors
|
78
|
+
end # method errors
|
79
|
+
|
80
|
+
# @!visibility public
|
81
|
+
#
|
82
|
+
# Marks the current result as failed. Calling #failure? on the returned
|
83
|
+
# result object will evaluate to true, whether or not the result has any
|
84
|
+
# errors.
|
85
|
+
#
|
86
|
+
# @see Cuprum::Result#failure!.
|
87
|
+
#
|
88
|
+
# @note This is a private method, and only available when executing the
|
89
|
+
# function implementation as defined in the constructor block or the
|
90
|
+
# #process method.
|
91
|
+
def failure!
|
92
|
+
@result&.failure!
|
93
|
+
end # method failure!
|
94
|
+
|
95
|
+
# @!visibility public
|
96
|
+
#
|
97
|
+
# Marks the current result as halted.
|
98
|
+
#
|
99
|
+
# @see Cuprum::Result#halt!.
|
100
|
+
#
|
101
|
+
# @note This is a private method, and only available when executing the
|
102
|
+
# function implementation as defined in the constructor block or the
|
103
|
+
# #process method.
|
104
|
+
def halt!
|
105
|
+
@result&.halt!
|
106
|
+
end # method halt!
|
107
|
+
|
108
|
+
# :nocov:
|
109
|
+
def humanize_list list, empty_value: ''
|
110
|
+
return empty_value if list.size.zero?
|
111
|
+
|
112
|
+
return list.first.to_s if list.size == 1
|
113
|
+
|
114
|
+
return "#{list.first} and #{list.last}" if list.size == 2
|
115
|
+
|
116
|
+
"#{list[0...-1].join ', '}, and #{list.last}"
|
117
|
+
end # method humanize_list
|
118
|
+
# :nocov:
|
119
|
+
|
120
|
+
def merge_results result, other
|
121
|
+
if value_is_result?(other)
|
122
|
+
Cuprum.warn(result_not_empty_warning) unless result.empty?
|
123
|
+
|
124
|
+
convert_value_to_result(other)
|
125
|
+
else
|
126
|
+
result.value = other
|
127
|
+
|
128
|
+
result
|
129
|
+
end # if-else
|
130
|
+
end # method merge_results
|
131
|
+
|
132
|
+
# @!visibility public
|
133
|
+
# @overload process(*arguments, **keywords, &block)
|
134
|
+
# The implementation of the function, to be executed when the #call method
|
135
|
+
# is called. Can add errors to or set the status of the result, and the
|
136
|
+
# value of the result will be set to the value returned by #process. Do
|
137
|
+
# not call this method directly.
|
138
|
+
#
|
139
|
+
# @param arguments [Array] The arguments, if any, passed from #call.
|
140
|
+
#
|
141
|
+
# @param keywords [Hash] The keywords, if any, passed from #call.
|
142
|
+
#
|
143
|
+
# @yield The block, if any, passed from #call.
|
144
|
+
#
|
145
|
+
# @return [Object] the value of the result object to be returned by #call.
|
146
|
+
#
|
147
|
+
# @raise [Cuprum::NotImplementedError] Unless a block was passed to the
|
148
|
+
# constructor or the #process method was overriden by a Command
|
149
|
+
# subclass.
|
150
|
+
#
|
151
|
+
# @note This is a private method.
|
152
|
+
def process *_args
|
153
|
+
raise Cuprum::NotImplementedError, nil, caller(1..-1)
|
154
|
+
end # method process
|
155
|
+
|
156
|
+
def result_not_empty_warning # rubocop:disable Metrics/MethodLength
|
157
|
+
warnings = []
|
158
|
+
|
159
|
+
unless @result.errors.empty?
|
160
|
+
warnings << "there were already errors #{@result.errors.inspect}"
|
161
|
+
end # unless
|
162
|
+
|
163
|
+
status = @result.send(:status)
|
164
|
+
unless status.nil?
|
165
|
+
warnings << "the status was set to #{status.inspect}"
|
166
|
+
end # unless
|
167
|
+
|
168
|
+
if @result.halted?
|
169
|
+
warnings << 'the function was halted'
|
170
|
+
end # if
|
171
|
+
|
172
|
+
message = '#process returned a result, but '
|
173
|
+
message <<
|
174
|
+
humanize_list(warnings, :empty_value => 'the result was not empty')
|
175
|
+
|
176
|
+
message
|
177
|
+
end # method result_not_empty_warning
|
178
|
+
|
179
|
+
# @!visibility public
|
180
|
+
#
|
181
|
+
# Marks the current result as passing. Calling #success? on the returned
|
182
|
+
# result object will evaluate to true, whether or not the result has any
|
183
|
+
# errors.
|
184
|
+
#
|
185
|
+
# @see Cuprum::Result#success!.
|
186
|
+
#
|
187
|
+
# @note This is a private method, and only available when executing the
|
188
|
+
# function implementation as defined in the constructor block or the
|
189
|
+
# #process method.
|
190
|
+
def success!
|
191
|
+
@result&.success!
|
192
|
+
end # method success!
|
193
|
+
|
194
|
+
def value_is_result? value
|
195
|
+
value.respond_to?(:value) && value.respond_to?(:success?)
|
196
|
+
end # method value
|
197
|
+
|
198
|
+
def wrap_result
|
199
|
+
result = Cuprum::Result.new(:errors => build_errors)
|
200
|
+
|
201
|
+
begin
|
202
|
+
@result = result
|
203
|
+
|
204
|
+
result = yield result
|
205
|
+
ensure
|
206
|
+
@result = nil
|
207
|
+
end # begin-ensure
|
208
|
+
|
209
|
+
result
|
210
|
+
end # method wrap_result
|
211
|
+
end # class
|
212
|
+
end # module
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'cuprum/built_in'
|
2
|
-
require 'cuprum/
|
2
|
+
require 'cuprum/command'
|
3
3
|
|
4
4
|
module Cuprum::BuiltIn
|
5
5
|
# A predefined function that returns the value or result it was called with.
|
6
6
|
#
|
7
7
|
# @example With a value.
|
8
|
-
# result =
|
8
|
+
# result = IdentityCommand.new.call('custom value')
|
9
9
|
# result.value
|
10
10
|
# #=> 'custom value'
|
11
11
|
# result.success?
|
@@ -14,14 +14,14 @@ module Cuprum::BuiltIn
|
|
14
14
|
# @example With a result.
|
15
15
|
# errors = ['errors.messages.unknown']
|
16
16
|
# value = Cuprum::Result.new('result value', :errors => errors)
|
17
|
-
# result =
|
17
|
+
# result = IdentityCommand.new.call(value)
|
18
18
|
# result.value
|
19
19
|
# #=> 'result value'
|
20
20
|
# result.success?
|
21
21
|
# #=> false
|
22
22
|
# result.errors
|
23
23
|
# #=> ['errors.messages.unknown']
|
24
|
-
class
|
24
|
+
class IdentityCommand < Cuprum::Command
|
25
25
|
private
|
26
26
|
|
27
27
|
def process value = nil
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'cuprum/built_in/
|
1
|
+
require 'cuprum/built_in/identity_command'
|
2
2
|
require 'cuprum/operation'
|
3
3
|
|
4
4
|
module Cuprum::BuiltIn
|
@@ -21,7 +21,7 @@ module Cuprum::BuiltIn
|
|
21
21
|
# #=> false
|
22
22
|
# operation.errors
|
23
23
|
# #=> ['errors.messages.unknown']
|
24
|
-
class IdentityOperation < Cuprum::BuiltIn::
|
24
|
+
class IdentityOperation < Cuprum::BuiltIn::IdentityCommand
|
25
25
|
include Cuprum::Operation::Mixin
|
26
26
|
end # class
|
27
27
|
end # module
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'cuprum/built_in'
|
2
|
-
require 'cuprum/
|
2
|
+
require 'cuprum/command'
|
3
3
|
|
4
4
|
module Cuprum::BuiltIn
|
5
|
-
# A predefined
|
5
|
+
# A predefined command that does nothing when called.
|
6
6
|
#
|
7
7
|
# @example
|
8
|
-
# result =
|
8
|
+
# result = NullCommand.new.call
|
9
9
|
# result.value
|
10
10
|
# #=> nil
|
11
11
|
# result.success?
|
12
12
|
# #=> true
|
13
|
-
class
|
13
|
+
class NullCommand < Cuprum::Command
|
14
14
|
private
|
15
15
|
|
16
16
|
def process *_args; end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'cuprum/built_in/
|
1
|
+
require 'cuprum/built_in/null_command'
|
2
2
|
require 'cuprum/operation'
|
3
3
|
|
4
4
|
module Cuprum::BuiltIn
|
@@ -10,7 +10,7 @@ module Cuprum::BuiltIn
|
|
10
10
|
# #=> nil
|
11
11
|
# operation.success?
|
12
12
|
# #=> true
|
13
|
-
class NullOperation < Cuprum::BuiltIn::
|
13
|
+
class NullOperation < Cuprum::BuiltIn::NullCommand
|
14
14
|
include Cuprum::Operation::Mixin
|
15
15
|
end # class
|
16
16
|
end # module
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'cuprum'
|
2
|
+
|
3
|
+
module Cuprum
|
4
|
+
# Mixin to implement command chaining functionality for a command class.
|
5
|
+
# Chaining commands allows you to define complex logic by composing it from
|
6
|
+
# simpler commands, including branching logic and error handling.
|
7
|
+
#
|
8
|
+
# @see Cuprum::Command
|
9
|
+
module Chaining
|
10
|
+
# (see Cuprum::BasicCommand#call)
|
11
|
+
def call *args, &block
|
12
|
+
call_chained_functions(super)
|
13
|
+
end # method call
|
14
|
+
|
15
|
+
# Registers a function or block to run after the current function, or after
|
16
|
+
# the last chained function if the current function already has one or more
|
17
|
+
# chained function(s). This creates and modifies a copy of the current
|
18
|
+
# function.
|
19
|
+
#
|
20
|
+
# @param on [Symbol] Sets a condition on when the chained function can run,
|
21
|
+
# based on the status of the previous function. Valid values are :success,
|
22
|
+
# :failure, and :always. A value of :success will constrain the function
|
23
|
+
# to run only if the previous function succeeded. A value of :failure will
|
24
|
+
# constrain the function to run only if the previous function failed. A
|
25
|
+
# value of :always will ensure the function is always run, even if the
|
26
|
+
# function chain has been halted. If no value is given, the function will
|
27
|
+
# run whether the previous function was a success or a failure, but not if
|
28
|
+
# the function chain has been halted.
|
29
|
+
#
|
30
|
+
# @overload chain(function, on: nil)
|
31
|
+
# The function will be passed the #value of the previous function result
|
32
|
+
# as its parameter, and the result of the chained function will be
|
33
|
+
# returned (or passed to the next chained function, if any).
|
34
|
+
#
|
35
|
+
# @param function [Cuprum::Command] The function to call after the
|
36
|
+
# current or last chained function.
|
37
|
+
#
|
38
|
+
# @overload chain(on: :nil, &block)
|
39
|
+
# The block will be passed the #result of the previous function as its
|
40
|
+
# parameter. If your use case depends on the status of the previous
|
41
|
+
# function or on any errors generated, use the block form of #chain.
|
42
|
+
#
|
43
|
+
# If the block returns a Cuprum::Result (or an object responding to #value
|
44
|
+
# and #success?), the block result will be returned (or passed to the next
|
45
|
+
# chained function, if any). If the block returns any other value
|
46
|
+
# (including nil), the #result of the previous function will be returned
|
47
|
+
# or passed to the next function.
|
48
|
+
#
|
49
|
+
# @yieldparam result [Cuprum::Result] The #result of the previous
|
50
|
+
# function.
|
51
|
+
#
|
52
|
+
# @return [Cuprum::Command] The chained function.
|
53
|
+
def chain function = nil, on: nil, &block
|
54
|
+
clone.tap do |fn|
|
55
|
+
fn.chained_functions <<
|
56
|
+
{
|
57
|
+
:proc => convert_function_or_proc_to_proc(block || function),
|
58
|
+
:on => on
|
59
|
+
} # end hash
|
60
|
+
end # tap
|
61
|
+
end # method chain
|
62
|
+
|
63
|
+
# Shorthand for function.chain(:on => :failure). Registers a function or
|
64
|
+
# block to run after the current function. The chained function will only
|
65
|
+
# run if the previous function was unsuccessfully run.
|
66
|
+
#
|
67
|
+
# @overload else(function)
|
68
|
+
#
|
69
|
+
# @param function [Cuprum::Command] The function to call after the
|
70
|
+
# current or last chained function.
|
71
|
+
#
|
72
|
+
# @overload else(&block)
|
73
|
+
#
|
74
|
+
# @yieldparam result [Cuprum::Result] The #result of the previous
|
75
|
+
# function.
|
76
|
+
#
|
77
|
+
# @return [Cuprum::Command] The chained function.
|
78
|
+
#
|
79
|
+
# @see #chain
|
80
|
+
def else function = nil, &block
|
81
|
+
chain(function, :on => :failure, &block)
|
82
|
+
end # method else
|
83
|
+
|
84
|
+
# Shorthand for function.chain(:on => :success). Registers a function or
|
85
|
+
# block to run after the current function. The chained function will only
|
86
|
+
# run if the previous function was successfully run.
|
87
|
+
#
|
88
|
+
# @overload then(function)
|
89
|
+
#
|
90
|
+
# @param function [Cuprum::Command] The function to call after the
|
91
|
+
# current or last chained function.
|
92
|
+
#
|
93
|
+
# @overload then(&block)
|
94
|
+
#
|
95
|
+
# @yieldparam result [Cuprum::Result] The #result of the previous
|
96
|
+
# function.
|
97
|
+
#
|
98
|
+
# @return [Cuprum::Command] The chained function.
|
99
|
+
#
|
100
|
+
# @see #chain
|
101
|
+
def then function = nil, &block
|
102
|
+
chain(function, :on => :success, &block)
|
103
|
+
end # method then
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
107
|
+
def chained_functions
|
108
|
+
@chained_functions ||= []
|
109
|
+
end # method chained_functions
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def call_chained_functions first_result
|
114
|
+
chained_functions.reduce(first_result) do |result, hsh|
|
115
|
+
next result if skip_chained_function?(result, :on => hsh[:on])
|
116
|
+
|
117
|
+
value = hsh.fetch(:proc).call(result)
|
118
|
+
|
119
|
+
convert_value_to_result(value) || result
|
120
|
+
end # reduce
|
121
|
+
end # method call_chained_functions
|
122
|
+
|
123
|
+
def convert_function_or_proc_to_proc function_or_proc
|
124
|
+
return function_or_proc if function_or_proc.is_a?(Proc)
|
125
|
+
|
126
|
+
->(result) { function_or_proc.call(result) }
|
127
|
+
end # method convert_function_or_proc_to_proc
|
128
|
+
|
129
|
+
def skip_chained_function? last_result, on:
|
130
|
+
return false if on == :always
|
131
|
+
|
132
|
+
return true if last_result.respond_to?(:halted?) && last_result.halted?
|
133
|
+
|
134
|
+
case on
|
135
|
+
when :success
|
136
|
+
!last_result.success?
|
137
|
+
when :failure
|
138
|
+
!last_result.failure?
|
139
|
+
end # case
|
140
|
+
end # method skip_chained_function?
|
141
|
+
end # module
|
142
|
+
end # modue
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'cuprum/basic_command'
|
2
|
+
require 'cuprum/chaining'
|
3
|
+
require 'cuprum/not_implemented_error'
|
4
|
+
require 'cuprum/result'
|
5
|
+
|
6
|
+
module Cuprum
|
7
|
+
# Functional object that encapsulates a business logic operation with a
|
8
|
+
# consistent interface and tracking of result value and status.
|
9
|
+
#
|
10
|
+
# A Command can be defined either by passing a block to the constructor, or
|
11
|
+
# by defining a subclass of Command and implementing the #process method.
|
12
|
+
#
|
13
|
+
# @example A Command with a block
|
14
|
+
# double_function = Cuprum::Command.new { |int| 2 * int }
|
15
|
+
# result = double_function.call(5)
|
16
|
+
#
|
17
|
+
# result.value #=> 10
|
18
|
+
#
|
19
|
+
# @example A Command subclass
|
20
|
+
# class MultiplyCommand < Cuprum::Command
|
21
|
+
# def initialize multiplier
|
22
|
+
# @multiplier = multiplier
|
23
|
+
# end # constructor
|
24
|
+
#
|
25
|
+
# private
|
26
|
+
#
|
27
|
+
# def process int
|
28
|
+
# int * @multiplier
|
29
|
+
# end # method process
|
30
|
+
# end # class
|
31
|
+
#
|
32
|
+
# triple_function = MultiplyCommand.new(3)
|
33
|
+
# result = triple_function.call(5)
|
34
|
+
#
|
35
|
+
# result.value #=> 15
|
36
|
+
#
|
37
|
+
# @example A Command with errors
|
38
|
+
# class DivideCommand < Cuprum::Command
|
39
|
+
# def initialize divisor
|
40
|
+
# @divisor = divisor
|
41
|
+
# end # constructor
|
42
|
+
#
|
43
|
+
# private
|
44
|
+
#
|
45
|
+
# def process int
|
46
|
+
# if @divisor.zero?
|
47
|
+
# errors << 'errors.messages.divide_by_zero'
|
48
|
+
#
|
49
|
+
# return
|
50
|
+
# end # if
|
51
|
+
#
|
52
|
+
# int / @divisor
|
53
|
+
# end # method process
|
54
|
+
# end # class
|
55
|
+
#
|
56
|
+
# halve_function = DivideCommand.new(2)
|
57
|
+
# result = halve_function.call(10)
|
58
|
+
#
|
59
|
+
# result.errors #=> []
|
60
|
+
# result.value #=> 5
|
61
|
+
#
|
62
|
+
# function_with_errors = DivideCommand.new(0)
|
63
|
+
# result = function_with_errors.call(10)
|
64
|
+
#
|
65
|
+
# result.errors #=> ['errors.messages.divide_by_zero']
|
66
|
+
# result.value #=> nil
|
67
|
+
#
|
68
|
+
# @example Command Chaining
|
69
|
+
# class AddCommand < Cuprum::Command
|
70
|
+
# def initialize addend
|
71
|
+
# @addend = addend
|
72
|
+
# end # constructor
|
73
|
+
#
|
74
|
+
# private
|
75
|
+
#
|
76
|
+
# def process int
|
77
|
+
# int + @addend
|
78
|
+
# end # method process
|
79
|
+
# end # class
|
80
|
+
#
|
81
|
+
# double_and_add_one = MultiplyCommand.new(2).chain(AddCommand.new(1))
|
82
|
+
# result = double_and_add_one(5)
|
83
|
+
#
|
84
|
+
# result.value #=> 5
|
85
|
+
#
|
86
|
+
# @example Conditional Chaining With #then And #else
|
87
|
+
# class EvenCommand < Cuprum::Command
|
88
|
+
# private
|
89
|
+
#
|
90
|
+
# def process int
|
91
|
+
# errors << 'errors.messages.not_even' unless int.even?
|
92
|
+
#
|
93
|
+
# int
|
94
|
+
# end # method process
|
95
|
+
# end # class
|
96
|
+
#
|
97
|
+
# # The next step in a Collatz sequence is determined as follows:
|
98
|
+
# # - If the number is even, divide it by 2.
|
99
|
+
# # - If the number is odd, multiply it by 3 and add 1.
|
100
|
+
# collatz_function =
|
101
|
+
# EvenCommand.new.
|
102
|
+
# then(DivideCommand.new(2)).
|
103
|
+
# else(MultiplyCommand.new(3).chain(AddCommand.new(1)))
|
104
|
+
#
|
105
|
+
# result = collatz_function.new(5)
|
106
|
+
# result.value #=> 16
|
107
|
+
#
|
108
|
+
# result = collatz_function.new(16)
|
109
|
+
# result.value #=> 8
|
110
|
+
class Command < Cuprum::BasicCommand
|
111
|
+
include Cuprum::Chaining
|
112
|
+
end # class
|
113
|
+
end # module
|