[![mix test](https://github.com/trevorite/defr/workflows/mix%20test/badge.svg)](https://github.com/trevorite/defr/actions)
[![Hex version badge](https://img.shields.io/hexpm/v/defr.svg)](https://hex.pm/packages/defr)
[![License badge](https://img.shields.io/hexpm/l/defr.svg)](https://github.com/trevorite/defr/blob/master/LICENSE.md)
`defr` is `def` for Witchcraft's Reader monads.
## Installation
The package can be installed by adding `defr` to your list of dependencies
in `mix.exs`:
```elixir
def deps do
[{:defr, "~> 0.1"}]
end
```
To format `defr` like `def`, add following to your `.formatter.exs`
```elixir
locals_without_parens: [defr: 2]
```
## Usage
```elixir
defmodule Defr.NestedCallTest do
use ExUnit.Case, async: true
use Defr
alias Algae.Reader
alias Algae.Either.Right
defmodule User do
use Defr
defstruct [:id, :name]
defr get_by_id(user_id) do
Repo.get(__MODULE__, user_id) |> Right.new()
end
end
defmodule Accounts do
use Defr
defr get_user_by_id(user_id) do
monad %Right{} do
user <- User.get_by_id(user_id)
user |> Right.new()
end
end
end
defmodule UserController do
use Defr
defr profile(user_id_str) do
user_id = String.to_integer(user_id_str)
Accounts.get_user_by_id(user_id)
end
end
test "inject 3rd layer" do
assert [{:profile, 1}] == UserController.__reader_funs__()
assert %Right{right: %User{id: 1, name: "josevalim"}} ==
UserController.profile("1")
|> Reader.run(%{&Repo.get/2 => fn _, _ -> %User{id: 1, name: "josevalim"} end})
end
test "inject 2nd layer" do
assert [{:get_user_by_id, 1}] == Accounts.__reader_funs__()
assert %Right{right: %User{id: 2, name: "chrismccord"}} ==
UserController.profile("2")
|> Reader.run(%{
&User.get_by_id/1 => fn _ ->
Reader.new(fn _ -> Right.new(%User{id: 2, name: "chrismccord"}) end)
end
})
end
end
```
### mock
If you don't need pattern matching in mock function, `mock/1` can be used to reduce boilerplates.
```elixir
UserController.profile("1") |> Reader.run(%{&Repo.get/2 => fn _, _ -> %User{} end})
```
can be changed to
```elixir
UserController.profile("1") |> Reader.run(%{&Repo.get/2 => mock(%User{})})
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE.md) file for details