Class: MonadOxide::Result

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

Overview

A Result is a chainable series of sequential transformations. The Result structure contains an ‘Ok<A> | Err<Exception>`. This is the central location for documentation between both `Ok` and `Err`. It is best to think of any given `Ok` or `Err` as a `Result` instead. All methods on `Ok` are present on `Err` and vice versa. This way we can interchange one for the other during virtually any call.

This is a base-class only, and you should never see instances of these in the wild.

Direct Known Subclasses

Err, Ok

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Result

None of these work. Option 1: private_class_method :new Option 2: class << self

protected :new

end

Raises:

  • (NoMethodError)


55
56
57
# File 'lib/result.rb', line 55

def initialize(data)
  raise NoMethodError.new('Do not use Result directly. See Ok and Err.')
end

Instance Method Details

#and_then(f = nil) { ... } ⇒ Ok<B> | Err<C>

For ‘Ok’, invokes ‘f’ or the block with the data and returns the Result returned from that. Exceptions raised during ‘f’ or the block will return an ‘Err<Exception>’.

For ‘Err’, returns itself and the function/block are ignored.

This method is used for control flow based on ‘Result’ values.

‘and_then’ is desirable for chaining together other Result based operations, or doing transformations where flipping from an ‘Ok’ to an ‘Err’ is desired. In cases where there is little/no risk of an ‘Err’ state, @see Result#map.

The ‘Err’ equivalent operation is @see Result#or_else.

The return type is enforced.

Parameters:

  • f (Proc<A, Result<B>>) (defaults to: nil)

    The function to call. Could be a block instead. Takes an [A=Object] and must return a [Result<B>].

Yields:

  • Will yield a block that takes an A and returns a Result<B>. Same as ‘f’ parameter.

Returns:

  • (Ok<B> | Err<C>)

    A new Result from ‘f’ or the block. Exceptions raised will result in ‘Err<C>’. If ‘f’ returns a non-Result, this will return ‘Err<ResultReturnExpectedError>’.



91
92
93
# File 'lib/result.rb', line 91

def and_then(f=nil, &block)
  Err.new(ResultMethodNotImplementedError.new())
end

#err?Boolean

Determine if this is a MonadOxide::Err.

Returns:

  • (Boolean)

    ‘true` if this is a MonadOxide::Err, `false` otherwise.



62
63
64
# File 'lib/result.rb', line 62

def err?()
  false
end

#flattenResult

Un-nest this ‘Result’. This implementation is shared between ‘Ok’ and ‘Err’. In both cases, the structure’s data is operated upon. return the inner-most ‘Result’, regardless of the depth of nesting. Otherwise return ‘self’.

