Crystal Error

Build Status ISC

An efficient way to handle errors without using raise - no expensive stack unwinding.

Advantages

Over "classic" Exception errors, this approach provides:

The main disadvantage is the slight verbosity added, having a new type Error type to handle. On the other side begin/rescue aren't needed

Installation

Add the dependency to your shard.yml:

dependencies:
  error:
    github: j8r/error.cr

Usage

Simple error

require "error"

def it_throws
  Error.throw "Oops!"
end
p it_throws

result:

Oops! (Error)
   from myapp.cr:4 in 'it_throws'

Handling errors

require "error"

struct Obj
  def action : String | Error
    Error.throw("Shouldn't be true") || "normal"
  end
end

def main_program : String | Error
  case result = Obj.new.action
  # Throw the error on the top.
  # Optionaly, the message can be modified and a parent error specified.
  when Error then Error.throw "Action not successful: #{result}", result
  else            "operation successful: " + result
  end
end

p main_program

result:

Action not successful: Shouldn't be true (Error)
   from myapp.cr:5 in 'Obj#action'
   from myapp.cr:13 in 'main_program'

Custom errors

class CustomError < Error
  @message = "This is a custom error message"
end

def action
  CustomError.throw
end

p action

result:

This is a custom error message (CustomError)
   from app.cr:6 in 'action'

FAQ

I can't use this in my main program.

This libary can only be used inside methods, because the Error.throw macro expands to a return Error.

This doesn't work in the initialize of my class!

A class initializer can't return an union, only an instance of the class.

You can create a self.new method that returns the union of the class and Error.

License

Copyright (c) 2018-2019 Julien Reichardt - ISC License