Skip to content

Commit eae144f

Browse files
committed
Unify handling of docs for groups
1 parent 38485a1 commit eae144f

File tree

8 files changed

+63
-85
lines changed

8 files changed

+63
-85
lines changed

lib/ex_doc/config.ex

+21-6
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ defmodule ExDoc.Config do
2323
before_closing_head_tag: &__MODULE__.before_closing_head_tag/1,
2424
canonical: nil,
2525
cover: nil,
26-
default_group_for_doc: &__MODULE__.default_group_for_doc/1,
2726
deps: [],
27+
docs_groups: [],
2828
extra_section: nil,
2929
extras: [],
3030
favicon: nil,
3131
filter_modules: &__MODULE__.filter_modules/2,
3232
formatter: "html",
3333
formatters: [],
34+
group_for_doc: &__MODULE__.default_group_for_doc/1,
3435
groups_for_extras: [],
35-
groups_for_docs: [],
3636
groups_for_modules: [],
3737
homepage_url: nil,
3838
language: "en",
@@ -67,16 +67,16 @@ defmodule ExDoc.Config do
6767
before_closing_head_tag: (atom() -> String.t()) | mfa() | map(),
6868
canonical: nil | String.t(),
6969
cover: nil | Path.t(),
70-
default_group_for_doc: (keyword() -> String.t() | nil),
7170
deps: [{ebin_path :: String.t(), doc_url :: String.t()}],
71+
docs_groups: [String.t()],
7272
extra_section: nil | String.t(),
7373
extras: list(),
7474
favicon: nil | Path.t(),
7575
filter_modules: (module, map -> boolean),
7676
formatter: nil | String.t(),
7777
formatters: [String.t()],
78+
group_for_doc: (keyword() -> String.t() | nil),
7879
groups_for_extras: [{binary(), term()}],
79-
groups_for_docs: [{binary(), (keyword() -> boolean)}],
8080
groups_for_modules: [{binary(), term()}],
8181
homepage_url: nil | String.t(),
8282
language: String.t(),
@@ -113,13 +113,17 @@ defmodule ExDoc.Config do
113113
options
114114
end
115115

116+
apps = Keyword.get(options, :apps, [])
117+
116118
{groups_for_docs, options} = Keyword.pop(options, :groups_for_docs, [])
117119
{groups_for_extras, options} = Keyword.pop(options, :groups_for_extras, [])
118-
apps = Keyword.get(options, :apps, [])
119120

120121
{groups_for_modules, options} =
121122
Keyword.pop(options, :groups_for_modules, default_groups_for_modules(apps))
122123