Returns:

  • (Result)

    If ‘A’ is a ‘Result’ (meaning this ‘Result` is nested),



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

def flatten()
  if @data.kind_of?(Result)
    return @data.flatten()
  else
    self
  end
end

#inspect_err(f = nil) { ... } ⇒ Result<A>

In the case of ‘Err’, applies ‘f’ or the block over the ‘Exception’ and returns the same ‘Err’. No changes are applied. This is ideal for logging. For ‘Ok’, this method falls through. Exceptions raised during these transformations will return an ‘Err’ with the Exception.

Parameters:

  • f (Proc<A, B>) (defaults to: nil)

    The function to call. Could be a block instead. Takes an [A=Exception] the return is ignored.

Yields:

  • Will yield a block that takes an A the return is ignored. Same as ‘f’ parameter.

Returns:

  • (Result<A>)

    returns self.



105
106
107
# File 'lib/result.rb', line 105

def inspect_err(f=nil, &block)
  Err.new(ResultMethodNotImplementedError.new())
end

#inspect_ok(f = nil) { ... } ⇒ Result<A>

In the case of ‘Ok’, applies ‘f’ or the block over the data and returns the same ‘Ok’. No changes are applied. This is ideal for logging. For ‘Err’, this method falls through. Exceptions raised during these transformations will return an ‘Err’ with the Exception.

Parameters:

  • f (Proc<A, B>) (defaults to: nil)

    The function to call. Could be a block instead. Takes an [A] the return is ignored.

Yields:

  • Will yield a block that takes an A the return is ignored. Same as ‘f’ parameter.

Returns:

  • (Result<A>)

    returns self.



133
134
135
# File 'lib/result.rb', line 133

def inspect_ok(f=nil, &block)
  Err.new(ResultMethodNotImplementedError.new())
end

#map(f = nil) { ... } ⇒ Result<B>

In the case of ‘Ok’, applies ‘f’ or the block over the data and returns a new new ‘Ok’ with the returned value. For ‘Err’, this method falls through. Exceptions raised during these transformations will return an ‘Err’ with the Exception.

Parameters:

  • f (Proc<A, B>) (defaults to: nil)

    The function to call. Could be a block instead. Takes an [A=Object] and returns a B.

Yields:

  • Will yield a block that takes an A and returns a B. Same as ‘f’ parameter.

Returns:

  • (Result<B>)

    A new ‘Result<B>’ whose ‘B’ is the return of ‘f’ or the block. Errors raised when applying ‘f’ or the block will result in a returned ‘Err<Exception>’.



149
150
151
# File 'lib/result.rb', line 149

def map(f=nil, &block)
  Err.new(ResultMethodNotImplementedError.new())
end

#map_err(f = nil) { ... } ⇒ Result<B>

In the case of ‘Err’, applies ‘f’ or the block over the ‘Exception’ and returns a new new ‘Err’ with the returned value. For ‘Ok’, this method falls through. Exceptions raised during these transformations will return an ‘Err’ with the Exception.

Parameters:

  • f (Proc<A, B>) (defaults to: nil)

    The function to call. Could be a block instead. Takes an [A=Exception] and returns a [B=Exception].

Yields:

  • Will yield a block that takes an A and returns a B. Same as ‘f’ parameter.

Returns:

  • (Result<B>)

    A new ‘Result<A, ErrorB>’ whose ‘ErrorB’ is the return of ‘f’ or the block. Errors raised when applying ‘f’ or the block will result in a returned ‘Err<Exception>’.



165
166
167
# File 'lib/result.rb', line 165

def map_err(f=nil, &block)
  Err.new(ResultMethodNotImplementedError.new())
end

#match(matcher) ⇒ R

Use pattern matching to work with both Ok and Err variants. This is useful when it is desirable to have both variants handled in the same location. It can also be useful when either variant can coerced into a non-Result type.

Ruby has no built-in pattern matching, but the next best thing is a Hash using the Result classes themselves as the keys.

Tests for this are found in Ok and Err’s tests.

upon.

Parameters:

  • matcher (Hash<Class, Proc<T | E, R>] matcher The matcher to match)

    atcher [Hash<Class, Proc<T | E, R>] matcher The matcher to match

Options Hash (matcher):

  • MonadOxide::Ok (Proc)

    The branch to execute for Ok.

  • MonadOxide::Err (Proc)

    The branch to execute for Err.

Returns:

  • (R)

    The return value of the executed Proc.



185
186
187
# File 'lib/result.rb', line 185

def match(matcher)
  matcher[self.class].call(@data)
end

#ok?Boolean

Determine if this is a MonadOxide::Ok.

Returns:

  • (Boolean)

    ‘true` if this is a MonadOxide::Ok, `false` otherwise.



192
193
194
# File 'lib/result.rb', line 192

def ok?()
  false
end

#or_else(f = nil) { ... } ⇒ Ok<B> | Err<C>

For ‘Err’, invokes ‘f’ or the block with the data and returns the Result returned from that. Exceptions raised during ‘f’ or the block will return an ‘Err<Exception>’.

For ‘Ok’, returns itself and the function/block are ignored.

This method is used for control flow based on ‘Result’ values.

‘or_else’ is desirable for chaining together other Result based operations, or doing transformations where flipping from an ‘Ok’ to an ‘Err’ is desired. In cases where there is little/no risk of an ‘Err’ state, @see Result#map.

The ‘Ok’ equivalent operation is @see Result#and_then.

The return type is enforced.

Parameters:

  • f (Proc<A, Result<B>>) (defaults to: nil)

    The function to call. Could be a block instead. Takes an [A=Object] and must return a [Result<B>].

Yields:

  • Will yield a block that takes an A and returns a Result<B>. Same as ‘f’ parameter.

Returns:

  • (Ok<B> | Err<C>)

    A new Result from ‘f’ or the block. Exceptions raised will result in ‘Err<C>’. If ‘f’ returns a non-Result, this will return ‘Err<ResultReturnExpectedError>’.



221
222
223
# File 'lib/result.rb', line 221

def or_else(f=nil, &block)
  Err.new(ResultMethodNotImplementedError.new())
end

#unwrapA

Dangerously access the ‘Result’ data. If this is an ‘Err’, an exception will be raised. It is recommended to use this for tests only.

Returns:

  • (A)
    • The inner data of this ‘Ok’.

Raises:



230
231
232
# File 'lib/result.rb', line 230

def unwrap()
  Err.new(ResultMethodNotImplementedError.new())
end

#unwrap_errE

Dangerously access the ‘Result’ data. If this is an ‘Ok’, an exception will be raised. It is recommended to use this for tests only.

Returns:

  • (E)
    • The inner data of this ‘Err’.

Raises:



239
240
241
# File 'lib/result.rb', line 239

def unwrap_err()
  Err.new(ResultMethodNotImplementedError.new())
end

#unwrap_err_or_else(_f) { ... } ⇒ T|B

Safely unwrap the ‘Result` but with lazy evaluation. In the case of `Err`, this returns the wrapped value. For `Ok` the function provided is evaluated and its returned value is what is returned.

Parameters:

  • f (Proc<B>)

    The function to call for ‘Ok`. Could be a block instead. Takes nothing and returns a [B=Object].

Yields:

  • Will yield a block for ‘Ok` that takes nothing and returns a [B=Object]. Same as `f’ parameter.

Returns:

  • (T|B)

    The wrapped value for ‘Err` and the returned from `f` for `Ok`.

Raises:



254
255
256
# File 'lib/result.rb', line 254

def unwrap_err_or_else(_f)
  raise ResultMethodNotImplementedError.new()
end

#unwrap_or(_) ⇒ T|B

Attempt to safely access the ‘Result` data. This always returns a value instead of raising an Exception. In the case of `Ok`, the data is returned. In the case of `Err`, the value provided is returned.

Parameters:

  • _ (B)

    The value to use for ‘Err`.

Returns:

  • (T|B)

    The inner data of this ‘Ok` or the passee value.



264
265
266
# File 'lib/result.rb', line 264

def unwrap_or(_)
  Err.new(ResultMethodNotImplementedError.new())
end

#unwrap_or_else(_f) { ... } ⇒ T|B

Safely unwrap the ‘Result` but with lazy evaluation. In the case of `Ok`, this returns the wrapped value. For `Err` the function provided is evaluated and its returned value is what is returned.

Parameters:

  • f (Proc<B>)

    The function to call for ‘Err`. Could be a block instead. Takes nothing and returns a [B=Object].

Yields:

  • Will yield a block for ‘Err` that takes nothing and returns a [B=Object]. Same as `f’ parameter.

Returns:

  • (T|B)

    The wrapped value for ‘Ok` and the returned from `f` for `Err`.

Raises:



279
280
281
# File 'lib/result.rb', line 279

def unwrap_or_else(_f)
  raise ResultMethodNotImplementedError.new()
end