defmodule Alchemist.Helpers.ModuleInfo do
|
|
|
|
@moduledoc false
|
|
|
|
def moduledoc?(module) do
|
|
case Code.get_docs module, :moduledoc do
|
|
{_, doc} -> is_binary doc
|
|
_ -> false
|
|
end
|
|
end
|
|
|
|
def docs?(module, function) do
|
|
docs = Code.get_docs module, :docs
|
|
do_docs?(docs, function)
|
|
end
|
|
|
|
def expand_alias([name | rest] = list, aliases) do
|
|
module = Module.concat(Elixir, name)
|
|
Enum.find_value(aliases, list, fn {alias, mod} ->
|
|
if alias === module do
|
|
case Atom.to_string(mod) do
|
|
"Elixir." <> mod ->
|
|
Module.concat [mod|rest]
|
|
_ ->
|
|
mod
|
|
end
|
|
end
|
|
end) |> normalize_module
|
|
end
|
|
|
|
def get_functions(module, hint) do
|
|
hint = to_string hint
|
|
{module, _} = Code.eval_string(module)
|
|
functions = get_module_funs(module)
|
|
|
|
list = Enum.reduce functions, [], fn({f, a}, acc) ->
|
|
case :lists.keyfind(f, 1, acc) do
|
|
{f, aa} -> :lists.keyreplace(f, 1, acc, {f, [a|aa]})
|
|
false -> [{f, [a]}|acc]
|
|
end
|
|
end
|
|
|
|
do_get_functions(list, hint) |> :lists.sort()
|
|
end
|
|
|
|
def has_function?(module, function) do
|
|
List.keymember? get_module_funs(module), function, 0
|
|
end
|
|
|
|
defp do_get_functions(list, "") do
|
|
all_functions(list)
|
|
end
|
|
|
|
defp do_get_functions(list, hint) do
|
|
all_functions(list, hint)
|
|
end
|
|
|
|
defp get_module_funs(module) do
|
|
case Code.ensure_loaded(module) do
|
|
{:module, _} ->
|
|
module.module_info(:functions) ++ module.__info__(:macros)
|
|
_otherwise ->
|
|
[]
|
|
end
|
|
end
|
|
|
|
defp all_functions(list) do
|
|
for {fun, arities} <- list, name = Atom.to_string(fun) do
|
|
"#{name}/#{List.first(arities)}"
|
|
end
|
|
end
|
|
|
|
defp all_functions(list, hint) do
|
|
for {fun, arities} <- list,
|
|
name = Atom.to_string(fun),
|
|
String.starts_with?(name, hint) do
|
|
"#{name}/#{List.first(arities)}"
|
|
end
|
|
end
|
|
|
|
def all_applications_modules do
|
|
for [app] <- loaded_applications(),
|
|
{:ok, modules} = :application.get_key(app, :modules),
|
|
module <- modules do
|
|
module
|
|
end
|
|
end
|
|
|
|
defp do_docs?([head|tail], function) do
|
|
{{func, _}, _, _, _, doc} = head
|
|
if func == function and is_binary(doc) do
|
|
true
|
|
else
|
|
do_docs?(tail, function)
|
|
end
|
|
end
|
|
defp do_docs?([], _function), do: false
|
|
defp do_docs?(nil, _function), do: false
|
|
|
|
defp loaded_applications do
|
|
# If we invoke :application.loaded_applications/0,
|
|
# it can error if we don't call safe_fixtable before.
|
|
# Since in both cases we are reaching over the
|
|
# application controller internals, we choose to match
|
|
# for performance.
|
|
:ets.match(:ac_tab, {{:loaded, :"$1"}, :_})
|
|
end
|
|
|
|
defp normalize_module(mod) do
|
|
if is_list(mod) do
|
|
Module.concat(mod)
|
|
else
|
|
mod
|
|
end
|
|
end
|
|
|
|
end
|