Result
∠(・.-)―〉 →◎ Result
adds Monadic Error Handling capabilities to Crystal lang, inspired by Result
in Rust lang, Monad and the Elixir lang approach (state return).
Adapted to be productive in Crystal and Domain-Driven Design (DDD).
Installation
- Add the dependency to your
shard.yml
:
dependencies:
result:
github: nicolab/crystal-result
version: ~> 2.0.1 # Check the latest version!
- Run
shards install
Usage
require "result"
require "result/utils"
# With a basic *value*
def something(value : Number) : Result
# Wrap value into a `Result` instance (struct: `Ok` or `Err`).
# If an error occurred, here *something* method returns an `Err` instance.
res = result!(value)
# Executed only if `result!` (above) has returned an `Ok` instance,
pp "does something"
pp res.unwrap # => Number
res
end
# With a `Result` instance
def something(res : Result) : Result
# Try to unwrap original value.
# If result is an error, here *something* method returns this `Err` instance.
data = try!(res)
# Executed if `try!` (above) has returned the original value.
pp "does something"
# Original value
pp data
# Wrap data into a `Result` struct:
# Returns success
# `Ok` / `Ok.status # => :done`
Ok.done data
# Or returns an error
# `Err` / `Err.status # => :fail`
Err.fail "Oops!"
end
# Try to unwrap a *Result* (like `Result#unwrap`) or forward the value if it is not a `Result`.
res = Ok.done("hello") # or `Ok.new("hello")`
value = unwrap!(res) # => "hello"
res = Err.fail("Oops") # or `Err.new("Oops")`
value = unwrap!(res) # => raise Exception.new "Oops"
foo = "bar"
value2 = unwrap!(foo) # => "bar"
To go further, Result
works wonderfully with fuzzineer/match-crystal.
require "result"
require "result/utils"
require "match-crystal"
res = something()
message = match res.status, {
:created => "Created with success",
:destroyed => "Destroyed with success",
:pending => "Pending task",
:input => "Bad argument",
:fail => "Failed",
_ => "anything else!",
}
puts message
# other example
message = match res, {
Ok(String) => "Ok is a good string",
res.status? :created => "Created with success",
Ok => "It's ok",
Err(ArgumentError) => "Bad argument",
res.status? :not_found => "Not found",
Err => ->{
puts "Block is supported using Proc syntax"
"Error occurred"
},
}
puts message
Example with a case
:
message = case res
when .status? :created
"Created with success"
when .status? :destroyed
"Destroyed with success"
when .status? :pending
"Pending task"
when .status? :input
"Bad argument"
when .status? :not_found
"Not found"
when .status? :fail
"Failed"
when Ok
"Another success"
when Err
"Another error"
else
"Anything else!"
end
puts message
Works well with a controller.
Development
crystal spec
crystal tool format
Contributing
- Fork it (https://github.com/Nicolab/crystal-result/fork)
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
LICENSE
MIT (c) 2020, Nicolas Talle.
Author
| | |---| | Nicolas Talle | | |