Improve this page Github へのログインが必要です。 簡単な修正は、ここから fork、オンライン編集、pull request ができます。 大きな修正については、 通常の clone で行って下さい。 Page wiki 関連するWikiページを参照・編集 English このページの英語版(原文)

埋め込みドキュメント

D言語は既に、"契約" や "単体テスト" のコードを実際のコードに埋め込んで、 それら全ての一貫性を常に保ちやすいような設計になっていました。 ここで欠けていたのは、埋め込みドキュメントです。 普通のコメントは自動抽出してマニュアルへと整形するのには あまり向いていませんでした。 ドキュメントをソースコードの中に埋め込むことには、重要な利点があります。 ドキュメントを2度書く必要がなくなることや、 コードとドキュメントを無矛盾に保ちやすくなることが主な利点です。

これに関する既存のアプローチとしては:

Dでの埋め込みドキュメントの目標は:

  1. 抽出して変換処理せずとも、 埋め込みドキュメントとしても綺麗に読めること
  2. 自然にそして簡単に書けること。 <タグ> やその他生成後のドキュメントには現れないようなごちゃごちゃした 要素への依存は最小にする。
  3. コンパイラが構文解析によって把握できる情報を 繰り返し書く必要をなくすこと
  4. 他の目的の情報抽出の邪魔にならないよう、 HTML埋め込みには頼らないこと
  5. 既存のDのコメント形式に基づいて、 Dのコードだけを使う他のパーザは完全に独立に実装できるようにすること
  6. コードと混同されることのないよう、 見た目はコード部分とは異なって見えるようにすること
  7. もし必要なら、ユーザーが Doxygen やその他のドキュメント抽出ツールも使えるようにすること

仕様

埋め込みドキュメントコメントの形式に関する以下の仕様は、 コンパイラに対してどのように情報が伝わるのか、のみを定めています。 その情報が最終的にどのように使われるのかは実装毎に定義されます。 最終的な出力がHTMLウェブページなのか、manページなのか、あるいは PDFファイルなのか、などは プログラミング言語Dの規格としては定義されません。

処理フェーズ

埋め込みドキュメントコメントは、以下の一連のフェーズに沿って処理されます:

  1. Lexical - コード中のドキュメントコメント部分が認識されます。
  2. Parsing - ドキュメントコメントが、特定の宣言に関連付けられ、 結合されます。
  3. Sections - それぞれのドキュメントコメントを、 幾つかのセクションに分解します。
  4. 特殊セクションが処理されます。
  5. 非特殊セクションのHighlightingが実行されます。
  6. モジュール用の全てのセクションが結合されます。
  7. マクロ置換が実行され、最終結果が生成されます。

Lexical

埋め込みドキュメントコメントは、以下のうちいずれかの形式で書かれます:

  1. /** ... */ 先頭スラッシュの後に2つの *
  2. /++ ... +/ 先頭スラッシュの後に2つの +
  3. /// 3つのスラッシュ

以下の例は全て埋め込みドキュメントコメントです:

/// これは一行ドキュメントコメントです。

/** これも同じく。 */

/++ これも。 +/

/**
   これは短いドキュメントコメントです。
 */

/**
 * この行の先頭の * はドキュメントコメントの一部としては扱われません。
 */

/*********************************
   /**の後に続いている余分な*は、
   ドキュメントコメントの一部ではありません。
 */

/++
   これは短いドキュメントコメントです。
 +/

/++
 + この行の先頭の + はドキュメントコメントの一部としては扱われません。
 +/

/+++++++++++++++++++++++++++++++++
   余分な+は、
   ドキュメントコメントの一部ではありません。
 +/

/**************** 閉じ*も一部ではありません *****************/

コメント開始部、終了部及び左マージンの余分な * や + は、 無視され、 埋め込みドキュメントとしては処理されません。 以上の形式のどれにも沿っていないコメントは、ドキュメントコメントではありません。

Parsing

