Class: MonadOxide::Err

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

Overview

Err is the error case for Result.

Any methods in Result that would process a successful Result (Ok) will fall through with Err instances.

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Result

#flatten, #match

Constructor Details

#initialize(data) ⇒ Err

Create an Err.

If the Exception provided was not thrown (ie. created with Exception.new), it will not have a backtrace. The Err constructor takes care of this by raising the Exception and immediately capturing the Exception - this causes the backtrace to be populated and will be availabl to any cosumers automatically.



50
51
52
53
54
55
56
# File 'lib/err.rb', line 50

def initialize(data)
  if data.kind_of?(Array)
    @data = data.map(&self.class.method(:backtrace_fix))
  else
    @data = self.class.backtrace_fix(data)
  end
end

Class Method Details

.backtrace_fix(x) ⇒ Object

Add a backtrace to an Exception, or just pass long whatever was given. The Exception is mutated in the process.

Ruby Exceptions do not come with a backtrace. During the act of raising an Exception, that Exception is granted a backtrace. So any kind of ‘Exception.new()’ invocations will have a ‘nil’ value for ‘backtrace()’. To get around this, we can simply raise the Exception here, and then we get the backtrace we want.

On a cursory search, this is not documented behavior.



26
27
28
29
30
31
32
33
34
# File 'lib/err.rb', line 26

def self.backtrace_fix(x)
  if x.kind_of?(Exception) && x.backtrace.nil?
    raise x
  else
    x
  end
rescue => e
  e
end

Instance Method Details

#and_then(f = nil) { ... } ⇒ Err

Falls through. @see Result#and_then for how this is handled in either Result case, and @see Ok.and_then for how this is handled in the Ok case.

Yields:

  • An ignored block.



64
65
66
# File 'lib/err.rb', line 64

def and_then(f=nil, &block)
  self
end

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

Applies ‘f’ or the block over the ‘Exception’ and returns the same ‘Err’. No changes are applied. This is ideal for logging. Exceptions raised during these transformations will return an ‘Err’ with the Exception.

Yields:

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



77
78
79
80
81
82
83
84
# File 'lib/err.rb', line 77

def inspect_err(f=nil, &block)
  begin
    (f || block).call(@data)
    self
  rescue => e
    self.class.new(e)
  end
end

#inspect_ok(f = nil) { ... } ⇒ Err

Falls through. @see Result#inspect_ok for how this is handled in either Result case, and @see Ok.inspect_ok for how this is handled in the Ok case.

Yields:

  • An ignored block.



93
94
95
# File 'lib/err.rb', line 93

def inspect_ok(f=nil, &block)
  self
end

#map(f = nil) { ... } ⇒ Err

Falls through. @see Result#map for how this is handled in either Result case, and @see Ok.map for how this is handled in the Ok case.

Yields:

  • An ignored block.



103
104
105
# File 'lib/err.rb', line 103

def map(f=nil, &block)
  self
end

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

Applies ‘f’ or the block over the data and returns a new new ‘Err’ with the returned value.

Yields:

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



117
118
119
120
121
122
123
# File 'lib/err.rb', line 117

def map_err(f=nil, &block)
  begin
    self.class.new((f || block).call(@data))
  rescue => e
    self.class.new(e)
  end
end

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

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>’. The return type is enforced.

Yields:

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



136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/err.rb', line 136

def or_else(f=nil, &block)
  begin
    r = (f || block).call(@data)
    # Enforce that we always get a Result. Without a Result, coerce to an
    # Err.
    if !r.kind_of?(Result)
      raise ResultReturnExpectedError.new(r)
    else
      r
    end
  rescue => e
    Err.new(e)
  end
end

#unwrapA

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

Raises:



155
156
157
158
159
# File 'lib/err.rb', line 155

def unwrap()
  raise UnwrapError.new(
    "#{self.class} with #{@data.inspect} could not be unwrapped as an Ok.",
  )
end

#unwrap_errE

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



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

def unwrap_err()
  @data
end

#unwrap_or(x) ⇒ T

Safely unwrap the ‘Result`. In the case of `Err`, this returns the provided default value.



175
176
177
# File 'lib/err.rb', line 175

def unwrap_or(x)
  x
end