Description
Environment
- Elixir & Erlang/OTP versions (elixir --version): 1.7.2
- Operating system: macOS
Current behavior
I wanted to create macro that would allow me to remove boilerplate over generating structures for events in my application. To document such structures I wanted to use @doc
to simulate feeling that these are normal parts of the external module instead of being separate modules, ex.:
defmodule MyApp.Event do
import Events
@moduledoc false
@doc """
Creation of new submission
"""
@doc deprecated: "Foo"
defevent SubmissionCreated,
id: any(),
name: String.t(),
author: [map()]
end
While basic implementation is dumb easy documentation is quite challenging. What I have achieved is:
defmodule Events do
@moduledoc false
defmacro defevent(module, fields \\ []) do
keys = Keyword.keys(fields)
quote do
docs = Module.get_attribute(__MODULE__, :doc)
deprecated = case Module.get_attribute(__MODULE__, :deprecated) do
nil -> []
value -> [deprecated: value]
end
{set, _} = :elixir_module.data_tables(__MODULE__)
metadata = case :ets.lookup(set, {:doc, :meta}) do
[{{:doc, :meta}, metadata, _}] -> deprecated ++ Keyword.new(metadata)
[] -> deprecated
end
defmodule unquote(module) do
if docs, do: Module.put_attribute(__MODULE__, :moduledoc, docs)
if metadata != [], do: @moduledoc metadata
@type t :: %__MODULE__{unquote_splicing(fields)}
defstruct unquote(keys)
end
:elixir_module.delete_definition_attributes(__ENV__, nil, nil, nil, nil, nil)
end
end
end
Which is fairly ok, except of the part where I need manually get data from ETS for documentation metadata. It cannot be mitigated by using Module.get_attribute/2
as it explicitly requires atom as a second argument while metadata are stored under {:doc, :meta}
.
Expected behavior
Somehow allow fetching documentation metadata in macros. This would allow macro writers to utilise that metadata in some way like example above.