ドキュメントコメントはそれぞれ、宣言へと関連付けられます。 ドキュメントコメントと同じ行に空白文字しか残っていない場合、 次に出現する 宣言を参照するものとします。 同じ宣言に適用されるドキュメントコメントが複数あるときは、 それらは結合されます。 宣言に関連付いていないドキュメントコメントは無視されます。 ModuleDeclaration の前にあるドキュメントコメントは、 モジュール全体に適用されます。 ドキュメントコメントが宣言と同じ行でその右側に出現するときは、 その宣言に適用されます。

宣言に対するドキュメントコメントが ditto という識別子のみからなる場合、 同じスコープにある直前のドキュメントコメントが、 その宣言に対しても同様に適用されます。

宣言に関連するドキュメントコメントがひとつも無い場合、 その宣言はドキュメントに出力されない可能性があります。確実に出力したい場合、 空のドキュメントコメントを付けておく必要があります。

int a;  /// aに関するドキュメント; bはドキュメントなし
int b;

/** cとdに関するドキュメント */
/** さらにcとdに関するドキュメント */
int c;
/** ditto */
int d;

/** eとfに関するドキュメント */ int e;
int f;	/// ditto

/** gに関するドキュメント */
int g; /// さらにgに関するドキュメント

/// C と D に関するドキュメント
class C {
  int x; /// C.x に関するドキュメント

  /** C.y と C.z に関するドキュメント */
  int y;
  int z; /// ditto
}

/// ditto
class D { }

Sections

ドキュメントコメントは、一連の Section で構成されています。 Section とは、行の最初の非空白文字であって、直後に ':' が続いている名前のことを言います。この名前がセクション名です。 セクション名については、大文字小文字が区別されません。

Summary

最初のセクションは Summary です。セクション名はありません。 空行かセクション名が現れるまでの最初の段落です。 Summaryがどれだけ長くても仕様上は問題ありませんが、出来る限り一行に収めるべきです。 Summary セクションは省略可能です。

Description

次の無名のセクションが、Description です。 Summary の後、セクション名かコメント終端が現れるまでの 全ての段落がこのセクションに含まれます。

Description セクションは省略可能ですが、 Summary セクションなしに Description を書くことはできません。

/***********************************
 * myfunc 関数の短い要旨で、
 * ここがsummaryセクションになります。
 *
 * 概要の説明の第一段落です。
 *
 * 概要の説明の
 * 第二段落です。ここまでdescriptionセクション。
 */

void myfunc() { }

無名セクション SummaryDescription の後に、名前つきセクションが続きます。

標準セクション

一貫性やわかりやすさのために、幾つか標準的なセクションが規定されています。 どれも、必須の要素ではありません。

Authors:
コードを書いた人のリスト
/**
 * Authors: Melvin D. Nerd, melvin@mailinator.com
 */
Bugs:
既知のバグのリスト
/**
 * Bugs: 負の数では動作しない
 */
Date:
現在のバージョンの更新日時。 std.date で解析可能な形式で記述する
/**
 * Date: March 14, 2003
 */
Deprecated:
非推奨な宣言について、 代替手段についてなどの説明
/**
 * Deprecated: 関数 bar() に置き換えられました
 */

deprecated void foo() { ... }
Examples:
使い方の例
/**
 * Examples:
 * --------------------
 * writefln("3"); // 標準出力に '3' を表示
 * --------------------
 */
History:
更新履歴
/**
 * History:
 *	V1 最初のバージョン
 *
 *	V2 機能Xを追加
 */
License:
著作権のあるコードに関して、ライセンスの情報
/**
 * License: どんな用途にもご自由にお使いください
 */

void bar() { ... }
Returns:
関数の返値に関する説明。 void を返す場合、無駄にそうドキュメントを書かないこと
/**
 * ファイルを読み込みます
 * Returns: ファイルの内容
 */

void[] readFile(char[] filename) { ... }
See_Also:
関連する識別子や、URLのリスト
/**
 * See_Also:
 *    foo, bar, http://www.digitalmars.com/d/phobos/index.html
 */
Standards:
何らかの標準規格に準拠した宣言の場合、 そのことに関する説明はここに
/**
 * Standards: DSPEC-1234 準拠
 */
