查看源码 文档

Erlang 中的文档通过 -moduledoc-doc 属性完成。 例如

-module(arith).
-moduledoc """
A module for basic arithmetic.
""".

-export([add/2]).

-doc "Adds two numbers.".
add(One, Two) -> One + Two.

-moduledoc 属性必须位于第一个 -doc 属性或函数声明之前。它记录了模块的整体用途。

-doc 属性始终位于它所文档化的函数属性之前。可以文档化的属性包括用户定义的类型-type-opaque)和行为模块属性-callback)。

默认情况下,文档属性使用的格式是 Markdown,但可以通过设置模块文档元数据来更改。

编写 Markdown 的一个好的起点是 基本的写作和格式语法

有关 -moduledoc-doc 属性中允许包含的内容的详细信息,请参阅文档属性

-doc 属性自 Erlang/OTP 27 起可用。

文档元数据

可以向文档条目添加元数据。您可以通过添加一个以映射作为参数的 -moduledoc-doc 属性来完成此操作。例如

-module(arith).
-moduledoc """
A module for basic arithmetic.
""".
-moduledoc #{since => "1.0"}.

-export([add/2]).

-doc "Adds two numbers.".
-doc(#{since => "1.0"}).
add(One, Two) -> One + Two.

元数据由文档工具使用,以向用户提供额外信息。可以有多个元数据文档条目,在这种情况下,映射将合并,如果存在重复的键,则以最新的为准。示例

-doc "Adds two numbers.".
-doc #{since => "1.0", author => "Joe"}.
-doc #{since => "2.0"}.
add(One, Two) -> One + Two.

这将导致元数据条目为 #{since => "2.0", author => "Joe"}

元数据映射中的键和值可以是任何类型,但建议键仅使用原子,值使用字符串

外部文档文件

-moduledoc-doc 也可以放在外部文件中。为此,使用 -doc {file, "path/to/doc.md"} 来指向文档。使用的路径是相对于 -doc 属性所在的文件而言的。 例如

%% doc/add.md
Adds two numbers.

%% src/arith.erl
-doc({file, "add.md"}).
add(One, Two) -> One + Two.

文档化模块

模块描述应包括如何使用 API 以及不同函数协同工作的示例的详细信息。这里是使用图像和其他图表更好地展示模块使用情况的好地方。与其在 moduledoc 属性中编写长文本,不如将其分解到外部页面中。

moduledoc 属性应以简短的段落描述模块开始,然后深入更详细的内容。例如

-module(arith).
-moduledoc """
   A module for basic arithmetic.

   This module can be used to add and subtract values. For example:

   ```erlang
   1> arith:substract(arith:add(2, 3), 1).
   4
   ```
   """.

Moduledoc 元数据

对于 -moduledoc,有三个保留的元数据键

  • since - 显示模块在应用程序的哪个版本中添加。如果添加此项,则其中所有函数、类型和回调也将收到相同的 since 值,除非在函数、类型或回调的元数据中指定。
  • deprecated - 在文档中显示一段文本,解释它已被弃用以及应改用什么。
  • format - 用于此模块中所有文档的格式。默认值为 text/markdown。它应该使用格式的MIME 类型编写。

示例

-moduledoc {file, "arith.asciidoc"}.
-moduledoc #{since => "0.1", format => "text/asciidoc"}.
-moduledoc #{deprecated => "Use the Erlang arithmetic operators instead."}.

文档化函数、用户定义的类型和回调

可以使用 -doc 属性来文档化函数、类型和回调。每个条目都应以简短的段落描述实体的目的开始,然后在需要时深入更详细的内容。

不建议在此文档中包含图像或图表,因为它被 IDE 和 c:h/1 使用来向用户显示文档。

例如

-doc """
A number that can be used by the arith module.

We use a special number here so that we know
that this number comes from this module.
""".
-opaque number() :: {arith, erlang:number()}.

-doc """
Adds two numbers.

### Example:

```
1> arith:add(arith:number(1), arith:number(2)). {number, 3}
```
""".
-spec add(number(), number()) -> number().
add({number, One}, {number, Two}) -> {number, One + Two}.

Doc 元数据

对于 -doc,有四个保留的元数据键

  • since => unicode:chardata() - 显示模块在应用程序的哪个版本中添加。

  • deprecated => unicode:chardata() - 在文档中显示一段文本,解释它已被弃用以及应改用什么。如果存在将函数标记为已弃用的 -deprecated 属性,则编译器将自动插入此键。

  • equiv => unicode:chardata() | F/A | F(...) - 注释此函数等效于此模块中的另一个函数。可以使用 Func/ArityFunc(Args)unicode 字符串来描述等效性。例如

    -doc #{equiv => add/3}.
    add(One, Two) -> add(One, Two, []).
    add(One, Two, Options) -> ...

    -doc #{equiv => add(One, Two, [])}.
    -spec add(One :: number(), Two :: number()) -> number().
    add(One, Two) -> add(One, Two, []).
    add(One, Two, Options) -> ...

    进入 EEP-48 文档块元数据的条目是将该值转换为字符串。

  • exported => boolean() - 一个 boolean/0,表示条目是否为 exported。此值由编译器自动设置,不应由用户设置。

文档签名

文档签名是一段简短的文本,用于描述函数及其参数。默认情况下,它是通过查看 -spec 或函数中的参数名称来确定的。例如

add(One, Two) -> One + Two.

-spec sub(One :: integer(), Two :: integer()) -> integer().
sub(X, Y) -> X - Y.

将具有 add(One, Two)sub(One, Two) 的签名。

对于类型或回调,签名来源于类型或回调规范。例如

-type number(Value) :: {number, Value}.
%% signature will be `number(Value)`

-opaque number() :: {number, number()}.
%% signature will be `number()`

-callback increment(In :: number()) -> Out.
%% signature will be `increment(In)`

-callback increment(In) -> Out when In :: number().
%% signature will be `increment(In)`

如果无法从代码中“轻松”找出好的签名,则改为使用 MFA 语法。例如:add/2number/1increment/1

可以通过将其作为 -doc 属性的第一行来提供自定义签名。提供的签名必须采用函数声明的形式,直到 ->。 例如

-doc """
add(One, Two)

Adds two numbers.
""".
add(A, B) -> A + B.

将创建签名 add(One, Two)。签名将从文档字符串中删除,因此在上面的示例中,只有文本 "Adds two numbers" 将是文档的一部分。这适用于函数、类型和回调。

在 Markdown 中编写文档时,会在任何看起来像 MFA 的内联代码段中自动找到链接。例如

-doc "See `sub/2` for more details".

如果存在,将创建指向当前模块中 sub/2 函数的链接。也可以使用 `sub/2` 作为链接目标。例如

-doc "See [subtract](`sub/2`) for more details".
-doc "See [`sub/2`] for more details".
-doc """
See [subtract] for more details

[subtract]: `sub/2`
""".
-doc """
See [subtract][1] for more details

[1]: `sub/2`
""".

上面的示例导致创建相同的链接。

该链接也可以链接到其他实体

  • 远程函数 - 使用 module:function/arity 语法。

示例

-doc "See `arith:sub/2` for more details".
  • 模块 - 编写带有 m 前缀的模块。使用锚点跳转到模块中的特定位置。

示例

-doc "See `m:arith` for more details".
-doc "See `m:arith#anchor` for more details".
  • 类型 - 使用与本地/远程函数相同的语法,但添加 t 前缀。

示例

-doc "See `t:number/0` for more details".
-doc "See `t:arith:number/0` for more details".
  • 回调 - 使用与本地/远程函数相同的语法,但添加 c 前缀。

示例

-doc "See `c:increment/0` for more details".
-doc "See `c:arith:increment/0` for more details".
  • 额外页面 - 对于当前应用程序中的额外页面,使用正常链接,例如 "[release notes](notes.md)"。对于另一个应用程序中的额外页面,使用 e 前缀并说明该页面所属的应用程序。也可以使用锚点跳转到页面中的特定位置。

示例

-doc "See `e:stdlib:unicode_usage` for more details".
-doc "See `e:stdlib:unicode_usage#notes-about-raw-filenames` for more details".

什么是可见的与隐藏的?

Erlang 应用程序 通常由各种公共和私有模块组成。也就是说,应该由其他应用程序使用的模块和不应该使用的模块。默认情况下,应用程序中的所有模块都是可见的,但是通过设置 -moduledoc false. 可以将特定模块隐藏为可用 API 的一部分。

Erlang 模块由公共和私有函数和类型属性组成。默认情况下,所有导出的函数、导出的类型和回调都被认为是可见的,并且是模块公共 API 的一部分。此外,任何其他可见类型属性引用的任何非导出类型也是可见的,但不被认为是公共 API 的一部分。例如

-export([example/0]).

-type private() :: one.
-spec example() -> private().
example() -> one.

在上面的代码中,函数 example/0 被导出,并且它引用了未导出的类型 private/0。因此,example/0private/0 都将被标记为可见。 private/0 类型将具有元数据字段 exported 设置为 false,以表明它不是公共 API 的一部分。

如果要使可见实体隐藏,则需要将 -doc 属性设置为 false。让我们重新访问之前的示例

-export([example/0]).

-type private() :: one.
-spec example() -> private().
-doc false.
example() -> one.

函数 example/0 被导出,但显式标记为隐藏;因此,example/0private/0 都将被隐藏。

添加到自动隐藏的实体(未导出的函数或类型)的任何文档都将被忽略,并且会生成警告。可以使用注释来文档化此类函数。

编译和获取文档

默认情况下,Erlang 编译器会在编译模块时将文档插入到 EEP-48 文档块中。通过将 no_docs 标志传递给 compile:file/1,或将 +no_docs 传递给 erlc,则不会插入文档块。

然后可以使用 code:get_doc/1 检索文档,或使用 shell 内置命令 h/1)查看。例如

1> h(arith).

      arith

  A module for basic arithmetic.

2> h(arith, add).

      add(One, Two)

  Adds two numbers.

使用 ExDoc 生成 HTML/ePub 文档

ExDoc 内置了从 Markdown 生成文档的支持。最简单的方法是使用 rebar3_ex_doc 插件。要设置 rebar3 项目以使用 ExDoc 生成文档,请将以下内容添加到您的 rebar3.config

%% Enable the plugin
{plugins, [rebar3_ex_doc]}.

{ex_doc, [
  {extras, ["README.md"]},
  {main, "README.md"},
  {source_url, "https://github.com/namespace/your_app"}
]}.

配置完成后,您可以运行 rebar3 ex_doc 来将文档生成到 doc/index.html。有关更多详细信息和选项,请参阅 rebar3_ex_doc 文档。

您还可以从 github 下载 最新的 escript 捆绑包,并从命令行运行它。通过运行 ex_doc --help 可以找到有关使用 escript 的文档。

如果您正在编写文档,并且将使用 ExDoc 来生成 HTML/ePub,强烈建议您阅读其文档。