Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/ex_doc/formatter/html.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule ExDoc.Formatter.HTML do
@doc """
Generate HTML documentation for the given modules.
"""
@spec run(list, ExDoc.Config.t()) :: String.t()
@spec run([module], ExDoc.Config.t()) :: String.t()
def run(project_nodes, config) when is_map(config) do
config = normalize_config(config)
config = %{config | output: Path.expand(config.output)}
Expand Down
41 changes: 34 additions & 7 deletions lib/ex_doc/formatter/html/autolink.ex
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do

%{
aliases: aliases,
config: config,
docs_refs: docs_refs ++ types_refs,
extension: extension,
lib_dirs: lib_dirs,
Expand All @@ -121,7 +122,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do
def project_doc(nil, _id, _compiled), do: nil

def project_doc(string, id, compiled) when is_binary(string) and is_map(compiled) do
config =
options =
compiled
|> Map.put(:id, id)
|> Map.put_new(:module_id, nil)
Expand All @@ -131,7 +132,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do

string =
Enum.reduce(@regexes, string, fn {kind, language, link_type}, acc ->
link(acc, language, kind, link_type, config)
link(acc, language, kind, link_type, options)
end)

postprocess(string)
Expand Down Expand Up @@ -340,12 +341,14 @@ defmodule ExDoc.Formatter.HTML.Autolink do
#
# It accepts a list of `options` used in the replacement functions.
# - `:aliases
# - `:docs_refs`
# - `:config`
# - `:docs_refs` - Docs and types references
# - `:extension` - Default value is `".html"`
# - `:lib_dirs`
# - `:locals` - A list of local functions
# - `:module_id` - Module of the current doc. Default value is `nil`
# - `:modules_refs` - List of modules available
# - `:skip_undefined_reference_warnings_on`
#
# Internal options:
# - `:preprocess?` - `true` or `false`. Do preprocessing and postprocessing, such as replacing backticks
Expand Down Expand Up @@ -380,7 +383,16 @@ defmodule ExDoc.Formatter.HTML.Autolink do
pmfa = {_prefix, module, function, arity} = split_match(kind, match)
text = default_text(":", link_type, pmfa, text)

if doc = module_docs(:erlang, module, lib_dirs) do
module_or_mfa =
case kind do
:module ->
module

:function ->
{module, function, arity}
end

if doc = module_docs(:erlang, module_or_mfa, lib_dirs) do
case kind do
:module ->
"[#{text}](#{doc}#{module}.html)"
Expand Down Expand Up @@ -467,7 +479,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do

all

doc = module_docs(:elixir, module, lib_dirs) ->
doc = module_docs(:elixir, {module, function, arity}, lib_dirs) ->
"[#{text}](#{doc}#{module}.html##{prefix}#{enc_h(function)}/#{arity})"

true ->
Expand Down Expand Up @@ -539,9 +551,15 @@ defmodule ExDoc.Formatter.HTML.Autolink do
defp default_lib_dirs(:erlang),
do: erlang_lib_dirs()

defp module_docs(:elixir, {module, function, arity}, lib_dirs),
do: lib_dirs_to_doc({"Elixir." <> module, function, arity}, lib_dirs)

defp module_docs(:elixir, module, lib_dirs),
do: lib_dirs_to_doc("Elixir." <> module, lib_dirs)

defp module_docs(:erlang, {module, function, arity}, lib_dirs),
do: lib_dirs_to_doc({module, function, arity}, lib_dirs)

defp module_docs(:erlang, module, lib_dirs),
do: lib_dirs_to_doc(module, lib_dirs)

Expand Down Expand Up @@ -588,7 +606,16 @@ defmodule ExDoc.Formatter.HTML.Autolink do
defp doc_prefix(%{type: c}) when c in [:callback, :macrocallback], do: "c:"
defp doc_prefix(%{type: _}), do: ""

defp lib_dirs_to_doc(module, lib_dirs) do
defp lib_dirs_to_doc(module, lib_dirs) when is_atom(module) do
lib_dirs_to_doc({"#{module}", "", ""}, lib_dirs)
end

defp lib_dirs_to_doc(module, lib_dirs) when is_binary(module) do
lib_dirs_to_doc({module, "", ""}, lib_dirs)
end

defp lib_dirs_to_doc({module, function, arity}, lib_dirs)
when is_binary(module) and is_binary(function) and is_binary(arity) do
case :code.where_is_file('#{module}.beam') do
:non_existing ->
nil
Expand All @@ -600,7 +627,7 @@ defmodule ExDoc.Formatter.HTML.Autolink do
|> Enum.filter(fn {lib_dir, _} -> String.starts_with?(path, lib_dir) end)
|> Enum.sort_by(fn {lib_dir, _} -> -byte_size(lib_dir) end)
|> case do
[{_, doc} | _] -> doc
[{_doc_path, doc} | _] -> doc
_ -> nil
end
end
Expand Down
65 changes: 51 additions & 14 deletions lib/ex_doc/retriever.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,25 @@ defmodule ExDoc.Retriever do
alias ExDoc.Retriever.Error

@doc """
Extract documentation from all modules in the specified directory or directories.
Extracts documentation from all modules in the specified directory or directories.
"""
@spec docs_from_dir(Path.t() | [Path.t()], ExDoc.Config.t()) :: [ExDoc.ModuleNode.t()]
def docs_from_dir(dir, config) when is_binary(dir) do
pattern = if config.filter_prefix, do: "Elixir.#{config.filter_prefix}*.beam", else: "*.beam"
files = Path.wildcard(Path.expand(pattern, dir))
docs_from_files(files, config)
dir
|> __docs_from_dir__(config)
|> reject_docs_with_moduledoc_false()
end

def docs_from_dir(dirs, config) when is_list(dirs) do
Enum.flat_map(dirs, &docs_from_dir(&1, config))
dirs
|> Enum.flat_map(&__docs_from_dir__(&1, config))
|> reject_docs_with_moduledoc_false()
end

defp __docs_from_dir__(dir, config) do
dir
|> files_from_pattern(config)
|> docs_from_files(config)
end

@doc """
Expand All @@ -35,20 +43,44 @@ defmodule ExDoc.Retriever do
end

@doc """
Extract documentation from all modules in the list `modules`
Extracts documentation from all modules in the list `modules`
"""
@spec docs_from_modules([atom], ExDoc.Config.t()) :: [ExDoc.ModuleNode.t()]
@spec docs_from_modules([module], ExDoc.Config.t()) :: [ExDoc.ModuleNode.t()]
def docs_from_modules(modules, config) when is_list(modules) do
modules
|> Enum.flat_map(&get_module(&1, config))
|> reject_docs_with_moduledoc_false()
|> Enum.sort_by(fn module ->
{GroupMatcher.group_index(config.groups_for_modules, module.group), module.id}
end)
end

## Helpers

defp reject_docs_with_moduledoc_false(docs) do
Enum.reject(docs, fn
{:module_doc_hidden, _} -> true
_ -> false
end)
end

defp files_from_pattern(dir, config) do
pattern =
if config.filter_prefix do
"Elixir.#{config.filter_prefix}*.beam"
else
"*.beam"
end

pattern
|> Path.expand(dir)
|> Path.wildcard()
end

defp filename_to_module(name) do
name = Path.basename(name, ".beam")
String.to_atom(name)
name
|> Path.basename(".beam")
|> String.to_atom()
end

# Get all the information from the module and compile
Expand All @@ -60,10 +92,15 @@ defmodule ExDoc.Retriever do
raise Error, "module #{inspect(module)} is not defined/available"
end

if docs_chunk = docs_chunk(module) do
generate_node(module, docs_chunk, config)
else
[]
case docs_chunk(module) do
false ->
[]

:hidden ->
%{module_doc_hidden: module}

docs_chunk ->
generate_node(module, docs_chunk, config)
end
end

Expand All @@ -89,7 +126,7 @@ defmodule ExDoc.Retriever do
if function_exported?(module, :__info__, 1) do
case Code.fetch_docs(module) do
{:docs_v1, _, _, _, :hidden, _, _} ->
false
:hidden

{:docs_v1, _, _, _, _, _, _} = docs ->
docs
Expand Down
7 changes: 7 additions & 0 deletions test/ex_doc/retriever_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ defmodule ExDoc.RetrieverTest do
"""
end

test "returns modules with @doc false" do
assert [CompiledWithDocs, CompiledWithDocs] ==
["CompiledWithDocs", "ModuledocFalse", "CompiledWithDocs"]
|> docs_from_files()
|> Enum.map(& &1.module)
end

test "returns module group" do
[module_node] =
docs_from_files(["CompiledWithDocs"], groups_for_modules: [Group: [CompiledWithDocs]])
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/moduledoc_false.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule ModuledocFalse do
@moduledoc false

@doc """
Foo is the new bar
"""
def foo do
:foo
end
end