Throws:
送出される可能性のある例外と、例外が起きる場合のリスト
/**
 * ファイルに書き込みます
 * Throws: 失敗時, WriteException
 */

void writeFile(char[] filename) { ... }
Version:
現在のバージョン番号を記述します
/**
 * Version: 1.6a
 */

特殊セクション

幾つかのセクションには、特別な意味と構文が定義されています。

Copyright:
著作権表示のセクションです。モジュール宣言のドキュメントとして使われると、 このセクションの内容が COPYRIGHT マクロにセットされます。 Copyrightセクションは、 モジュール宣言に対して使われたときのみ特別な動作になります。
/** Copyright: Public Domain */

module foo;
Params:
関数の引数は、Params セクションにリストアップすることでドキュメント化します。 変数名、そして '=' と続く行が、新しい引数の説明の開始となります。 説明は 複数行にまたがっても構いません。
/***********************************
 * foo はこれこれの動作をします。
 * Params:
 *	x =	は、これに使われます。
 *		あれではありません。
 *	y =	は、あれに使われます。
 */

void foo(int x, int y)
{
}
Macros:
マクロセクションは、Params: セクションと同じ構文で書かれます。 つまり、NAME=value の組が複数並ぶことになります。 NAME がマクロ名で、value が置換先の文字列です。
/**
 * Macros:
 *	FOO =	本日は
 *		晴天なり
 *	BAR =	bar
 *	MAGENTA =   &lt;font color=magenta&gt;&lt;/font&gt;
 */

Highlighting

埋め込みコメント

ドキュメントコメントの中に、 $(DDOC_COMMENT comment text) 構文でコメントを入れることができます。 このコメントをネストすることはできません。

埋め込みコード

D のコードは、コードセクションを区切る 三個以上のハイフンを含む行によって埋め込むことができます。

/++
 + 我々の関数
 +
 + Example:
 + ---
 + import std.stdio;
 +
 + void foo()
 + {
 +     writefln("foo!");  /* 文字列を表示 */
 + }
 + ---
 +/

コードセクションの中で /++ ... +/ を使えるようにするため、ここではドキュメント化コメントとして /* ... */ 形式を使いました。

埋め込みHTML

ドキュメント化コメントの中にHTMLを埋め込むことも可能で、 HTML出力の際には変更されずそのまま出力されます。 しかし、必ずしも出力形式がHTMLであるとは限らないため、 実際には これは使わないでおくべきでしょう。

/**
 * HTML 埋め込みの例:
 *
 * <ol>
 *   <li><a href="http://www.digitalmars.com">Digital Mars</a></li>
 *   <li><a href="http://www.classicempire.com">Empire</a></li>
 * </ol>
 */

強調

ドキュメントコメント内の識別子で、関数の引数や、 その他関連する宣言のスコープで定義されている名前となっているものは 出力中で強調表示されます。 強調は、斜体や太字、ハイパーリンクなどで表現されます。 どのように強調されるかは、それが関数引数なのか、型なのか、 あるいはDの予約語なのか、などに依存します。 意図しない強調表示を避けるためには、単語の直前に下線 (_) をつけます。 この下線は出力時に自動的に除去されます。

文字実体

ドキュメントプロセッサにとって特別な意味を持つ文字が幾つか存在します。 混乱を避けるには、 それらの文字を対応するエンティティに置き換えるのがベストでしょう:

文字とエンティティ
文字 エンティティ
< &lt;
> &gt;
& &amp;

コードセクションの中でこの置換をしておく必要はありません。 あるいは特殊文字の直後に#や英数字が来ない場合も不要です。

ドキュメント生成されない場合

たとえドキュメントコメントがあったとしても、 以下の要素についてはドキュメントは生成されません。

マクロ

