Class: SorbetOperation::Result

Inherits:
Object
  • Object
show all
Extended by:
T::Generic, T::Sig
Defined in:
lib/sorbet_operation/result.rb

Overview

Result is a generic class that represents the result of an operation, either success or failure.

If the result is a success, it wraps a value of type member ValueType.

If the result is a failure, it wraps an exception of type Failure.

Constant Summary collapse

ValueType =

The type of the value wrapped by the SorbetOperation::Result. The type can be any valid Sorbet type, as long as it's a subtype of Object.

type_member { { upper: Object } }

Instance Method Summary collapse

Constructor Details

#initialize(success, value, error) ⇒ Result

Returns a new instance of Result.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/sorbet_operation/result.rb', line 36

def initialize(success, value, error)
  @success = success
  @value = value
  @error = error

  # NOTE: these checks are annoying. A better API would be to make this
  # constructor private and provide two factory methods:
  # - `Result.success(value)`
  # - `Result.failure(error)`
  #
  # However, in order to do this, we would need to be able to use
  # {ValueType} in class methods. At this time, there is no way to tell
  # Sorbet that a generic type applies to both the class and its
  # singleton. We would need to duplicate the value type:
  # ```
  # ValueTypeMember = type_member { { upper: Object } }
  # ValueTypeTemplate = type_template { { upper: Object } }
  # ```
  # and every subclass would need to specify both (and ensure that
  # they're both set to the same type). This would be quite clumsy. Since
  # `Result` should rarely be instantiated directly (rather, it's
  # instantiated by `SorbetOperation::Base#perform`), we'll just live with
  # this less than ideal API for now.
  if @success
    # We can't test that value is not nil because the value type can be
    # nilable. (In theory we could check if the type is nilable and only
    # apply the check if it's not, but that's not worth the complexity.)
    unless error.nil?
      raise ArgumentError, "Cannot pass an error to a success result"
    end
  elsif error.nil?
    raise ArgumentError, "Must pass an error to a failure result"
  elsif !value.nil?
    raise ArgumentError, "Cannot pass a value to a failure result"
  end
end

Instance Method Details

#casted_valueObject (private)



198
199
200
# File 'lib/sorbet_operation/result.rb', line 198

def casted_value
  T.cast(@value, ValueType)
end

#failure?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/sorbet_operation/result.rb', line 81

def failure?
  !success?
end

#on_failure {|T.must(@error)| ... } ⇒ Object

Yields:

  • (T.must(@error))


173
174
175
176
# File 'lib/sorbet_operation/result.rb', line 173

def on_failure(&blk)
  yield(T.must(@error)) if failure?
  self
end

#on_success {|casted_value| ... } ⇒ Object

Yields:



160
161
162
163
# File 'lib/sorbet_operation/result.rb', line 160

def on_success(&blk)
  yield(casted_value) if success?
  self
end

#safe_unwrapObject



97
98
99
100
101
# File 'lib/sorbet_operation/result.rb', line 97

def safe_unwrap
  return if failure?

  casted_value
end

#safe_unwrap_errorObject



146
147
148
149
150
# File 'lib/sorbet_operation/result.rb', line 146

def safe_unwrap_error
  return T.must(@error) if failure?

  nil
end

#success?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/sorbet_operation/result.rb', line 75

def success?
  @success
end

#unwrap!Object



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

def unwrap!
  raise T.must(@error) if failure?

  casted_value
end

#unwrap_error!Object



136
137
138
139
140
141
# File 'lib/sorbet_operation/result.rb', line 136

def unwrap_error!
  return T.must(@error) if failure?

  # TODO: custom error type?
  raise "Called `unwrap_err!` on a success"
end

#unwrap_or(default) ⇒ Object



112
113
114
115
116
# File 'lib/sorbet_operation/result.rb', line 112

def unwrap_or(default)
  return casted_value if success?

  default
end

#unwrap_or_else {|T.must(@error)| ... } ⇒ Object

Yields:

  • (T.must(@error))


127
128
129
130
131
# File 'lib/sorbet_operation/result.rb', line 127

def unwrap_or_else(&blk)
  return casted_value if success?

  yield(T.must(@error))
end