Current section
Files
Jump to
Current section
Files
lib/extractly.ex
defmodule Extractly do
@moduledoc """
Provide easy access to information inside the templates rendered by `mix xtra`
"""
@doc """
Returns docstring of a function (or nil)
Ex:
iex(1)> Extractly.functiondoc("Extractly.moduledoc/1")
[ " Returns docstring of a module (or nil)",
" Ex:",
"",
" Extractly.moduledoc(\\"Extractly\\")",
""
] |> Enum.join("\\n")
"""
def functiondoc(name) do
{module, function_name, arity} = _parse_entity_name(name)
case Code.ensure_loaded(module) do
{:module, _} -> _get_entity_doc(module, function_name, arity, :function)
_ -> nil
end
end
@doc """
Returns docstring of a macro (or nil)
Same naming convention for macros as for functions.
"""
def macrodoc(name) do
{module, macro_name, arity} = _parse_entity_name(name)
case Code.ensure_loaded(module) do
{:module, _} -> _get_entity_doc(module, macro_name, arity, :macro)
_ -> nil
end
end
@doc """
Returns docstring of a module (or nil)
Ex:
Extractly.moduledoc("Extractly")
"""
def moduledoc(name) do
module = String.replace(name, ~r{\A(?:Elixir\.)?}, "Elixir.") |> String.to_atom
case Code.ensure_loaded(module) do
{:module, _} -> _get_moduledoc(module)
_ -> nil
end
end
defp _get_entity_doc(module, name, arity, entity_type) do
if function_exported?(module, :__info__, 1) do
{:docs_v1, _, :elixir, _, _, _, docs} = Code.fetch_docs(module)
Enum.find_value(docs, &_find_entity_doc(&1, name, arity, entity_type))
end
end
defp _get_moduledoc(module) do
if function_exported?(module, :__info__, 1) do
case Code.fetch_docs(module) do
{:docs_v1, _, :elixir, _, %{"en" => module_doc}, _, _} -> module_doc
_ -> nil
end
# TODO: Check under which circomstances this code is needed if at all.
# case Code.get_docs(module, :moduledoc) do
# {_, docs} when is_binary(docs) ->
# docs
# _ -> nil
# end
end
end
@doc false
def version do
:application.ensure_started(:extractly)
with {:ok, version} = :application.get_key(:extractly, :vsn), do: to_string(version)
end
defp _find_entity_doc(doctuple, function_name, arity, entity_type) do
case doctuple do
{{^entity_type, ^function_name, ^arity}, _anno, _sign, %{"en" => doc}, _metadata} -> doc
_ -> nil
end
end
defp _parse_entity_name(name) do
names = String.split(name, ".")
[func | modules] = Enum.reverse(names)
module = ["Elixir" | Enum.reverse(modules)] |> Enum.join(".") |> String.to_atom()
[function_name, arity] = String.split(func, "/")
function_name = String.to_atom(function_name)
{arity, _} = Integer.parse(arity)
{module, function_name, arity}
end
end