ドキュメント化コメントの処理系は、 単純なマクロテキストのプリプロセッサを備えています。 $(NAME) という形がセクションの文章に現れると、 対応するマクロ NAME の指す文字列へと置換されます。 置換後の文字列は再帰的に、さらなるマクロ展開のために走査されます。 再帰的に 同じマクロが同じ引数で出現した場合は、 空のテキストへと置換されます。 置換テキストの境界をまたぐようなマクロ起動は、 展開されません。 マクロ名が未定義の時は、 空文字列へと置換されます。 マクロ展開されずに $(NAME) という文字列そのものを出力したい場合は、 $ の代わりに &#36; と記述してください。

マクロは引数を取ることもできます。マクロ名の後ろから 閉じ括弧 ‘)’ までの全ての文字列が $0 引数です。 置換文字列の中の $0 が、 引数文字列に置き換えられます。 引数の中にカンマがあると、$1 が最初のカンマまでの文字列を表し、 $2 が最初のカンマから2番目のカンマまでを表し…、 と $9 まで用意されています。 $+ は、最初のカンマから閉じ ‘)’ までの文字列です。 引数文字列内にはネストした括弧や、"" や '' による文字列、 <!-- ... --> コメントやタグも含むことができます。 対応していない括弧が必要な場合は、 ( の代わりに文字実体 &#40;、) の代わりに &#41; を使用します。

マクロ定義は、 以下の位置から以下の順番で取得されます:

  1. 定義済みマクロ
  2. sc.inidmd.conf の DDOCFILE 設定での定義
  3. コマンドラインで指定された *.ddoc ファイルでの定義
  4. Ddoc によって生成される実行時定義
  5. Macros: セクションでの定義

マクロの再定義によって、前に定義された同名のマクロを置き換えることができます。 つまり、様々な定義元から取得された一連のマクロ定義は階層構造を なすことになります。

"D_" や "DDOC_" で始まるマクロ名は予約されています。

定義済みマクロ

これらは、Ddoc内部に組み込まれ、 Ddocが整形とハイライト処理を行うために必要な最小の定義セット となっているものです。 定義は、簡単なHTMLを出力するものとなっています。

B =     <b>$0</b>
I =     <i>$0</i>
U =     <u>$0</u>
P =     <p>$0</p>
DL =    <dl>$0</dl>
DT =    <dt>$0</dt>
DD =    <dd>$0</dd>
TABLE = <table>$0</table>
TR =    <tr>$0</tr>
TH =    <th>$0</th>
TD =    <td>$0</td>
OL =    <ol>$0</ol>
UL =    <ul>$0</ul>
LI =    <li>$0</li>
BIG =   <big>$0</big>
SMALL = <small>$0</small>
BR =    <br>
LINK =  <a href="$0">$0</a>
LINK2 = <a href="$1">$+</a>
LPAREN= (
RPAREN= )

RED =   <font color=red>$0</font>
BLUE =  <font color=blue>$0</font>
GREEN = <font color=green>$0</font>
YELLOW =<font color=yellow>$0</font>
BLACK = <font color=black>$0</font>
WHITE = <font color=white>$0</font>

D_CODE = <pre class="d_code">$0</pre>
D_COMMENT = $(GREEN $0)
D_STRING  = $(RED $0)
D_KEYWORD = $(BLUE $0)
D_PSYMBOL = $(U $0)
D_PARAM   = $(I $0)

DDOC = <html><head>
       <META http-equiv="content-type" content="text/html; charset=utf-8">
       <title>$(TITLE)</title>
       </head><body>
       <h1>$(TITLE)</h1>
       $(BODY)
       </body></html>

DDOC_COMMENT   = <!-- $0 -->
DDOC_DECL      = $(DT $(BIG $0))
DDOC_DECL_DD   = $(DD $0)
DDOC_DITTO     = $(BR)$0
DDOC_SECTIONS  = $0
DDOC_SUMMARY   = $0$(BR)$(BR)
DDOC_DESCRIPTION = $0$(BR)$(BR)
DDOC_AUTHORS   = $(B Authors:)$(BR)
		$0$(BR)$(BR)
DDOC_BUGS      = $(RED BUGS:)$(BR)
		$0$(BR)$(BR)
DDOC_COPYRIGHT = $(B Copyright:)$(BR)
		$0$(BR)$(BR)
DDOC_DATE      = $(B Date:)$(BR)
		$0$(BR)$(BR)
DDOC_DEPRECATED = $(RED Deprecated:)$(BR)
		$0$(BR)$(BR)
DDOC_EXAMPLES  = $(B Examples:)$(BR)
		$0$(BR)$(BR)
DDOC_HISTORY   = $(B History:)$(BR)
		$0$(BR)$(BR)
DDOC_LICENSE   = $(B License:)$(BR)
		$0$(BR)$(BR)
DDOC_RETURNS   = $(B Returns:)$(BR)
		$0$(BR)$(BR)
DDOC_SEE_ALSO  = $(B See Also:)$(BR)
		$0$(BR)$(BR)
DDOC_STANDARDS = $(B Standards:)$(BR)
		$0$(BR)$(BR)
DDOC_THROWS    = $(B Throws:)$(BR)
		$0$(BR)$(BR)
DDOC_VERSION   = $(B Version:)$(BR)
		$0$(BR)$(BR)
DDOC_SECTION_H = $(B $0)$(BR)$(BR)
DDOC_SECTION   = $0$(BR)$(BR)
DDOC_MEMBERS   = $(DL $0)
DDOC_MODULE_MEMBERS   = $(DDOC_MEMBERS $0)
DDOC_CLASS_MEMBERS    = $(DDOC_MEMBERS $0)
DDOC_STRUCT_MEMBERS   = $(DDOC_MEMBERS $0)
DDOC_ENUM_MEMBERS     = $(DDOC_MEMBERS $0)
DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)
DDOC_PARAMS    = $(B Params:)$(BR)\n$(TABLE $0)$(BR)
DDOC_PARAM_ROW = $(TR $0)
DDOC_PARAM_ID  = $(TD $0)
DDOC_PARAM_DESC  = $(TD $0)
DDOC_BLANKLINE = $(BR)$(BR)