124+
{default_group_for_doc, options} =
125+
Keyword.pop(options, :default_group_for_doc, &default_group_for_doc/1)
126+
123127
{skip_undefined_reference_warnings_on, options} =
124128
Keyword.pop(
125129
options,
@@ -137,7 +141,8 @@ defmodule ExDoc.Config do
137141

138142
preconfig = %__MODULE__{
139143
filter_modules: normalize_filter_modules(filter_modules),
140-
groups_for_docs: normalize_groups(groups_for_docs),
144+
docs_groups: for({group, _} <- groups_for_docs, do: to_string(group)),
145+
group_for_doc: normalize_groups_for_docs(groups_for_docs, default_group_for_doc),
141146
groups_for_extras: normalize_groups(groups_for_extras),
142147
groups_for_modules:
143148
normalize_groups(
@@ -176,6 +181,16 @@ defmodule ExDoc.Config do
176181
raise ArgumentError, "#{inspect(proglang)} is not supported"
177182
end
178183

184+
defp normalize_groups_for_docs(groups, default) do
185+
groups = normalize_groups(groups)
186+
187+
fn metadata ->
188+
Enum.find_value(groups, fn {group, function} ->
189+
function.(metadata) && group
190+
end) || default.(metadata)
191+
end
192+
end
193+
179194
defp normalize_groups(groups) do
180195
for {k, v} <- groups, do: {to_string(k), v}
181196
end

lib/ex_doc/group_matcher.ex

-8
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,6 @@ defmodule ExDoc.GroupMatcher do
3131
groups ++ Enum.sort(leftovers)
3232
end
3333

34-
@doc """
35-
Finds a matching group for the given function.
36-
"""
37-
def match_doc(group_patterns, callback, default, metadata) do
38-
match_group_patterns(group_patterns, fn pattern -> pattern.(metadata) end) ||
39-
callback.(metadata) || default
40-
end
41-
4234
@doc """
4335
Finds a matching group for the given module name, id, and metadata.
4436
"""

lib/ex_doc/retriever.ex

+7-28
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,10 @@ defmodule ExDoc.Retriever do
137137

138138
{doc_line, doc_file, format, source_doc, doc, metadata} = get_module_docs(module_data, source)
139139

140-
default_group = config.default_group_for_doc
141-
groups_for_docs = config.groups_for_docs
140+
group_for_doc = config.group_for_doc
142141
annotations_for_docs = config.annotations_for_docs
143142

144-
docs_groups =
145-
Enum.uniq(Enum.map(groups_for_docs, &elem(&1, 0)) ++ module_data.default_groups)
146-
147-
docs = get_docs(module_data, source, default_group, groups_for_docs, annotations_for_docs)
143+
docs = get_docs(module_data, source, group_for_doc, annotations_for_docs)
148144
metadata = Map.put(metadata, :kind, module_data.type)
149145
group = GroupMatcher.match_module(config.groups_for_modules, module, module_data.id, metadata)
150146
{nested_title, nested_context} = module_data.nesting_info || {nil, nil}
@@ -158,7 +154,7 @@ defmodule ExDoc.Retriever do
158154
module: module,
159155
type: module_data.type,
160156
deprecated: metadata[:deprecated],
161-
docs_groups: docs_groups,
157+
docs_groups: config.docs_groups ++ module_data.default_groups,
162158
docs: ExDoc.Utils.natural_sort_by(docs, &"#{&1.name}/#{&1.arity}"),
163159
doc_format: format,
164160
doc: doc,
@@ -190,35 +186,19 @@ defmodule ExDoc.Retriever do
190186
{doc_line, doc_file, format, moduledoc, doc_ast(format, moduledoc, options), metadata}
191187
end
192188

193-
defp get_docs(module_data, source, default_group, groups_for_docs, annotations_for_docs) do
189+
defp get_docs(module_data, source, group_for_doc, annotations_for_docs) do
194190
{:docs_v1, _, _, _, _, _, docs} = module_data.docs
195191

196192
nodes =
197193
for doc <- docs,
198194
doc_data = module_data.language.doc_data(doc, module_data) do
199-
get_doc(
200-
doc,
201-
doc_data,
202-
module_data,
203-
source,
204-
default_group,
205-
groups_for_docs,
206-
annotations_for_docs
207-
)
195+
get_doc(doc, doc_data, module_data, source, group_for_doc, annotations_for_docs)
208196
end
209197

210198
filter_defaults(nodes)
211199
end
212200

213-
defp get_doc(
214-
doc,
215-
doc_data,
216-
module_data,
217-
source,
218-
default_group,
219-
groups_for_docs,
220-
annotations_for_docs
221-
) do
201+
defp get_doc(doc, doc_data, module_data, source, group_for_doc, annotations_for_docs) do
222202
{:docs_v1, _, _, content_type, _, module_metadata, _} = module_data.docs
223203
{{type, name, arity}, anno, _signature, source_doc, metadata} = doc
224204
doc_file = anno_file(anno, source)
@@ -242,8 +222,7 @@ defmodule ExDoc.Retriever do
242222
(source_doc && doc_ast(content_type, source_doc, file: doc_file, line: doc_line + 1)) ||
243223
doc_data.doc_fallback.()
244224

245-
group =
246-
GroupMatcher.match_doc(groups_for_docs, default_group, doc_data.default_group, metadata)
225+
group = group_for_doc.(metadata) || doc_data.default_group
247226

248227
%ExDoc.DocNode{
249228
id: doc_data.id_key <> nil_or_name(name, arity),

mix.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
%{
2-
"earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"},
2+
"earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
33
"easyhtml": {:hex, :easyhtml, "0.3.2", "050adfc8074f53b261f7dfe83303d864f1fbf5988245b369f8fdff1bf4c4b3e6", [:mix], [{:floki, "~> 0.35", [hex: :floki, repo: "hexpm", optional: false]}], "hexpm", "b6a936f91612a4870aa3e828cd8da5a08d9e3b6221b4d3012b6ec70b87845d06"},
44
"floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
55
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},

test/ex_doc/config_test.exs

+10
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ defmodule ExDoc.ConfigTest do
114114
assert config.source_url_pattern.("foo.ex", 123) == "a123bfoo.exc"
115115
end
116116

117+
test "groups_for_docs" do
118+
config =
119+
build(groups_for_docs: [Foo: &(&1[:section] == "foo"), Bar: &(&1[:section] == "bar")])
120+
121+
assert config.group_for_doc.(section: "foo") == "Foo"
122+
assert config.group_for_doc.(section: "bar") == "Bar"
123+
assert config.group_for_doc.(section: "baz") == nil
124+
assert config.docs_groups == ~w(Foo Bar)
125+
end
126+
117127
test "groups_for_modules" do
118128
# Using real applications, since we load them to extract the corresponding list of modules
119129
stdlib = :stdlib

test/ex_doc/formatter/epub/templates_test.exs

+8-4
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,14 @@ defmodule ExDoc.Formatter.EPUB.TemplatesTest do
127127
test "outputs function groups" do
128128
content =
129129
get_module_page([CompiledWithDocs],
130-
groups_for_docs: [
131-
"Example functions": &(&1[:purpose] == :example),
132-
Legacy: &is_binary(&1[:deprecated])
133-
]
130+
group_for_doc: fn metadata ->
131+
cond do
132+
metadata[:purpose] == :example -> "Example functions"
133+
is_binary(metadata[:deprecated]) -> "Legacy"
134+
true -> "Functions"
135+
end
136+
end,
137+
docs_groups: ["Example functions", "Legacy"]
134138
)
135139

136140
assert content =~ ~r{id="example-functions".*Example functions}ms

test/ex_doc/formatter/html/templates_test.exs

+15-8
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,14 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
303303
ExDoc.Retriever.docs_from_modules(
304304
[CompiledWithDocs, CompiledWithDocs.Nested],
305305
doc_config(context,
306-
groups_for_docs: [
307-
"Example functions": &(&1[:purpose] == :example),
308-
Legacy: &is_binary(&1[:deprecated])
309-
]
306+
group_for_doc: fn metadata ->
307+
cond do
308+
metadata[:purpose] == :example -> "Example functions"
309+
is_binary(metadata[:deprecated]) -> "Legacy"
310+
true -> "Functions"
311+
end
312+
end,
313+
docs_groups: ["Example functions", "Legacy"]
310314
)
311315
)
312316

@@ -484,10 +488,13 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
484488
test "outputs function groups", context do
485489
content =
486490
get_module_page([CompiledWithDocs], context,
487-
groups_for_docs: [
488-
"Example functions": &(&1[:purpose] == :example),
489-
Legacy: &is_binary(&1[:deprecated])
490-
]
491+
group_for_doc: fn metadata ->
492+
cond do
493+
metadata[:purpose] == :example -> "Example functions"
494+
is_binary(metadata[:deprecated]) -> "Legacy"
495+
true -> "Functions"
496+
end
497+
end
491498
)
492499

493500
doc = EasyHTML.parse!(content)

test/ex_doc/retriever_test.exs

+1-30
Original file line numberDiff line numberDiff line change
@@ -62,35 +62,6 @@ defmodule ExDoc.RetrieverTest do
6262
assert %{module: Qux, group: nil} = qux
6363
end
6464

65-
test "function groups", c do
66-
elixirc(c, ~S"""
67-
defmodule A do
68-
@doc group: 1
69-
def foo(), do: :ok
70-
71-
@doc group: 1
72-
def bar(), do: :ok
73-
74-
@doc group: 2
75-
def baz(), do: :ok
76-
end
77-
""")
78-
79-
config = %ExDoc.Config{
80-
groups_for_docs: [
81-
{"Group 1", &(&1.group == 1)},
82-
{"Group 2", &(&1.group == 2)}
83-
]
84-
}
85-
86-
{[mod], []} = Retriever.docs_from_modules([A], config)
87-
[bar, baz, foo] = mod.docs
88-
89-
assert %{id: "foo/0", group: "Group 1"} = foo
90-
assert %{id: "bar/0", group: "Group 1"} = bar
91-
assert %{id: "baz/0", group: "Group 2"} = baz
92-
end
93-
9465
test "function groups use :group metadata", c do
9566
elixirc(c, ~S"""
9667
defmodule A do
@@ -128,7 +99,7 @@ defmodule ExDoc.RetrieverTest do
12899
end
129100
""")
130101

131-
config = %ExDoc.Config{default_group_for_doc: & &1[:semi_group]}
102+
config = %ExDoc.Config{group_for_doc: & &1[:semi_group]}
132103
{[mod], []} = Retriever.docs_from_modules([A], config)
133104
[bar, baz, foo] = mod.docs
134105

0 commit comments

Comments
 (0)