Packages

Runs edoc on multiple apps and stitches the results together

Current section

Files

Jump to
medoc src medoc.erl
Raw

src/medoc.erl

-module(medoc).
-behaviour(provider).
-export([init/1, do/1, format_error/1]).
-define(PROVIDER, medoc).
-define(DEPS, [edoc]).
-define(DOC_DIR, "doc").
-define(TOC_TEMPLATE, "toc.html").
-define(MODULE_TEMPLATE, "module.html").
-define(TOC_PLACEHOLDER, "{toc}").
-define(MODULE_PLACEHOLDER, "{module}").
-define(TOC_FILE, "modules-frame.html").
%% ==================================================
%% PUBLIC API
%% ==================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Provider = providers:create([
{name, ?PROVIDER},
{module, ?MODULE},
{bare, true},
{deps, ?DEPS},
{example, "rebar medoc"},
{opts, []},
{short_desc, "Generates edoc for all the apps"},
{desc, "Runs edoc and then recreates the table of contents"
" to include all the applications."}
]),
%% Put all the docs into single dir
% {edoc_opts, [{dir, "doc"}]}.
State2 = rebar_state:set(State, edoc_opts, [{dir, ?DOC_DIR}]),
{ok, rebar_state:add_provider(State2, Provider)}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
%% Explor the doc dir
Modules = get_modules(?DOC_DIR),
Html = build_toc(Modules),
ok = write_toc(Html),
{ok, State}.
get_modules(Path) ->
{ok, Files} = file:list_dir(Path),
Htmls = [F || F <- Files,
filename:extension(F) == ".html",
string:str(F, "index") == 0,
string:str(F, "overview") == 0,
string:str(F, "modules") == 0],
%% Chop off .html
Modules = [filename:basename(H, ".html") || H <- Htmls],
lists:sort(Modules).
-spec format_error(any()) -> iolist().
format_error(Reason) ->
io_lib:format("~p", [Reason]).
build_toc(Modules) ->
ModuleTemplate = module_template(),
ModuleHtml = build_module_html(ModuleTemplate, Modules),
TocTemplate = toc_template(),
build_template_html(ModuleHtml, TocTemplate).
write_toc(TocHtml) ->
file:write_file(filename:join(?DOC_DIR, ?TOC_FILE), TocHtml).
build_template_html(ModuleHtml, TocTemplate) ->
re:replace(TocTemplate, ?TOC_PLACEHOLDER, ModuleHtml, [global, {return, list}]).
build_module_html(Template, Modules) ->
ModuleHtmls = lists:reverse(build_module_htmls(Template, Modules, [])),
string_join("\r\n", ModuleHtmls).
build_module_htmls(_, [], Acc) -> Acc;
build_module_htmls(Template, [M|Rest], Acc) ->
M2 = re:replace(Template, ?MODULE_PLACEHOLDER, M, [global, {return,list}]),
build_module_htmls(Template, Rest, [M2 | Acc]).
module_template() ->
Dir = code:priv_dir(?MODULE),
{ok, File} = file:read_file(filename:join(Dir, ?MODULE_TEMPLATE)),
unicode:characters_to_list(File).
toc_template() ->
Dir = code:priv_dir(?MODULE),
{ok, File} = file:read_file(filename:join(Dir, ?TOC_TEMPLATE)),
unicode:characters_to_list(File).
%% Helper function:
%% https://erlangcentral.org/wiki/index.php?title=String_join_with
string_join(Join, L) ->
string_join(Join, L, fun(E) -> E end).
string_join(_Join, L=[], _Conv) ->
L;
string_join(Join, [H|Q], Conv) ->
lists:flatten(lists:concat(
[Conv(H)|lists:map(fun(E) -> [Join, Conv(E)] end, Q)]
)).