Current section
Files
Jump to
Current section
Files
lib/module_information.ex
defmodule Doctor.ModuleInformation do
@moduledoc """
"""
alias __MODULE__
alias Doctor.{Docs, Specs}
defstruct ~w(module file_full_path file_relative_path file_ast docs_version module_doc metadata docs specs user_defined_functions)a
@doc """
Breaks down the docs format entry returned from Code.fetch_docs(MODULE)
"""
def build({docs_version, _annotation, _language, _format, module_doc, metadata, docs}, module) do
{:ok, module_specs} = Code.Typespec.fetch_specs(module)
%ModuleInformation{
module: module,
file_full_path: get_full_file_path(module),
file_relative_path: get_relative_file_path(module),
file_ast: nil,
docs_version: docs_version,
module_doc: module_doc,
metadata: metadata,
docs: Enum.map(docs, &Docs.build/1),
specs: Enum.map(module_specs, &Specs.build/1),
user_defined_functions: nil
}
end
def load_file_ast(%ModuleInformation{} = module_info) do
ast =
module_info.file_full_path
|> File.read!()
|> Code.string_to_quoted!()
%{module_info | file_ast: ast}
end
def load_user_defined_functions(%ModuleInformation{} = module_info) do
{_ast, functions} = Macro.prewalk(module_info.file_ast, [], &parse_ast_node_for_def/2)
%{module_info | user_defined_functions: functions}
end
defp get_full_file_path(module) do
module.module_info()
|> Keyword.get(:compile)
|> Keyword.get(:source)
|> to_string()
end
defp get_relative_file_path(module) do
module
|> get_full_file_path()
|> Path.relative_to(File.cwd!())
end
defp parse_ast_node_for_def(
{:def, _def_line,
[{:when, _line_when, [{function_name, _function_line, args}, _guard]}, _do_block]} =
tuple,
acc
) do
{tuple, [{function_name, get_function_arity(args)} | acc]}
end
defp parse_ast_node_for_def(
{:def, _def_line, [{function_name, _function_line, args}, _do_block]} = tuple,
acc
) do
{tuple, [{function_name, get_function_arity(args)} | acc]}
end
defp parse_ast_node_for_def(tuple, acc) do
{tuple, acc}
end
defp get_function_arity(nil), do: 0
defp get_function_arity(args), do: length(args)
end