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.

Results

A Cuprum::Result is a data object that encapsulates the result of calling a Cuprum command.

Contents

Value, Error, and Status

Each result has a #value, an #error object (defaults to nil), and a #status. By default, the status will be either :success or :failure, and accessible via the #success? and #failure? predicates.

result = Cuprum::Result.new

result.value    #=> nil
result.error    #=> nil
result.status   #=> :success
result.success? #=> true
result.failure? #=> true

Creating a result with a value stores the value.

value  = 'A result value'.freeze
result = Cuprum::Result.new(value: value)

result.value    #=> 'A result value'
result.error    #=> nil
result.status   #=> :success
result.success? #=> true
result.failure? #=> false

Creating a Result with an error stores the error and sets the status to :failure.

error  = Cuprum::Error.new(message: "I'm sorry, something went wrong.")
result = Cuprum::Result.new(error: error)
result.value    #=> nil
result.error    #=> Error with message "I'm sorry, something went wrong."
result.status   #=> :failure
result.success? #=> false
result.failure? #=> true

Although using a Cuprum::Error instance as the :error is recommended, it is not required. You can use a custom error object, or just a string message.

result = Cuprum::Result.new(error: "I'm sorry, something went wrong.")
result.value    #=> nil
result.error    #=> "I'm sorry, something went wrong."
result.status   #=> :failure
result.success? #=> false
result.failure? #=> true

Finally, the status can be overridden via the :status keyword.

result = Cuprum::Result.new(status: :failure)
result.error    #=> nil
result.status   #=> :failure
result.success? #=> false
result.failure? #=> true

error  = Cuprum::Error.new(message: "I'm sorry, something went wrong.")
result = Cuprum::Result.new(error: error, status: :success)
result.error    #=> Error with message "I'm sorry, something went wrong."
result.status   #=> :success
result.success? #=> true
result.failure? #=> false

Result Lists

A Cuprum::ResultList is a special type of Result that aggregates together a number of other results.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success, value: :ok),
  Cuprum::Result.new(status: :failure),
  Cuprum::Result.new(error: 'Something went wrong')
)
result_list.results
#=> [#<Cuprum::Result>, #<Cuprum::Result>, #<Cuprum::Result>]

Each ResultList defines the same interface as a standard Result: the #value, #error, and #status methods and the #success? and #failure? predicates.

result_list.value
#=> [:ok, nil, nil]
result_list.error
#=> #<Cuprum::Errors::MultipleErrors>
result_list.error.errors
#=> [nil, nil, 'Something went wrong']
result_list.status
#=> :failure
result_list.success?
#=> false
result_list.failure?
#=> true

Success And Failure

The status of a result list depends on the statuses of its constituent results.

An empty ResultList (with no Results) will have a status of :success.

result_list = Cuprum::ResultList.new
result_list.status
#=> :success

A non-empty ResultList will have a status of :success if and only if all of the Results are passing.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(status: :success)
)
result_list.status
#=> :success

A non-empty ResultList will have a status of :failure if any of the Results are failing.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(status: :failure),
  Cuprum::Result.new(status: :success)
)
result_list.status
#=> :failure

The status can also be specified directly. This will override the default status for the ResultList:

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(status: :success),
  status: :failure
)
result_list.status
#=> :failure

Partial Success

A result list can also be configured to pass if there are any passing results (or an empty input) by setting the :allow_partial flag to true.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(status: :failure),
  Cuprum::Result.new(status: :success),
  allow_partial: true
)
result_list.status
#=> :success

Values

By default, the #value of a ResultList is equal to the mapped values of each constituent result. These values can also be accessed directly by calling the #values method.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(value: 'Hello world'),
  Cuprum::Result.new(value: 'Greetings, programs!'),
  Cuprum::Result.new(status: :success)
)
result_list.value
#=> ['Hello world', 'Greetings, programs!', nil]
result_list.values
#=> ['Hello world', 'Greetings, programs!', nil]

A ResultList can also be initialized with a custom value.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(value: 'Hello world'),
  Cuprum::Result.new(value: 'Greetings, programs!'),
  Cuprum::Result.new(status: :success),
  value: { ok: true }
)
result_list.value
#=> { ok: true }
result_list.values
#=> ['Hello world', 'Greetings, programs!', nil]

The individual values can also be accessed via the #values property of the result list.

Errors

If the result list is empty, or if none of the results in the result list have an error, then the ResultList’s own #error property will be nil.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(status: :failure),
  Cuprum::Result.new(status: :failure)
)
result_list.error
#=> nil
result_list.errors
#=> [nil, nil, nil]

If at least one of the results has an error object, the result errors are aggregated together into a Cuprum::Errors::MultipleErrors object.

The individual errors can also be accessed via the #errors property of the result list.

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(
    status: :failure,
    error: Cuprum::Error.new(message: 'Something went wrong')),
  Cuprum::Result.new(status: :failure)
)
result_list.error.class
#=> Cuprum::Errors::MultipleErrors
result_list.error.message
#=> 'the command encountered one or more errors'
result_list.error.errors
#=> [nil, #<Cuprum::Error>, nil]
result_list.errors
#=> [nil, #<Cuprum::Error>, nil]

The error can also be specified directly. This will override the default error for the ResultList:

result_list = Cuprum::ResultList.new(
  Cuprum::Result.new(status: :success),
  Cuprum::Result.new(
    status: :failure,
    error: Cuprum::Error.new(message: 'Something went wrong')),
  Cuprum::Result.new(status: :failure),
  error: Cuprum::Error.new(message: 'Custom error message')
)
result_list.error.class
#=> Cuprum::Error
result_list.error.message
#=> 'Custom error message'
result_list.errors
#=> [nil, #<Cuprum::Error>, nil]

Back to Documentation | Versions | 1.1