ResultEx v0.1.0 ResultEx View Source
ResultEx is a module for handling functions returning a ResultEx.t/0.
This module is inspired by the f# Result module, and Railway Oriented Programming as explained by Scott Wlaschin.
A result can be either the tuple {:ok, term} where term will be the expected return value of a function, or the tuple {:error, term} where term will be an explanation of what went wrong while executing a function.
Using this module, it will be possible to combine functions that return a ResultEx.t/0, and functions that take the value contained by the ok variant.
In the case one of the functions returns an error variant, subsequent functions expecting an ok result can be prevented from being executed.
Also, functions can be connected that will only execute in the case of an error.
Examples
iex> defmodule ResultExExample do
...>
...> def divide(0, _), do: {:error, :zero_division_exception}
...> def divide(0.0, _), do: {:error, :zero_division_exception}
...> def divide(x, y), do: ResultEx.return(x / y)
...> def subtract(x, y), do: ResultEx.return(x - y)
...>
...> end
...>
...> ResultExExample.divide(4, 2)
...> |> ResultEx.bind(fn x -> ResultExExample.subtract(x, 2) end)
{:ok, 0.0}
iex> ResultExExample.divide(4, 2)
...> |> ResultEx.bind(fn x -> ResultExExample.subtract(x, 2) end)
...> |> ResultEx.bind(fn x -> ResultExExample.divide(x, 2) end)
...> |> ResultEx.bind(fn x -> ResultExExample.subtract(x, 2) end)
{:error, :zero_division_exception}
iex> ResultExExample.divide(0, 2)
...> |> ResultEx.or_else(2)
2
iex> ResultExExample.divide(0, 2)
...> |> ResultEx.or_else_with(fn _err -> {:ok, 0} end)
{:ok, 0}
Link to this section Summary
Functions
Executes or partially executes the function given as value of the first ResultEx.t/0,
and applies it with the value of the second ResultEx.t/0.
If the function has an arity greater than 1, the returned ResultEx.t/0 value will be the function partially applied.
(The function name is ‘appl’ rather than ‘apply’ to prevent import conflicts with ‘Kernel.apply’)
Partially applies ResultEx.bind/2 with the passed function
Applies a function with the value of the ResultEx.t/0.
The passed function is expected to return a ResultEx.t/0.
This can be useful for chaining functions together that elevate values into ResultEx.t/0s
Unwraps the ResultEx.t/0 to return its value.
The second argument will be a specific error message to throw when the ResultEx.t/0 is an Error
Flatten nested ResultEx.t/0s into a single ResultEx.t/0
Flattens an Enum.t/0 of ResultEx.t/0s into a ResultEx.t/0 of enumerables
Partially applies ResultEx.map/2 with the passed function
Runs a function against the ResultEx.t/0s value.
If the ResultEx.t/0 is an error, the function will not be executed
Unwraps the ResultEx.t/0 to return its value.
If the ResultEx.t/0 is an error, it will return the default value passed as second argument instead
Unwraps the ResultEx.t/0 to return its value.
If the ResultEx.t/0 is an error, the given function will be applied with the unwrapped error instead
Elevates a value to a ResultEx.t/0 type
Converts the ResultEx.t/0 to an Option.
An Option is a {:some, term} tuple pair, or the :none atom
Unwraps the ResultEx.t/0 to return its value.
Throws an error if the ResultEx.t/0 is an error
Link to this section Types
Link to this section Functions
Executes or partially executes the function given as value of the first ResultEx.t/0,
and applies it with the value of the second ResultEx.t/0.
If the function has an arity greater than 1, the returned ResultEx.t/0 value will be the function partially applied.
(The function name is ‘appl’ rather than ‘apply’ to prevent import conflicts with ‘Kernel.apply’)
Examples
iex> value_result = {:ok, 1}
...> function_result = {:ok, fn value -> value + 1 end}
...> ResultEx.appl(function_result, value_result)
{:ok, 2}
iex> {:ok, fn value1, value2, value3 -> value1 + value2 + value3 end}
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 2})
...> |> ResultEx.appl({:ok, 3})
{:ok, 6}
iex> {:error, "no such function"}
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 1})
{:error, "no such function"}
iex> {:ok, fn value1, value2, value3 -> value1 + value2 + value3 end}
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:ok, 1})
...> |> ResultEx.appl({:error, "no such value"})
{:error, "no such value"}
Partially applies ResultEx.bind/2 with the passed function.
Applies a function with the value of the ResultEx.t/0.
The passed function is expected to return a ResultEx.t/0.
This can be useful for chaining functions together that elevate values into ResultEx.t/0s.
Examples
iex> divide = fn
...> 0 -> {:error, "Zero division"}
...> n -> {:ok, n / 2}
...> end
...> divide.(4)
...> |> ResultEx.bind(divide)
{:ok, 1.0}
iex> divide = fn
...> 0 -> {:error, "Zero division"}
...> n -> {:ok, n / 2}
...> end
...> divide.(0)
...> |> ResultEx.bind(divide)
{:error, "Zero division"}
Unwraps the ResultEx.t/0 to return its value.
The second argument will be a specific error message to throw when the ResultEx.t/0 is an Error.
Examples
iex> ResultEx.return(5)
...> |> ResultEx.expect!("The value was not what was expected")
5
Flatten nested ResultEx.t/0s into a single ResultEx.t/0.
Examples
iex> ResultEx.return(5)
...> |> ResultEx.return()
...> |> ResultEx.return()
...> |> ResultEx.flatten()
{:ok, 5}
iex> {:ok, {:ok, {:error, "Oops"}}}
...> |> ResultEx.flatten()
{:error, "Oops"}
Flattens an Enum.t/0 of ResultEx.t/0s into a ResultEx.t/0 of enumerables.
Examples
iex> [{:ok, 1}, {:ok, 2}, {:ok, 3}]
...> |> ResultEx.flatten_enum()
{:ok, [1, 2, 3]}
iex> [{:ok, 1}, {:error, "Oops"}, {:ok, 3}]
...> |> ResultEx.flatten_enum()
{:error, "Oops"}
iex> %{a: {:ok, 1}, b: {:ok, 2}, c: {:ok, 3}}
...> |> ResultEx.flatten_enum()
{:ok, %{a: 1, b: 2, c: 3}}
iex> %{a: {:ok, 1}, b: {:error, "Oops"}, c: {:ok, 3}}
...> |> ResultEx.flatten_enum()
{:error, "Oops"}
Partially applies ResultEx.map/2 with the passed function.
Runs a function against the ResultEx.t/0s value.
If the ResultEx.t/0 is an error, the function will not be executed.
Examples
iex> result = {:ok, 1}
...> ResultEx.map(result, &(&1 + 1))
{:ok, 2}
iex> result = {:error, "Oops"}
...> ResultEx.map(result, &(&1 + 1))
{:error, "Oops"}
Unwraps the ResultEx.t/0 to return its value.
If the ResultEx.t/0 is an error, it will return the default value passed as second argument instead.
Examples
iex> ResultEx.return(5)
...> |> ResultEx.or_else(4)
5
iex> {:error, "Oops"}
...> |> ResultEx.or_else(4)
4
Unwraps the ResultEx.t/0 to return its value.
If the ResultEx.t/0 is an error, the given function will be applied with the unwrapped error instead.
Examples
iex> ResultEx.return(5)
...> |> ResultEx.or_else_with(fn err -> IO.inspect(err) end)
5
iex> {:error, "Oops"}
...> |> ResultEx.or_else_with(fn err -> err <> "!" end)
"Oops!"
Elevates a value to a ResultEx.t/0 type.
Examples
iex> ResultEx.return(1)
{:ok, 1}
Converts the ResultEx.t/0 to an Option.
An Option is a {:some, term} tuple pair, or the :none atom.
Examples
iex> ResultEx.return(5)
...> |> ResultEx.to_option()
{:some, 5}
iex> {:error, "Oops"}
...> |> ResultEx.to_option()
:none
Unwraps the ResultEx.t/0 to return its value.
Throws an error if the ResultEx.t/0 is an error.
Examples
iex> ResultEx.return(5)
...> |> ResultEx.unwrap!()
5