本章介紹 OCamldoc,這是一個從嵌入在原始碼檔案中的特殊註解產生文件的工具。OCamldoc 使用的註解格式為 (**…*),並遵循 19.2 節中描述的格式。
OCamldoc 可以產生多種格式的文件:HTML、LATEX、TeXinfo、Unix man pages 和 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 捨棄此註解之後的元素,直到目前類別、類別類型、模組或模組類型的結尾,或直到下一個 stop 註解。例如:
使用 ocamldoc 的 -no-stop 選項會導致 Stop 特殊註解被忽略。
文件註解 (**…*) 的內部包含自由格式的文字,以及選擇性的格式註解,後面接著選擇性的標籤,提供有關參數、版本、作者等的更具體資訊。標籤以 @ 字元開頭。因此,文件註解的形狀如下:
(** 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 *)
某些元素僅支援所有 @-tag 的子集。與文件化的元素無關的標籤會被直接忽略。例如,在文件化類型建構函式、記錄欄位和類別繼承子句時,會忽略所有標籤。同樣地,類別實例變數上的 @param 標籤也會被忽略。
最後,(**) 是空的文件註解。
以下是 BNF 文法,用於格式化文字描述的簡單標記語言。
|
text-element | ::= |
∣ | inline-text-element | |
∣ | blank-line | 強制換行。 |
∣ | { { 0 … 9 }+ 行內文字 } | 將 文字 格式化為章節標題;{ 後面的整數表示章節層級。 |
∣ | { { 0 … 9 }+ : 標籤 行內文字 } | 相同,但同時將名稱 標籤 與目前位置關聯。此位置可像其他元素一樣,在 {! 命令中使用其完整限定的標籤來參考。 |
∣ | {b 行內文字 } | 將 文字 設定為粗體。 |
∣ | {i 行內文字 } | 將 文字 設定為斜體。 |
∣ | {e 行內文字 } | 強調 文字。 |
∣ | {C 行內文字 } | 將 文字 置中對齊。 |
∣ | {L 行內文字 } | 將 文字 靠左對齊。 |
∣ | {R 行內文字 } | 將 文字 靠右對齊。 |
∣ | {ul 列表 } | 建立一個列表。 |
∣ | {ol 列表 } | 建立一個編號列表。 |
∣ | {{: 字串 } 行內文字 } | 在指定的 文字 上放置一個指向給定地址(以 字串 形式給出)的連結。 |
∣ | [ 字串 ] | 將給定的 字串 設定為原始碼樣式。 |
∣ | {[ 字串 ]} | 將給定的 字串 設定為預格式化原始碼樣式。 |
∣ | {v 字串 v} | 將給定的 字串 設定為逐字樣式。 |
∣ | {% 字串 %} | 特定目標的內容(預設為 LATEX 程式碼,詳情請參閱 19.2.4.4) |
∣ | {! 字串 } | 插入一個對元素的交叉引用(有關交叉引用的語法,請參閱 19.2.4.2 節)。 |
∣ | {{! 字串 } 行內文字 } | 插入一個帶有給定文字的交叉引用。 |
∣ | {!modules: 字串 字串 ... } | 為給定的模組名稱插入索引表。僅在 HTML 中使用。 |
∣ | {!indexlist} | 插入一個指向各個索引(類型、值、模組等)的連結表。僅在 HTML 中使用。 |
∣ | {^ 行內文字 } | 將文字設定為上標。 |
∣ | {_ 行內文字 } | 將文字設定為下標。 |
∣ | 跳脫字串 | 按原樣排版給定的字串;特殊字元(’{’、’}’、’[’、’]’ 和 ’@’)必須使用 ’\’ 跳脫 |
列表和編號列表存在快捷語法
(** 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} 來表示同名的值。
可能的語法類別列表如下
標籤 | 語法類別 |
模組 | 模組 |
模組類型 | 模組類型 |
類別 | 類別 |
類別類型 | 類別類型 |
值 | 值 |
類型 | 類型 |
例外 | 例外 |
屬性 | 屬性 |
方法 | 類別方法 |
章節 | ocamldoc 章節 |
常數 | 變體建構子 |
記錄欄位 | 記錄欄位 |
對於變體建構子或記錄欄位,建構子或欄位名稱之前應加上對應的類型名稱,以避免多個類型具有相同建構子名稱的歧義。例如,類型為 tree 的建構子 Node 將被引用為 {!tree.Node} 或 {!const:tree.Node},或者可能從模組外部引用為 {!Mod1.Mod2.tree.Node}。
在值、類型、例外、模組、模組類型、類別或類別類型的描述中,*首句* 有時用於索引,或當只需要部分描述時。首句由描述的第一個字元組成,直到
在下列文字格式設定之外:{ul 列表 }、{ol 列表 }、[ 字串 ]、{[ 字串 ]}、{v 字串 v}、{% 字串 %}、{! 字串 }、{^ 文字 }、{_ 文字 }。
{%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 字串 | 元素的作者。每個 @author 標籤一個作者。同一個元素可以有多個 @author 標籤。 |
@deprecated 文字 | 文字 應描述元素何時被棄用、要使用什麼替代方案,以及可能被棄用的原因。 |
@param id 文字 | 將給定的描述(文字)與給定的參數名稱 id 關聯。此標籤用於函式、方法、類別和函子。 |
@raise Exc 文字 | 說明元素可能會引發例外 Exc。 |
@return 文字 | 描述傳回值及其可能的值。此標籤用於函式和方法。 |
@see < URL > 文字 | 新增一個對 URL 的參考,並以給定的 文字 作為註解。 |
@see '檔案名稱' 文字 | 新增一個對給定檔案名稱(寫在單引號之間)的參考,並以給定的 文字 作為註解。 |
@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 結構列表來呼叫。
建議繼承與您要定義的產生器相同種類的當前產生器。這樣做,就可以載入各種自訂產生器,以結合每個產生器帶來的改進。
這是使用 first class modules(請參閱 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
選擇 ocamldoc 的內建產生器的選項(例如 -html)如果使用 -g 提供相同種類的自訂產生器,則不起作用。如果種類不符,則使用選定的內建產生器,而忽略自訂產生器。
可以在多個模組中定義產生器類別,這些模組定義在多個檔案 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