defmodule Fex.Lazy do
@moduledoc """
Documentation for `Fex`.
Lazy module won't execute the code. It will instead wrap it inside
function and return nested function. This make the module "pure" as
it's actually not executing any of its code
Example:
```
def allowed?(email, read_fn \\ &File.read/1) do
Lazy.task(fn () -> read_fn.("list.json") end)
|> Lazy.chain(&Jason.decode/1)
|> Lazy.apply(&check_email(&1, email))
|> Lazy.fold(& &1, fn error ->
Logger.error("User service error occurred")
IO.inspect(error)
false
end)
end
Calling the above function results in a function returned. None of
the code is executed. You can "trigger" the execution by just calling
the resulted function:
```
iex(1)> function = allowed?("test@example.com")
iex(2)> function.()
true
```
"""
def task(function) do
fn () ->
function.()
end
end
def chain(acc, function) do
fn () ->
case acc.() do
{:ok, data} -> function.(data)
{:error, error} -> {:error, error}
end
end
end
def apply(acc, function) do
fn () ->
case acc.() do
{:ok, data} -> {:ok, function.(data)}
{:error, error} -> {:error, error}
end
end
end
def map(acc, iteration_fn) do
fn () ->
case acc.() do
{:ok, data} -> Enum.map(data, iteration_fn)
{:error, error} -> {:error, error}
end
end
end
def fold(acc, success_fn, error_fn) do
fn () ->
case acc.() do
{:ok, data} -> success_fn.(data)
{:error, error} -> error_fn.(error)
end
end
end
end