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.
A CurriedCommand wraps another command and passes preset params to #call.
Currying Arguments
# Our base command takes two arguments.
say_command = Cuprum::Command.new do |greeting, person|
"#{greeting}, #{person}!"
end
say_command.call('Hello', 'world')
#=> returns a result with value 'Hello, world!'
# Next, we create a curried command. This sets the first argument to
# always be 'Greetings', so our curried command only takes one argument,
# namely the name of the person being greeted.
greet_command =
Cuprum::CurriedCommand.new(
arguments: ['Greetings'],
command: say_command
)
greet_command.call('programs')
#=> returns a result with value 'Greetings, programs!'
# Here, we are creating a curried command that passes both arguments.
# Therefore, our curried command does not take any arguments.
recruit_command =
Cuprum::CurriedCommand.new(
arguments: ['Greetings', 'starfighter'],
command: say_command
)
recruit_command.call
#=> returns a result with value 'Greetings, starfighter!'Currying Keywords
# Our base command takes two keywords: a math operation and an array of
# integers.
math_command = Cuprum::Command.new do |operands:, operation:|
operations.reduce(&operation)
end
math_command.call(operands: [2, 2], operation: :+)
#=> returns a result with value 4
# Our curried command still takes two keywords, but now the operation
# keyword is optional. It now defaults to :*, for multiplication.
multiply_command =
Cuprum::CurriedCommand.new(
command: math_command,
keywords: { operation: :* }
)
multiply_command.call(operands: [3, 3])
#=> returns a result with value 9.subclass(*class_arguments, **class_keywords, &block) => Class
Creates a subclass with partially applied constructor parameters.
#initialize(command:, arguments: [], block: nil, keywords: {}) => CurriedCommand
#arguments => Array (readonly)
#block => Proc, nil (readonly)
#command => Cuprum::Command (readonly)
#keywords => Hash (readonly)
#arity => Integer
Returns an indication of the number of arguments accepted by #call.
If the method takes a fixed number N of arguments, returns N. If the method takes a variable number of arguments, returns -N-1, where N is the number of required arguments. Keyword arguments will be considered as a single additional argument, that argument being mandatory if any keyword argument is mandatory.
#call(*args, **kwargs) => Cuprum::Result
Merges the arguments and keywords and calls the wrapped command.
First, the arguments array is created starting with the :arguments passed to #initialize. Any positional arguments passed directly to #call are then appended.
Second, the keyword arguments are created by merging the keywords passed directly into #call into the keywods passed to #initialize. This means that if a key is passed in both places, the value passed into #call will take precedence.
Finally, the merged arguments and keywords are passed into the original command’s #call method.
#curry(*arguments, **keywords, &block) => Cuprum::Currying::CurriedCommand
Returns a CurriedCommand that wraps this command with pre-set arguments.
When the curried command is called, the predefined arguments and/or keywords will be combined with the arguments passed to #call.
The original command is unchanged.
#step => Object
Executes the block and returns the value, or halts on a failure.
The #step method is used to evaluate a sequence of processes, and to fail fast and halt processing if any of the steps returns a failing result. Each invocation of #step should be wrapped in a #steps block, or used inside the #process method of a Command.
If the object returned by the block is a Cuprum result or compatible object (such as a called operation), the value is converted to a Cuprum result via the #to_cuprum_result method. Otherwise, the object is returned directly from #step.
If the returned object is a passing result, the #value of the result is returned by #step.
If the returned object is a failing result, then #step will throw :cuprum_failed_result and the failing result. This is caught by the #steps block, and halts execution of any subsequent steps.
Calling a Step
# The #do_something method returns the string 'some value'.
step { do_something() } #=> 'some value'
value = step { do_something() }
value #=> 'some value'Calling a Step with a Passing Result
# The #do_something_else method returns a Cuprum result with a value
# of 'another value'.
step { do_something_else() } #=> 'another value'
# The result is passing, so the value is extracted and returned.
value = step { do_something_else() }
value #=> 'another value'Calling a Step with a Failing Result
# The #do_something_wrong method returns a failing Cuprum result.
step { do_something_wrong() } # Throws the :cuprum_failed_step symbol.#steps(&block) => Cuprum::Result
Returns the first failing #step result, or the final result if none fail.
The #steps method is used to wrap a series of #step calls. Each step is executed in sequence. If any of the steps returns a failing result, that result is immediately returned from #steps. Otherwise, #steps wraps the value returned by a block in a Cuprum result.
With A Passing Step
result = steps do
step { success('some value') }
end
result.class #=> Cuprum::Result
result.success? #=> true
result.value #=> 'some value'With A Failing Step
result = steps do
step { failure('something went wrong') }
end
result.class #=> Cuprum::Result
result.success? #=> false
result.error #=> 'something went wrong'With Multiple Steps
result = steps do
# This step is passing, so execution continues on to the next step.
step { success('first step') }
# This step is failing, so execution halts and returns this result.
step { failure('second step') }
# This step will never be called.
step { success('third step') }
end
result.class #=> Cuprum::Result
result.success? #=> false
result.error #=> 'second step'#to_proc => Proc
Wraps the command in a proc.
Calling the proc will call the command with the given arguments, keywords, and block.
Back to Documentation | Reference | Cuprum | Cuprum::Currying