Cuprum

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.

Class: Cuprum::Command

Parent Namespace
Cuprum
Extended Modules
SleepingKingStudios::Tools::Toolbox::Subclass
Included Modules
Cuprum::Currying, Cuprum::Processing, Cuprum::Steps
Defined In
lib/cuprum/command.rb

Table Of Contents

Overview

Functional object that encapsulates a business logic operation or step.

Using commands allows the developer to maintain a state or context, such as by passing context into the constructor. It provides a consistent interface by always returning a Cuprum::Result object, which tracks the status of the command call, the returned value, and the error object (if any). Finally, as a full-fledged Ruby object a Command can be passed around like any other object, including returned from a method (or another Command) or passed in as a parameter.

A Command can be defined either by passing a block to the constructor, or by defining a subclass of Command and implementing the #process method.

Examples

A Command with a block

double_command = Cuprum::Command.new { |int| 2 * int }
result         = double_command.call(5)

result.value #=> 10

A Command subclass

class MultiplyCommand < Cuprum::Command
  def initialize(multiplier)
    @multiplier = multiplier
  end

  private def process(int)
    int * @multiplier
  end
end

triple_command = MultiplyCommand.new(3)
result         = command_command.call(5)

result.value #=> 15

A Command with an error state

class DivideCommand < Cuprum::Command
  def initialize(divisor)
    @divisor = divisor
  end

  private def process(int)
    if @divisor.zero?
      return Cuprum::Result.new(error: 'errors.messages.divide_by_zero')
    end

    int / @divisor
  end
end

halve_command = DivideCommand.new(2)
result        = halve_command.call(10)

result.error #=> nil
result.value #=> 5

divide_command = DivideCommand.new(0)
result         = divide_command.call(10)

result.error #=> 'errors.messages.divide_by_zero'
result.value #=> nil

See Also

Back To Top

Direct Subclasses

Cuprum::BuiltIn::IdentityCommand, Cuprum::BuiltIn::NullCommand, Cuprum::Currying::CurriedCommand, Cuprum::MapCommand, Cuprum::Operation

Back To Top

Class Methods

.subclass(*class_arguments, **class_keywords, &block) => Class

Creates a subclass with partially applied constructor parameters.

Parameters

Yields

Returns

Back To Top

Constructor

#initialize(&implementation) => Command

Returns a new instance of Cuprum::Command.

Yields

Yield Parameters

Yield Returns

Returns

Back To Top

Instance Methods

#arity => Integer

Inherited From
Cuprum::Processing

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.

Returns

See Also

#call(*arguments, **keywords, &block) => Cuprum::Result

Executes the command and returns a Cuprum::Result or compatible object.

Each time #call is invoked, the object performs the following steps:

  1. The #process method is called, passing the arguments, keywords, and block that were passed to #call.
  2. If the value returned by #process is a Cuprum::Result or compatible object, that result is directly returned by #call.
  3. Otherwise, the value returned by #process will be wrapped in a successful result, which will be returned by #call.

Parameters

Yields

Returns

#curry(*arguments, **keywords, &block) => Cuprum::Currying::CurriedCommand

Inherited From
Cuprum::Currying

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.

Parameters

Returns

See Also

#process(*arguments, **keywords, &block) => Cuprum::Result, Object

Note: This is a private method.

The implementation of the command.

Whereas the #call method provides the public interface for calling a command, the #process method defines the actual implementation. This method should not be called directly.

When the command is called via #call, the parameters are passed to #process. If #process returns a result, that result will be returned by #call; otherwise, the value returned by #process will be wrapped in a successful Cuprum::Result object.

Parameters

Yields

Returns

#step => Object

Inherited From
Cuprum::Steps

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.

Examples

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.

Yields

Returns

Raises

#steps(&block) => Cuprum::Result

Inherited From
Cuprum::Steps

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.

Examples

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'

Yields

Yield Returns

Returns

Raises

#to_proc => Proc

Wraps the command in a proc.

Calling the proc will call the command with the given arguments, keywords, and block.

Returns

Back To Top


Back to Documentation | Reference | Cuprum