Class: Faulty::Result

Inherits:
Object
  • Object
show all
Defined in:
lib/faulty/result.rb

Overview

An approximation of the Result type from some strongly-typed languages.

F#: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/results

Rust: https://doc.rust-lang.org/std/result/enum.Result.html

Since we can't enforce the type at compile-time, we use runtime errors to check the result for consistency as early as possible. This means we enforce runtime checks of the result type. This approach does not eliminate issues, but it does help remind the user to check the result in most cases.

This is returned from Circuit#try_run to allow error handling without needing to rescue from errors.

Examples:

result = Result.new(ok: 'foo')

# Check the result before calling get
if result.ok?
  puts result.get
else
  puts result.error.message
end
result = Result.new(error: StandardError.new)
puts result.or_default('fallback') # prints "fallback"
result = Result.new(ok: 'foo')
result.get # raises UncheckedResultError
result = Result.new(ok: 'foo')
if result.ok?
  result.error.message # raises WrongResultError
end

Constant Summary collapse

NOTHING =

The constant used to designate that a value is empty

This is needed to differentiate between an ok nil value and an empty value.

{}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(ok: NOTHING, error: NOTHING) ⇒ Result

Create a new Result with either an ok or error value

Exactly one parameter must be given, and not both.

Parameters:

  • ok (defaults to: NOTHING)

    An ok value

  • error (Error) (defaults to: NOTHING)

    An error instance



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/faulty/result.rb', line 56

def initialize(ok: NOTHING, error: NOTHING)
  if ok.equal?(NOTHING) && error.equal?(NOTHING)
    raise ArgumentError, 'Result must have an ok or error value'
  end
  if !ok.equal?(NOTHING) && !error.equal?(NOTHING)
    raise ArgumentError, 'Result must not have both an ok and error value'
  end

  @ok = ok
  @error = error
  @checked = false
end

Instance Method Details

#errorObject

Get the error value

Raises:

  • UncheckedResultError if this result was not checked using #ok? or #error?

  • WrongResultError if this result is ok



108
109
110
111
# File 'lib/faulty/result.rb', line 108

def error
  validate_checked!('error')
  unsafe_error
end

#error?Boolean

Check if the value is an error value

Returns:

  • (Boolean)

    True if this result is an error



80
81
82
# File 'lib/faulty/result.rb', line 80

def error?
  !ok?
end

#getObject

Get the ok value

Returns:

  • The ok value

Raises:

  • UncheckedResultError if this result was not checked using #ok? or #error?

  • WrongResultError if this result is an error



89
90
91
92
# File 'lib/faulty/result.rb', line 89

def get
  validate_checked!('get')
  unsafe_get
end

#ok?Boolean

Check if the value is an ok value

Returns:

  • (Boolean)

    True if this result is ok



72
73
74
75
# File 'lib/faulty/result.rb', line 72

def ok?
  @checked = true
  ok_unchecked?
end

#or_default(default = nil) { ... } ⇒ Object

Get the ok value if this result is ok, otherwise return a default

Parameters:

  • default (defaults to: nil)

    The default value. Ignored if a block is given

Yields:

  • A block returning the default value

Returns:

  • The ok value or the default if this result is an error



128
129
130
131
132
133
134
135
136
# File 'lib/faulty/result.rb', line 128

def or_default(default = nil)
  if ok_unchecked?
    @ok
  elsif block_given?
    yield @error
  else
    default
  end
end

#unsafe_errorError

Get the error value without checking whether it's safe to do so

Returns:

  • (Error)

    The error

Raises:

  • WrongResultError if this result is ok



117
118
119
120
121
# File 'lib/faulty/result.rb', line 117

def unsafe_error
  raise WrongResultError, 'Tried to get error for ok result' if ok_unchecked?

  @error
end

#unsafe_getObject

Get the ok value without checking whether it's safe to do so

Returns:

  • The ok value

Raises:

  • WrongResultError if this result is an error



98
99
100
101
102
# File 'lib/faulty/result.rb', line 98

def unsafe_get
  raise WrongResultError, 'Tried to get value for error result' unless ok_unchecked?

  @ok
end