DDOC_PSYMBOL = $(U $0)
DDOC_KEYWORD = $(B $0)
DDOC_PARAM   = $(I $0)

Ddoc は HTML コードを生成するわけではありません。Ddoc は基本書式化マクロを生成し、(その定義済み形式に従って) HTMLへの展開を行います。 HTML以外の形式での出力が必要な場合、 以下のマクロを再定義する必要があります。

基本書式化マクロ
B 引数を太字にする
I 引数を斜体にする
U 引数に下線をひく
P 引数をひとつの段落とする
DL 引数は定義リスト
DT 引数は定義リスト内の定義名
DD 引数は定義リスト内の定義説明部分
TABLE 引数は表
TR 引数は表の列
TH 引数は表の列のヘッダ項目
TD 引数は表の列のデータ項目
OL 引数は順序つきリスト
UL 引数は順序なしリスト
LI 引数はリストの要素
BIG 引数を一回り大きく表示
SMALL 引数を一回り小さく表示
BR 改行
LINK 引数をクリック可能なリンクとする
LINK2 引数をクリック可能なリンクとする。第一引数がアドレス
RED 引数を赤く表示
BLUE 引数を青く表示
GREEN 引数を緑に表示
YELLOW 引数を黄色く表示
BLACK 引数を黒く表示
WHITE 引数を白く表示
D_CODE 引数をDソースコードとして処理
DDOC 出力全体のテンプレート

DDOC は、生成されたテキスト全体(Ddocの生成するマクロ BODY で参照できます)が挿入される雛形になるという意味で、特殊なマクロです。 例えばスタイルシートを使うには、 DDOC を次のように再定義します:

DDOC =	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
	<html><head>
	<META http-equiv="content-type" content="text/html; charset=utf-8">
	<title>$(TITLE)</title>
	<link rel="stylesheet" type="text/css" href="style.css">
	</head><body>
	<h1>$(TITLE)</h1>
	$(BODY)
	</body></html>

DDOC_COMMENT は出力ファイルにコメントを挿入するのに使えます。

Dのソースコードのハイライト表示は以下のマクロで行われます:

