本章介绍 OCamldoc,它是一个从源文件中嵌入的特殊注释生成文档的工具。OCamldoc 使用的注释格式为 (**…*),其格式如第 19.2 节所述。
OCamldoc 可以生成多种格式的文档:HTML、LATEX、TeXinfo、Unix 手册页和 dot 依赖项图。此外,用户还可以添加自己的自定义生成器,如第 19.3 节所述。
在本章中,我们使用“元素”一词来指代 OCaml 源文件中的任何以下部分:类型声明、值、模块、异常、模块类型、类型构造器、记录字段、类、类类型、类方法、类值或类继承子句。
OCamldoc 通过命令 ocamldoc 调用,如下所示
ocamldoc options sourcefiles
以下选项确定生成的文档的格式。
OCamldoc 调用 OCaml 类型检查器以获取类型信息。以下选项会影响类型检查阶段。它们与 ocamlc 和 ocamlopt 命令的含义相同。
以下选项与 -html 选项一起使用
module M : functor (A:Module) -> functor (B:Module2) -> sig .. end显示为
module M (A:Module) (B:Module2) : sig .. end
以下选项与 -latex 选项一起使用
当您有名称相同的类型和值时,这些选项非常有用。如果您未指定前缀,LATEX 会抱怨重复定义的标签。
以下选项与 -texi 选项一起使用
以下选项与 -dot 选项一起使用
以下选项与 -man 选项一起使用
模块信息可以从 .mli 或 .ml 文件中提取,或者从两者中提取,具体取决于命令行上给出的文件。当为同一个模块同时给出 .mli 和 .ml 文件时,从这些文件中提取的信息将根据以下规则进行合并
必须遵守以下规则,以避免导致交叉引用错误的名称冲突
包含文档材料的注释称为特殊注释,它们写在 (** 和 *) 之间。特殊注释必须以 (** 开头。以 ( 开头且有两个以上 * 的注释将被忽略。
OCamldoc 可以将注释与源文件中遇到的语言的一些元素关联起来。关联根据注释相对于语言元素的位置进行。.mli 和 .ml 文件中注释的位置不同。
如果特殊注释放在元素之前或之后,则将其与元素关联。
在元素之前的特殊注释将与该元素关联,如果
在元素之后的特殊注释将与该元素关联,如果在特殊注释和元素之间没有空行或注释。
有两个例外:对于类型定义中的构造函数和记录字段,关联的注释只能放在构造函数或字段定义之后,它们之间不能有空行或其他注释。带有其他构造函数的构造函数的特殊注释必须放在分隔两个构造函数的’|’ 字符之前。
以下示例接口文件 foo.mli 说明了在 .mli 文件中对注释进行放置的规则。
如果特殊注释放置在元素之前,并且注释和元素之间没有空行,则该特殊注释将与元素关联。 同时,在特殊注释和元素之间可能存在一个简单的注释。 有两个例外,对于类型定义中的构造函数和记录字段,它们的关联注释必须放置在构造函数或字段定义之后,它们之间没有空行。 具有另一个构造函数跟随的构造函数的特殊注释必须放置在分离两个构造函数的“|”字符之前。
以下 toto.ml 文件示例显示了在 .ml 文件中放置注释的位置。
特殊注释 (**/**) 告诉 OCamldoc 丢弃此注释之后的元素,直到当前类、类类型、模块或模块类型的结束,或直到下一个停止注释。 例如
ocamldoc 的 -no-stop 选项会导致忽略停止特殊注释。
文档注释 (**…*) 的内部包含自由格式的文本,其中包含可选的格式化注释,后跟可选的 _tags_,这些 _tags_ 提供有关参数、版本、作者等的更具体信息。 _tags_ 由前导的 @ 字符区分。 因此,文档注释具有以下形状
(** The comment begins with a description, which is text formatted according to the rules described in the next section. The description continues until the first non-escaped '@' character. @author Mr Smith @param x description for parameter x *)
某些元素仅支持所有 @-tags 的子集。 与所记录元素无关的 _tags_ 将被简单地忽略。 例如,在记录类型构造函数、记录字段和类继承子句时,所有 _tags_ 都将被忽略。 同样,类实例变量上的 @param _tag_ 将被忽略。
最后,(**) 是空的文档注释。
以下是用于格式化文本描述的简单标记语言的 BNF 语法。
|
text-element | ::= |
∣ | inline-text-element | |
∣ | blank-line | 强制换行。 |
∣ | { { 0 … 9 }+ inline-text } | 将 text 格式化为节标题;紧随 { 后的整数表示节的级别。 |
∣ | { { 0 … 9 }+ : label inline-text } | 相同,但还将名称 label 与当前点相关联。 此点可以通过其完全限定的标签在 {! 命令中引用,就像任何其他元素一样。 |
∣ | {b inline-text } | 将 text 设置为粗体。 |
∣ | {i inline-text } | 将 text 设置为斜体。 |
∣ | {e inline-text } | 强调 text。 |
∣ | {C inline-text } | 居中 text。 |
∣ | {L inline-text } | 左对齐 text。 |
∣ | {R inline-text } | 右对齐 text。 |
∣ | {ul list } | 创建一个列表。 |
∣ | {ol list } | 创建一个编号列表。 |
∣ | {{: string } inline-text } | 在给定的 text 上添加一个指向给定地址(以 string 格式给出)的链接。 |
∣ | [ string ] | 将给定的 string 设置为源代码样式。 |
∣ | {[ string ]} | 将给定的 string 设置为预格式化的源代码样式。 |
∣ | {v string v} | 将给定的 string 设置为逐字显示样式。 |
∣ | {% string %} | 目标特定内容(默认情况下为 LATEX 代码,详情请参见 19.2.4.4) |
∣ | {! string } | 插入对元素的交叉引用(有关交叉引用的语法,请参见 19.2.4.2 节)。 |
∣ | {{! string } inline-text } | 插入带有给定文本的交叉引用。 |
∣ | {!modules: string string ... } | 插入给定模块名称的索引表。仅在 HTML 中使用。 |
∣ | {!indexlist} | 插入指向各种索引(类型、值、模块等)的链接的表。仅在 HTML 中使用。 |
∣ | {^ inline-text } | 将文本设置为上标。 |
∣ | {_ inline-text } | 将文本设置为下标。 |
∣ | escaped-string | 按原样排版给定的字符串;特殊字符(’{’,’}’,’[’,’]’ 和 ’@’)必须通过 ’\’ 转义。 |
|
列表和编号列表存在快捷语法
(** Here is a {b list} - item 1 - item 2 - item 3 The list is ended by the blank line.*)
等效于
(** Here is a {b list} {ul {- item 1} {- item 2} {- item 3}} The list is ended by the blank line.*)
相同的快捷方式可用于编号列表,使用 ’+’ 代替 ’-’。请注意,在嵌套列表中,只能通过此快捷方式定义一个列表。
交叉引用是完全限定的元素名称,例如 {!Foo.Bar.t}。这是一个模棱两可的引用,因为它可能代表一个类型名称、一个值名称、一个类名称等。可以使用 {!type:Foo.Bar.t} 来指定一个类型,以及 {!val:Foo.Bar.t} 来指定具有相同名称的值,以明确所需的语法类别。
可能的语法类别的列表如下
tag | 语法类别 |
module | module |
modtype | 模块类型 |
class | class |
classtype | 类类型 |
val | value |
type | type |
exception | exception |
attribute | attribute |
method | 类方法 |
section | ocamldoc section |
const | 变体构造函数 |
recfield | 记录字段 |
在变体构造函数或记录字段的情况下,构造函数或字段名称应以相应类型的名称为前缀,以避免多个类型具有相同构造函数名称的歧义。例如,类型 tree 的构造函数 Node 将被引用为 {!tree.Node} 或 {!const:tree.Node},或者可能从模块外部引用为 {!Mod1.Mod2.tree.Node}。
在对值、类型、异常、模块、模块类型、类或类类型的描述中,首句 有时用于索引,或者在只需要描述的一部分时使用。首句由描述的第一个字符组成,直到
在以下文本格式之外:{ul list } ,{ol list } ,[ string ] ,{[ string ]} ,{v string v} ,{% string %} ,{! string } ,{^ text } ,{_ text } 。
{%foo: ... %} 中的内容是目标特定的,仅由后端 foo 解释,其他后端将忽略它。发行版的后端是 latex、html、texi 和 man。如果没有指定目标(语法 {% ... %}),则默认情况下选择 latex。自定义生成器可能支持自己的目标前缀。
HTML 标签 <b>..</b>、<code>..</code>、<i>..</i>、<ul>..</ul>、<ol>..</ol>、<li>..</li>、<center>..</center> 和 <h[0-9]>..</h[0-9]> 可分别用于 {b ..} 、[..] 、{i ..} 、{ul ..} 、{ol ..} 、{li ..} 、{C ..} 和 {[0-9] ..}。
下表列出了预定义的 @-tags,及其语法和含义。
@author string | 元素的作者。每个 @author 标签对应一个作者。同一个元素可能有多个 @author 标签。 |
@deprecated text | text 应描述元素何时被弃用,使用什么作为替代,以及可能的原因。 |
@param id text | 将给定的描述(text)与给定的参数名称 id 关联。此标签用于函数、方法、类和函子。 |
@raise Exc text | 解释元素可能会引发异常 Exc。 |
@return text | 描述返回值及其可能的值。此标签用于函数和方法。 |
@see < URL > text | 添加指向 URL 的引用,并使用给定的 text 作为注释。 |
@see 'filename' text | 添加指向给定文件名(用单引号括起来)的引用,并使用给定的 text 作为注释。 |
@see "document-name" text | 添加指向给定文档名称(用双引号括起来)的引用,并使用给定的 text 作为注释。 |
@since string | 指示元素何时引入。 |
@before version text | 将给定的描述(text)与给定的 version 关联,以记录兼容性问题。 |
@version string | 元素的版本号。 |
您可以在文档注释中使用自定义标签,但如果使用的生成器不支持它们,则它们将无效。要使用自定义标签,例如 foo,只需在注释中添加 @foo 和一些文本,例如
(** My comment to show you a custom tag. @foo this is the text argument to the [foo] custom tag. *)
要处理自定义标签,您需要定义一个自定义生成器,如 19.3.2 节中所述。
OCamldoc 分两个步骤操作
用户可以在步骤 2 中提供他们自己的文档生成器来代替默认生成器。在分析步骤中检索到的所有信息都可通过 Odoc_info 模块获得,该模块提供对在给定模块中找到的所有元素的类型和函数的访问,以及它们的关联描述。
用于定义自定义生成器的文件安装在 OCaml 标准库的 ocamldoc 子目录中。
生成器模块的类型取决于生成的文档类型。以下是生成器模块类型的列表,以及模块中的生成器类的名称
也就是说,要定义一个新的生成器,必须实现一个具有预期签名的模块,并使用给定的生成器类,提供 generate 方法作为入口点,使生成器为给定的模块列表生成文档
method generate : Odoc_info.Module.t_module list -> unit
此方法将使用分析过的,可能合并过的 Odoc_info.t_module 结构列表进行调用。
建议从与要定义的相同类型的当前生成器继承。这样做,可以加载各种自定义生成器,以结合每个生成器带来的改进。
这是使用一等模块完成的(参见第 12.5 章)。
定义自定义生成器最简单的方法是遵循以下示例,这里扩展了当前的 HTML 生成器。我们无需知道这是 ocamldoc 中定义的原始 HTML 生成器,还是已经被先前加载的自定义生成器扩展过
module Generator (G : Odoc_html.Html_generator) = struct class html = object(self) inherit G.html as html (* ... *) method generate module_list = (* ... *) () (* ... *) end end;; let _ = Odoc_args.extend_html_generator (module Generator : Odoc_gen.Html_functor);;
要了解要覆盖哪些方法和/或哪些方法可用,请查看不同的基本实现,具体取决于要扩展的生成器类型
使自定义生成器处理自定义标签(参见 19.2.5)非常简单。
以下是开发处理自定义标签的 HTML 生成器的方法。
类 Odoc_html.Generator.html 继承自类 Odoc_html.info,包含一个字段 tag_functions,它是一个由自定义标签(例如 "foo")和一个接受 text 并返回 HTML 代码(类型为 string)的函数组成的列表对。要处理新的标签 bar,请扩展当前的 HTML 生成器并完成 tag_functions 字段
module Generator (G : Odoc_html.Html_generator) = struct class html = object(self) inherit G.html (** Return HTML code for the given text of a bar tag. *) method html_of_bar t = (* your code here *) initializer tag_functions <- ("bar", self#html_of_bar) :: tag_functions end end let _ = Odoc_args.extend_html_generator (module Generator : Odoc_gen.Html_functor);;
类 Odoc_html.info 的另一种方法将查找与自定义标签关联的函数,并将其应用于给定标签的文本。如果与自定义标签没有关联任何函数,则该方法会在 stderr 上打印警告消息。
您可以对其他类型的生成器采取相同的方式。
命令行分析是在加载包含文档生成器的模块后执行的,因此允许将命令行选项添加到现有选项列表中。可以使用以下函数添加选项
Odoc_args.add_option : string * Arg.spec * string -> unit
注意:可以使用此函数重新定义现有的命令行选项。
设 custom.ml 是定义新生成器类的文件。可以使用以下命令编译 custom.ml
ocamlc -I +ocamldoc -c custom.ml
将创建文件 custom.cmo,可以使用以下方式使用它
ocamldoc -g custom.cmo other-options source-files
如果使用 -g 提供了相同类型的自定义生成器,则选择内置生成器的选项(例如 -html)将不起作用。如果类型不匹配,则使用所选的内置生成器,而忽略自定义生成器。
可以在多个模块中定义生成器类,这些模块定义在多个文件 file1.ml[i], file2.ml[i], ..., filen.ml[i] 中。必须创建一个包含所有这些文件的 .cma 库文件。
以下命令从文件 file1.ml[i], ..., filen.ml[i] 创建 custom.cma 文件
ocamlc -I +ocamldoc -c file1.ml[i] ocamlc -I +ocamldoc -c file2.ml[i] ... ocamlc -I +ocamldoc -c filen.ml[i] ocamlc -o custom.cma -a file1.cmo file2.cmo ... filen.cmo
然后,以下命令使用 custom.cma 作为自定义生成器
ocamldoc -g custom.cma other-options source-files