defmodule Forum.Modules do @moduledoc """ Snapshot of every loaded Erlang/Elixir module with its OTP app and source file. Powers the /modules endpoint. """ @doc """ Returns a list of maps, one per loaded module, sorted by module name. Each map has string keys (JSON-friendly): "module" — module name, e.g. "Elixir.Forum.Router" "app" — OTP app the module belongs to, e.g. ":forum", or nil "source" — absolute path to the source file at compile time, or nil "mine" — true if the module belongs to this app """ def list do my_modules = MapSet.new(Application.spec(:forum, :modules) || []) :code.all_loaded() |> Enum.map(fn {mod, _beam} -> %{ "module" => inspect(mod), "app" => format_app(Application.get_application(mod)), "source" => source_for(mod), "mine" => MapSet.member?(my_modules, mod) } end) |> Enum.sort_by(& &1["module"]) end defp format_app(nil), do: nil defp format_app(app) when is_atom(app), do: inspect(app) defp source_for(mod) do case Keyword.get(mod.module_info(:compile), :source) do nil -> nil source when is_list(source) -> List.to_string(source) source when is_binary(source) -> source _ -> nil end rescue _ -> nil end end