Current section
Files
Jump to
Current section
Files
src/fn_exts.erl
-module(fn_exts).
-export([get_extensions/0, match_extensions/2, handle/5, behaviour_info/1]).
behaviour_info(callbacks) ->
[{handle, 3}];
behaviour_info(_) ->
undefined.
% returns the same format as code:all_loaded/0
all_modules() ->
[{list_to_atom(filename:rootname(filename:basename(F))), filename:dirname(F)} ||
P <- code:get_path(),
F <- filelib:wildcard(P ++ "/*.beam")] ++ code:all_loaded().
get_extensions() ->
lists:filtermap(fun parse_and_load_extension/1, all_modules()).
match_extensions(Name, Extensions) ->
Exts = lists:filter(fun (Info) -> is_extension_handler(Info, Name) end,
Extensions),
lists:sort(Exts).
parse_and_load_extension({Name, Path}) ->
StrName = atom_to_list(Name),
case is_extension(StrName) of
true ->
case code:ensure_loaded(Name) of
{module, _} -> ok;
{error, Reason} ->
io:format("error loading extension module ~p: ~p~n",
[Name, Reason])
end,
{true, {Name, StrName, Path}};
false -> false
end.
handle(Name, Path, Ast, State, Extensions) ->
case match_extensions(Name, Extensions) of
[] -> {error, notfound};
Exts -> handle(Path, Ast, State, Exts)
end.
handle(_Path, Ast, State, []) ->
{{error, {nomatch, Ast}}, State};
handle(Path, Ast, State, [{Module, _ModStr, _ModPath}|Exts]) ->
%io:format("looking for handler ~p:handle/3~n", [Module]),
try erlang:function_exported(Module, handle, 3) of
true ->
%io:format("handler ~p:handle/3 found~n", [Module]),
case Module:handle(Path, Ast, State) of
next ->
%io:format("handler ~p:handle/3 returned next~n", [Module]),
handle(Path, Ast, State, Exts);
Other ->
%io:format("handler ~p:handle/3 returned ~p~n", [Module, Other]),
Other
end;
false->
%io:format("handler ~p:handle/3 not found~n", [Module]),
% TODO: return warning
handle(Path, Ast, State, Exts)
catch T:E ->
% TODO: return warning
%{error, {ext_handler_error, T, E}}
io:format("error calling handler ~p:handle/3 ~p: ~p~n", [Module, T, E]),
handle(Path, Ast, State, Exts)
end.
is_extension_handler({_AtomName, ModName, _Path}, Name) ->
ModPrefix = "fn_ext_" ++ Name,
lists:suffix(ModPrefix, ModName).
is_extension("fn_ext_" ++ _) -> true;
is_extension(_) -> false.