[インデックス 11951] ファイルの概要
このコミットは、Go言語の公式ドキュメンテーションツールであるgodoc
の機能改善に関するものです。具体的には、GoのExample関数に記述されたドキュメンテーションコメントが、godoc
のWeb UI上で表示されるように変更が加えられました。これにより、Exampleコードが何を示しているのか、どのような意図で書かれたのかといった背景情報が、ユーザーにとってより明確に伝わるようになります。
コミット
commit 7c9662f4612979298642a17cb4e8a52559e204ba
Author: Andrew Gerrand <adg@golang.org>
Date: Thu Feb 16 12:43:22 2012 +1100
godoc: show example function doc comments in UI
R=gri
CC=golang-dev
https://golang.org/cl/5677061
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7c9662f4612979298642a17cb4e8a52559e204ba
元コミット内容
godoc: show example function doc comments in UI
R=gri
CC=golang-dev
https://golang.org/cl/5677061
変更の背景
Go言語では、コードのExample(例)を記述するための特別な関数(Example
で始まる関数)がサポートされています。これらのExample関数は、単にコードの動作を示すだけでなく、そのExampleが何を目的としているのか、どのような状況で役立つのかといった説明をドキュメンテーションコメントとして記述することが推奨されています。
しかし、このコミット以前のgodoc
では、Example関数のコードと出力は表示されるものの、それに付随するドキュメンテーションコメントはWeb UI上に表示されていませんでした。このため、Exampleの意図を完全に理解するためには、ソースコードを直接参照する必要がありました。
この変更の背景には、godoc
が提供するドキュメンテーションの完全性と利便性を向上させ、ユーザーがExampleコードの意図をより簡単に把握できるようにするという目的があります。Example関数のドキュメンテーションコメントを表示することで、godoc
はより包括的なドキュメンテーション体験を提供できるようになります。
前提知識の解説
godoc
godoc
は、Go言語のソースコードからドキュメンテーションを生成し、表示するためのツールです。Go言語の設計思想の一つに「ドキュメンテーションはコードと共にあるべき」という考え方があり、godoc
はその思想を具現化したものです。
- コードからのドキュメンテーション生成:
godoc
は、Goのソースコードに記述されたコメント(特にパッケージ、関数、型、変数などの宣言の直前に記述されたコメント)を解析し、HTML形式のドキュメンテーションを生成します。 - Example関数のサポート: Goでは、
Example
というプレフィックスを持つ関数を記述することで、そのパッケージのExampleコードを提供できます。これらのExample関数は、go test
コマンドで実行可能であり、その出力が期待される出力と一致するかどうかをテストすることもできます。godoc
はこれらのExampleコードも解析し、ドキュメンテーションに含めます。 - Webサーバー機能:
godoc
は、生成したドキュメンテーションをWebブラウザで閲覧するためのHTTPサーバーとしても機能します。これにより、ローカル環境で簡単にGoの標準ライブラリや自身のプロジェクトのドキュメンテーションを参照できます。
GoのExample関数とドキュメンテーションコメント
GoのExample関数は、以下のような形式で記述されます。
package mypackage
import (
"fmt"
)
// ExampleHello は、Hello関数がどのように使われるかを示すExampleです。
// このExampleは、"Hello, World!"という文字列を出力します。
func ExampleHello() {
fmt.Println("Hello, World!")
// Output: Hello, World!
}
func Hello() {
fmt.Println("Hello, World!")
}
上記のExampleHello
関数の場合、// ExampleHello は、...
から始まるコメントがExample関数のドキュメンテーションコメントです。このコメントは、Exampleコードの目的や動作を説明するために使用されます。// Output:
行は、Exampleの期待される出力を指定するために使用され、go test
によって検証されます。
Goのtext/template
パッケージ
godoc
のWeb UIは、Goの標準ライブラリであるtext/template
パッケージを使用してHTMLを生成しています。text/template
は、データ構造をテンプレートに適用してテキスト出力を生成するための強力なツールです。
- アクション: テンプレート内では、
{{.FieldName}}
のようなプレースホルダーや、{{if .Condition}}...{{end}}
、{{range .Slice}}...{{end}}
、{{with .Value}}...{{end}}
のような制御構造(アクション)を使用できます。 {{with .Value}}...{{end}}
: このアクションは、.Value
がnilまたはゼロ値でない場合に、そのブロック内のテンプレートを実行し、.Value
を現在のコンテキスト(ドット)に設定します。これは、特定のフィールドが存在する場合にのみコンテンツを表示する際に便利です。
Goのgo/ast
パッケージ
go/ast
パッケージは、Goのソースコードの抽象構文木(AST: Abstract Syntax Tree)を表現するためのデータ構造と、それを操作するための関数を提供します。godoc
のようなツールは、このパッケージを使用してGoのソースコードを解析し、その構造やコメントなどの情報を抽出します。
ast.File
: Goの単一のソースファイルを表すASTノードです。ast.FuncDecl
: 関数宣言を表すASTノードです。ast.CommentGroup
: コメントのグループを表すASTノードです。関数や型の宣言に付随するドキュメンテーションコメントは、このCommentGroup
としてAST内に格納されます。f.Doc.Text()
:ast.FuncDecl
のDoc
フィールドは、その関数に付随するドキュメンテーションコメントの*ast.CommentGroup
を保持します。Text()
メソッドは、そのコメントグループから整形されたテキストを返します。
技術的詳細
このコミットは、Example関数のドキュメンテーションコメントをgodoc
のWeb UIに表示するために、以下の3つの主要なコンポーネントにわたる変更を加えています。
-
AST(抽象構文木)の解析とデータ構造の拡張:
src/pkg/go/ast/example.go
が変更され、Example
構造体にDoc string
フィールドが追加されました。Examples
関数内で、Example関数を解析する際に、その関数のドキュメンテーションコメント(f.Doc.Text()
)を抽出し、新しく追加されたDoc
フィールドに格納するように変更されました。これにより、Example関数のドキュメンテーションコメントが、godoc
の内部データモデルの一部として扱われるようになります。
-
godoc
コマンドのデータ渡し:src/cmd/godoc/godoc.go
が変更され、example_htmlFunc
関数内でHTMLテンプレートに渡すデータ構造に、Exampleのドキュメンテーションコメント(eg.Doc
)が追加されました。これにより、HTMLテンプレートがExampleのドキュメンテーションコメントにアクセスできるようになります。
-
HTMLテンプレートの更新:
lib/godoc/example.html
が変更され、Exampleのドキュメンテーションコメントを表示するためのHTML要素が追加されました。具体的には、{{with .Doc}}<p>{{html .}}</p>{{end}}
という行が追加され、Doc
フィールドが存在する場合にその内容を段落として表示するようにしました。- また、
{{if .Output}}
が{{with .Output}}
に変更されました。これは機能的には大きな違いはありませんが、with
アクションは、変数が存在する場合にその変数を現在のコンテキストに設定するため、テンプレートの記述をより簡潔にするGoテンプレートの慣用的な書き方です。
これらの変更により、godoc
はExample関数のドキュメンテーションコメントを内部的に取得し、それをWeb UIにレンダリングする一連のパイプラインが完成しました。
コアとなるコードの変更箇所
lib/godoc/example.html
--- a/lib/godoc/example.html
+++ b/lib/godoc/example.html
@@ -4,11 +4,12 @@
</div>
<div class="expanded">
<p class="exampleHeading">▾ Example{{example_suffix .Name}}</p>
+ {{with .Doc}}<p>{{html .}}</p>{{end}}
<p>Code:</p>
<pre class="code">{{.Code}}</pre>
- {{if .Output}}\
+ {{with .Output}}\
<p>Output:</p>
- <pre class="output">{{html .Output}}</pre>
+ <pre class="output">{{html .}}</pre>
{{end}}
</div>
</div>
src/cmd/godoc/godoc.go
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -539,8 +539,8 @@ func example_htmlFunc(funcName string, examples []*ast.Example, fset *token.File
}
err := exampleHTML.Execute(&buf, struct {
- Name, Code, Output string
- }{eg.Name, code, out})
+ Name, Doc, Code, Output string
+ }{eg.Name, eg.Doc, code, out})
if err != nil {
log.Print(err)
}
src/pkg/go/ast/example.go
--- a/src/pkg/go/ast/example.go
+++ b/src/pkg/go/ast/example.go
@@ -16,6 +16,7 @@ import (
type Example struct {
Name string // name of the item being exemplified
+ Doc string // example function doc string
Code Node
Comments []*CommentGroup
Output string // expected output
@@ -45,8 +46,13 @@ func Examples(files ...*File) []*Example {
if !isTest(name, "Example") {
continue
}
+ var doc string
+ if f.Doc != nil {
+ doc = f.Doc.Text()
+ }
flist = append(flist, &Example{
Name: name[len("Example"):],
+ Doc: doc,\
Code: f.Body,
Comments: file.Comments,
Output: exampleOutput(f, file.Comments),
コアとなるコードの解説
lib/godoc/example.html
の変更
{{with .Doc}}<p>{{html .}}</p>{{end}}
:{{with .Doc}}
は、テンプレートに渡されたデータ構造のDoc
フィールドが空でない場合に、その内部のブロックを実行します。Doc
フィールドはExample関数のドキュメンテーションコメントのテキストを含みます。<p>
タグで囲むことで、ドキュメンテーションコメントが独立した段落として表示されます。{{html .}}
は、Doc
フィールドの内容をHTMLエスケープして出力します。これにより、コメント内にHTML特殊文字が含まれていても、正しく表示され、XSS(クロスサイトスクリプティング)などのセキュリティリスクを防ぎます。
{{if .Output}}
から{{with .Output}}
への変更:- これは機能的な変更というよりは、Goの
text/template
における慣用的な書き方への修正です。with
アクションは、変数が存在する場合にその変数を現在のコンテキスト(.
)に設定するため、{{html .Output}}
を{{html .}}
と短縮して記述できるようになります。
- これは機能的な変更というよりは、Goの
src/cmd/godoc/godoc.go
の変更
example_htmlFunc
関数内のstruct
定義の変更:- HTMLテンプレートに渡される匿名構造体に
Doc string
フィールドが追加されました。 {eg.Name, eg.Doc, code, out}
という形で、eg.Doc
(ast.Example
構造体から取得したドキュメンテーションコメント)がこの構造体に渡されるようになりました。これにより、HTMLテンプレートが{{.Doc}}
としてこの値にアクセスできるようになります。
- HTMLテンプレートに渡される匿名構造体に
src/pkg/go/ast/example.go
の変更
Example
構造体へのDoc string
フィールドの追加:type Example struct { ... Doc string ... }
という行が追加され、Exampleのメタデータとしてドキュメンテーションコメントを保持できるようになりました。
Examples
関数内の変更:var doc string
でdoc
変数を宣言し、Example関数のASTノードf
のf.Doc
フィールドがnil
でない場合に、f.Doc.Text()
を呼び出してドキュメンテーションコメントのテキストを取得しています。- 取得した
doc
変数の値を、新しく作成されるExample
構造体のDoc
フィールドに代入しています。 f.Doc
は*ast.CommentGroup
型であり、Text()
メソッドはコメントグループから整形された文字列を返します。これにより、Example関数のドキュメンテーションコメントが正確に抽出され、Example
構造体に格納されるようになります。
これらの変更が連携することで、Example関数のドキュメンテーションコメントがgodoc
のWeb UIに表示されるという機能が実現されています。
関連リンク
- Go言語のExample関数に関する公式ドキュメント: https://go.dev/blog/examples
godoc
コマンドに関する公式ドキュメント: https://pkg.go.dev/cmd/godoctext/template
パッケージのドキュメント: https://pkg.go.dev/text/templatego/ast
パッケージのドキュメント: https://pkg.go.dev/go/ast
参考にした情報源リンク
- https://golang.org/cl/5677061 (このコミットのGerrit Code Reviewリンク)
- Go言語の公式ドキュメントおよびブログ記事
- Go言語のソースコード(特に
src/cmd/godoc
、src/pkg/go/ast
、lib/godoc
ディレクトリ) text/template
パッケージの挙動に関する一般的なGoのドキュメンテーションとチュートリアルgo/ast
パッケージのAST解析に関する一般的なGoのドキュメンテーションとチュートリアルgodoc
のExample表示に関する情報(Web検索)- GoのExample関数の書き方に関する情報(Web検索)