Packages

A package for extracting documentation from modules and their functions

Current section

Files

Jump to
documentation_extractor lib documentation_extractor.ex
Raw

lib/documentation_extractor.ex

defmodule DocumentationExtractor do
@moduledoc """
Extracts documentation from modules and their functions and callbacks
## Usecase example
```elixir
defmodule A do
@doc "execs"
def exec, do: :a
end
defmodule B do
@doc DocumentationExtractor.get_function_docs(A, :exec)
def exec, do: :b
end
```
"""
@default_lang nil
@doc """
Extracts documentation from a function on a module
## Examples
```elixir
iex> DocumentationExtractor.get_module_docs(ExampleModule)
"A example module\\n"
```
"""
@spec get_function_docs(
module(),
atom(),
nil | :function | :callback,
nil | integer(),
nil | binary()
) ::
binary()
def get_function_docs(
module,
function_name,
kind \\ nil,
arity \\ nil,
doc_lang \\ @default_lang
) do
with {:ok, _module_doc, docs} <- get_raw_docs(module) do
docs
|> Enum.find(&match_doc_entry(&1, {kind, function_name, arity}))
|> case do
{{_kind, _name, _arity}, _anno, _signature, doc, _metadata} ->
get_doc_with_lang(doc, doc_lang)
nil ->
""
end
end
end
@doc """
Extracts documentation from a module
## Examples
```elixir
iex> DocumentationExtractor.get_module_docs(ExampleModule)
"A example module\\n"
```
"""
@spec get_module_docs(module(), nil | binary()) :: binary()
def get_module_docs(module, doc_lang \\ @default_lang) do
with {:ok, module_doc, _docs} <- get_raw_docs(module) do
get_doc_with_lang(module_doc, doc_lang)
end
end
defp match_doc_entry(doc_entry, match = {kind, name, arity}) do
{entry_type = {_kind, _name, _arity}, _anno, _signature, _doc, _metadata} = doc_entry
case {kind, arity} do
{nil, nil} ->
match?({_kind, ^name, _arity}, entry_type)
{kind, nil} ->
match?({^kind, ^name, _arity}, entry_type)
{nil, arity} ->
match?({_kind, ^name, ^arity}, entry_type)
{_kind, _arity} ->
entry_type == match
end
end
defp get_raw_docs(module) do
with {:docs_v1, _anno, :elixir, _format, module_doc, _metadata, docs} <-
Code.fetch_docs(module) do
{:ok, module_doc, docs}
end
end
defp get_doc_with_lang(docs_map, nil) when is_map(docs_map) do
docs_map
|> Map.to_list()
|> List.first()
|> case do
{_lang, doc} -> doc
nil -> ""
end
end
defp get_doc_with_lang(docs_map, lang) when is_map(docs_map) do
Map.get(docs_map, lang, "")
end
defp get_doc_with_lang(_, _), do: ""
end