Packages

Makes your structures enumerable!

Current section

Files

Jump to
make_enumerable lib make_enumerable.ex
Raw

lib/make_enumerable.ex

defmodule MakeEnumerable do
@moduledoc """
Makes your structures enumerable!
The `MakeEnumerable` module injects `defimpl Enumerable` for your structs,
as structs are basically `maps` with special tag (member) `__struct__`.
The module hides the tag `__struct__` and delegates all other members
to map to be `Enumerable`.
```
defmodule Bar do
use MakeEnumerable
defstruct foo: "a", baz: 10
end
iex> import Bar
iex> Enum.map(%Bar{}, fn({k, v}) -> {k, v} end)
[baz: 10, foo: "a"]
```
"""
defmacro __using__(_options) do
quote do
import unquote(__MODULE__)
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(_env) do
quote do
defimpl Enumerable, for: __MODULE__ do
def reduce(map, acc, fun) do
map = :maps.without([:"__struct__"], map)
do_reduce(:maps.to_list(map), acc, fun)
end
defp do_reduce(_, {:halt, acc}, _fun), do: {:halted, acc}
defp do_reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &do_reduce(list, &1, fun)}
defp do_reduce([], {:cont, acc}, _fun), do: {:done, acc}
defp do_reduce([h|t], {:cont, acc}, fun), do: do_reduce(t, fun.(h, acc), fun)
def member?(map, {:"__struct__", value}) do
{:ok, false}
end
def member?(map, {key, value}) do
{:ok, match?({:ok, ^value}, :maps.find(key, map))}
end
def member?(_map, _other) do
{:ok, false}
end
def count(map) do
{:ok, map_size(map) - 1}
end
end
end
end
end