Packages

A series of macros, and utilities to help hadling your elixir tonics.

Current section

Files

Jump to
rubbergloves lib annotations annotatable.ex
Raw

lib/annotations/annotatable.ex

defmodule Rubbergloves.Annotatable do
@moduledoc"""
Add simple annotations to elixir methods which can be used later to do some funkiness see https://medium.com/@cowen/annotations-in-elixir-450015ecdd97
## Usage
```
defmodule Example do
use Rubbergloves.Annotatable, [:bar, :foo]
@bar true
def bar_method do end
@foo [:test]
@bar true
def foo_bar_method do end
def no_annotation_method do end
@baz "ads"
def undefined_annotation_method do end
end
```
And later:
```
Example.annotations
```
Gives:
```
%{
bar_method: [%{annotation: :bar, value: true}],
foo_bar_method: [
%{annotation: :bar, value: true},
%{annotation: :foo, value: [:test]}
]
}
```
"""
defmacro __using__(args) do
quote do
def __on_annotation_(_) do
quote do end
end
@annotations %{}
@supported_annotations unquote(args)
@on_definition { unquote(__MODULE__), :__on_definition__ }
@before_compile { unquote(__MODULE__), :__before_compile__ }
import Rubbergloves.Annotatable
require Rubbergloves.Annotatable
end
end
def __on_definition__(env, _kind, name, _args, _guards, _body) do
Module.get_attribute(env.module, :supported_annotations) |> Enum.each(&annotate_method(&1, env.module, name))
end
def annotate_method(annotation, module, method) do
annotations = Module.get_attribute(module, :annotations)
value = Module.get_attribute(module, annotation)
Module.delete_attribute(module, annotation)
update_annotations(annotation, annotations, module, method, value)
end
def update_annotations(_, _, _, _, nil), do: :no_op
def update_annotations(annotation, annotations, module, method, value) do
method_annotations = Map.get(annotations, method, []) ++ [%{ annotation: annotation, value: value}]
Module.put_attribute(module, :annotations, annotations |> Map.put(method, method_annotations))
end
defmacro __before_compile__(_env) do
quote do
def annotations do
@annotations
end
def annotated_with(annotation) do
@annotations
|> Map.keys
|> Enum.filter(fn method ->
Map.get(@annotations, method, [])
|> Enum.map(fn a -> a.annotation end)
|> Enum.member?(annotation)
end)
end
end
end
end