Ok Jose

A tiny library for piping function return values on a given pattern like the erlang idiom {:ok, _} and {:error, _} tuples.

You can also define your own pattern-matched pipes besides ok and error.

Installation

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

Motivation

A lot of erlang libraries follow the convention of returning {:ok, _} and {:error, _} tuples to denote success or failure.

This library is my try at having a beautiful syntax for a happy pipe, that is, a pipe that expects {:ok, _} tuples to be returned by each piped function. If any piped function returns a non matched value, the remaining functions expecting an {:ok, _} value wont get executed.

So, for example, the following code

filename
|> File.read()
|> case do
{:ok, content} ->
content |> Poison.Parser.parse()
{:error, _} = error -> error
end

can be written as:

filename |> File.read |> Poison.Parser.parse |> ok

or alternatively:

ok(filename |> File.read |> Poison.Parser.parse)

Usage

use OkJose

Provides you with the following macros: ok, ok!, error, error!

use OkJose.Pipe

which provides you the defpipe macro.

ok/1

Pipes values into functions as long as they match {:ok, _}

{:ok, v} |> f |> g |> ok

ok!/1

Pipes values into functions but if at any point a value does not match {:ok, _} raises a match error.

defpipe

Allows you to define custom pipe patterns, for example the previous ok!, macro is defined like:

defpipe ok! do
{:ok, value} -> value
end

The do block of defpipe has the same form as the elixir case expression.

So for example, you may define a pipe to work on kittens only:

defpipe purr do
c = %Kitten{} -> c
t = %Tiger{domesticated: true} -> t
end

Example

ok math
def dup(x), do: {:ok, x * 2}
def nop(x), do: {:error, x}
{:ok, 12} |> dup |> dup |> ok # => {:ok, 48}
{:ok, 24} |> nop |> dup |> ok # => {:error, 24}
{:ok, 24} |> dup |> ok! # => 48
{:ok, 24} |> nop |> dup |> ok! # raises
kittens
defpipe ok_kitten do
k = %Kitten{} -> k
t = %Tiger{domesticated: true} -> t
end
def purr(%Kitten{}), do: "purr"
def purr(%Tiger{}), do: "PuRRR"
%Kitten{} |> purr |> ok_kitten #=> "purr"
ok_kitten( %Doggie{} |> purr ) #=> %Doggie{}
# using do/end syntax
# block executed only for matching kittens
%Kitten{} |> (ok_kitten do
k -> purr(k)
end)

About ok

I wanted name this library ok, but the hex package name was already taken. So I just wanted to make a tribute to @josevalim.

Actually both projects are trying to solve the same issue. But I think this one has an easier syntax that consist of just piping to ok

Is it any good?

Yes