D ソースコード整形マクロ
D_COMMENT コメントのハイライト
D_STRING 文字列リテラルのハイライト
D_KEYWORD 予約語のハイライト
D_PSYMBOL 現在の宣言名のハイライト
D_PARAM 現在の関数引数のハイライト

ハイライト表示マクロは DDOC_ で始まります。 これらによって表示の個々のパートの整形を制御します。

Ddoc セクション整形マクロ
DDOC_DECL 宣言のハイライト
DDOC_DECL_DD 宣言の説明部のハイライト
DDOC_DITTO ditto 宣言のハイライト
DDOC_SECTIONS 全セクションのハイライト
DDOC_SUMMARY Summaryセクションのハイライト
DDOC_DESCRIPTION Descriptionセクションのハイライト
DDOC_AUTHORS .. DDOC_VERSION それぞれ対応する標準セクションのハイライト
DDOC_SECTION_H 非標準セクションのセクション名のハイライト
DDOC_SECTION 非標準セクションの内容のハイライト
DDOC_MEMBERS クラスや構造体などのメンバのデフォルトのハイライト
DDOC_MODULE_MEMBERS モジュールメンバのハイライト
DDOC_CLASS_MEMBERS クラスメンバのハイライト
DDOC_STRUCT_MEMBERS 構造体メンバのハイライト
DDOC_ENUM_MEMBERS 列挙体メンバのハイライト
DDOC_TEMPLATE_MEMBERS テンプレートメンバのハイライト
DDOC_PARAMS 関数引数セクションのハイライト
DDOC_PARAM_ROW name=value 関数引数のハイライト
DDOC_PARAM_ID 引数名 name のハイライト
DDOC_PARAM_DESC 引数説明 value のハイライト
DDOC_PSYMBOL 特定のセクションから参照されている宣言名のハイライト
DDOC_KEYWORD D予約語のハイライト
DDOC_PARAM 関数引数のハイライト
DDOC_BLANKLINE 空行の挿入

例えば、DDOC_SUMMARY を次のように再定義できます:

DDOC_SUMMARY = $(GREEN $0)

これで、Summaryセクションが全て緑色になります。

sc.ini/dmd.conf の DDOCFILE によるマクロ定義

マクロ定義のテキストファイルを作っておくことができ、 sc.inidmd.conf で指定可能です:

DDOCFILE=myproject.ddoc

コマンドライン指定による .ddoc ファイルからのマクロ定義

拡張子 .ddoc を持つファイルが DMD のコマンドラインに渡ると、 順番に読み込まれ処理されます。

Ddoc の生成するマクロ定義

生成されるマクロ定義
マクロ名 内容
BODY ドキュメントテキスト本文が入ります
TITLE モジュール名が入ります
DATETIME 現在の日時が入ります
YEAR 現在の年が入ります
COPYRIGHT モジュールコメントの Copyright: セクションの内容が入ります
DOCFILENAME 生成されるファイルの名前が入ります
SRCFILENAME ドキュメント生成の元となった ソースファイルの名前が入ります。

他のドキュメント生成に Ddoc を使う

当初は Ddoc は、埋め込みコメントからのドキュメント生成用に作られました。 しかしながら、 その他の一般的なドキュメントの処理にも使用できます。 埋め込みコメント以外でも利用する利点としては、 Ddoc のマクロ機能や、 ソースコードの構文ハイライト機能があります。

.d ソースファイルが Ddoc という文字列で開始している場合、 Dのソースコードではなく一般的なドキュメントファイルとして扱われます。 "Ddoc" 文字列の直後から、ファイル終端か "Macros:" セクションまでがドキュメントとなります。 テキストには、---行 で囲まれた埋め込みソースコード部分以外は、 自動的構文ハイライト処理は行われません。 マクロ処理だけが実行されます。

このページを含め、 Dのドキュメントそのものも、多くはこのようにして生成されています。 そのようなドキュメントには、一番下に Ddoc で生成された旨を表示してあります。

参考文献

CandyDoc は、マクロとスタイルシートによって Ddoc の出力をカスタマイズする非常に良い例です。