All Projects → vic → Happy

vic / Happy

Licence: apache-2.0
the alchemist's happy path with elixir

Programming Languages

elixir
2628 projects

Projects that are alternatives of or similar to Happy

result17
A rust like Result type for modern C++
Stars: ✭ 13 (-64.86%)
Mutual labels:  monad, error-handling
sealed-monad
Scala library for nice business logic oriented, for-comprehension-style error handling
Stars: ✭ 16 (-56.76%)
Mutual labels:  monad, error-handling
Ok jose
Pipe elixir functions that match ok/error tuples or custom patterns.
Stars: ✭ 91 (+145.95%)
Mutual labels:  monad, error-handling
Perhaps
A monad, perhaps.
Stars: ✭ 35 (-5.41%)
Mutual labels:  monad, error-handling
Purify
Functional programming library for TypeScript - https://gigobyte.github.io/purify/
Stars: ✭ 843 (+2178.38%)
Mutual labels:  monad
Ltupatternfactory
Lambda the ultimate Pattern Factory: FP, Haskell, Typeclassopedia vs Software Design Patterns
Stars: ✭ 735 (+1886.49%)
Mutual labels:  monad
Static Land
Specification for common algebraic structures in JavaScript based on Fantasy Land
Stars: ✭ 699 (+1789.19%)
Mutual labels:  monad
Snafu
Easily assign underlying errors into domain-specific errors while adding context
Stars: ✭ 630 (+1602.7%)
Mutual labels:  error-handling
Make Error Cause
Make your own nested errors
Stars: ✭ 36 (-2.7%)
Mutual labels:  error-handling
Whoops
PSR-15 middleware to use Whoops as error handler
Stars: ✭ 29 (-21.62%)
Mutual labels:  error-handling
Error Overlay Webpack Plugin
Catch errors with style 💥✨
Stars: ✭ 821 (+2118.92%)
Mutual labels:  error-handling
Lambda
Functional patterns for Java
Stars: ✭ 737 (+1891.89%)
Mutual labels:  monad
Witchcraft
Monads and other dark magic for Elixir
Stars: ✭ 864 (+2235.14%)
Mutual labels:  monad
Errorx
A comprehensive error handling library for Go
Stars: ✭ 712 (+1824.32%)
Mutual labels:  error-handling
Rbdl Orb
RBDL - Rigid Body Dynamics Library - ORB Version - The two main differences to the original rbdl is that this version has error handling and uses polymorphism for constraints
Stars: ✭ 33 (-10.81%)
Mutual labels:  error-handling
Tracerr
Golang errors with stack trace and source fragments.
Stars: ✭ 646 (+1645.95%)
Mutual labels:  error-handling
Fp Core.rs
A library for functional programming in Rust
Stars: ✭ 772 (+1986.49%)
Mutual labels:  monad
Statusprovider
Protocol to handle initial Loadings, Empty Views and Error Handling in a ViewController & views
Stars: ✭ 879 (+2275.68%)
Mutual labels:  error-handling
Httperrorpages
⏩ Simple HTTP Error Page Generator
Stars: ✭ 772 (+1986.49%)
Mutual labels:  error-handling
Thoth
An Error Logger for Go
Stars: ✭ 22 (-40.54%)
Mutual labels:  error-handling

Happy

help maintain this lib

the alchemist's happy path with elixir

If you are using Elixir >= 1.2, you might prefer happy_with

Installation

Available in Hex, the package can be installed as:

  1. Add happy to your list of dependencies in mix.exs:
  def deps do
    [{:happy, "~> 1.3.1"}]
  end

About

Ok, so I was just trying to find a nice way (beautiful syntax, yet flexible enough) to handle errors in elixir. Handling :ok/:error like tuples without lots of if/cases.

After creating ok_jose, looking at Elixir's with special form and other alternatives, I wanted to create this tiny library with the following goals in mind:

  • The happy path must be immediately obvious to the eyes.
  • Code should not be cluttered and should just work using the elixir you already know.
  • Avoid introducing noisy operators ~>>, requiring commas after each pattern
  • Should provide a way to recover when not so happy moments come.

If you dont need special features like tags, and are using elixir ~> 1.2, checkout happy_with wich is just tiny sugar around with special form.

Usage

import Happy
the happy_path macro

The happy_path macro takes a do block and rewrites any first-level pattern matching expression into a case.

happy_path do
  {:ok, b} = a
  {:ok, d} = b
  c(d)
end

gets rewritten to something like:

case(a) do
  {:ok, b} ->
    case (b) do
      {:ok, d} -> c(d)
    end
end

Note that a variable pattern match (assignment) is not rewritten, as it will always match and would cause warnings.

happy_path do
  x = some(thing) # simple assignment is left as is
end
handling errors with else clauses

If you want to handle non-matching values, provide an else block with additional matching clauses:

happy_path do
  {:ok, b} = a
  c(b)
else
  {:error, x} -> x
end
sharing common error handling code

Sometimes you would want to share common error handling code on many happy_paths, for example in an api controller with many actions, all of which handle common invalid cases like parameter validation.

In those cases you can provide happy_path with an default error handler as first argument. Note that if no local else clause matches, the error value is piped into the provided error handler. Thus the handler is anything you can pipe the error value into.

happy_path(else: handler) do 
 {:ok, x} = foo
 x + 1
else
 {:error, y} -> y
end

gets rewritten to something like:

case foo do
  {:ok, x} -> 
    x + 1
  {:error, y} ->
    y
  err -> 
    err |> handler
end
support for guards

Just like with case you can include guard tests.

happy_path do
  x when not is_nil(x) = some(foo)
  x + 1
end
tags

Tags is an special feature of happy_path not found on alternatives like elixir's with expression.

Tags look like module attributes but they are not, they are just shorthand for tagging a pattern.

happy_path do
  # using the `foo` tag
  @foo {:ok, x} = y

  # is exactly the same as
  {:foo, {:ok, x}} = {:foo, y}
else
  {:foo, {:error, e}} -> "Foo error"
end

Tags can help error handlers to get a clue about which context the mismatch was produced on. It's mostly useful for distingishing between lots of {:error, _} like tuples.

@happy tag

The special tag @happy lets you mark a pattern matching expression to be skipped by happy_path. For example when you know something will always match.

happy_path do
  @happy {this, would} = {"always", "match"}
end

produces just:

{this, would} = {"always", "match"}
Example usage in a web application creating a user
happy_path do

  %{valid?: true} = ch = User.changeset(params)
  {:ok, user} = Repo.insert(ch)
  render(conn, "user.json", user: user)

else

  %{valid?: false} = ch -> render(conn, "validation_errors.json", ch: ch)
  {:error, ch} -> render(conn, "db_error.json", ch: ch)
  _ -> text(conn, "error")

end

Is it any good?

Yes

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].