[インデックス 10829] ファイルの概要
このコミットは、Go言語のドキュメンテーションツールであるgodoc
において、メソッドの例(Example)を記述し、それをgodoc
が正しく認識・表示できるようにする機能を追加するものです。具体的には、func ExampleT_M()
という命名規則を用いて型T
のメソッドM
の例を記述できるようになり、さらに複数の例を区別するために小文字で始まるサフィックスを追加する機能も導入されました。これにより、Goのドキュメンテーションの網羅性と利便性が向上しました。
コミット
- コミットハッシュ:
cb7d6e37d81a92eb990f314a3824ec17d9099f0c
- 作者: Volker Dobler dr.volker.dobler@gmail.com
- コミット日時: Fri Dec 16 10:01:54 2011 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cb7d6e37d81a92eb990f314a3824ec17d9099f0c
元コミット内容
godoc: Allow examples for methods.
An example for a method M() of type T can be written as
func ExampleT_M() { ... }.
To differentiate between multiple examples for one function, type or
method a suffix with a lowercase start may be appended to the name
of the example function, e.g. ExampleFoo_basicUsage.
Fixes #2465.
R=golang-dev, adg, r, rsc, duperray.olivier, r
CC=golang-dev
https://golang.org/cl/5440100
変更の背景
この変更は、GitHubのIssue #2465「godoc: no way to give examples of methods?」に対応するものです。Go言語の公式ドキュメンテーションツールであるgodoc
は、関数や型の使用例をコードとして記述し、それをドキュメントに含める「Example」機能を提供していました。しかし、この時点では、特定の型に紐づくメソッドのExampleを記述するための明確なメカニズムが存在しませんでした。
開発者は、関数や型のExampleと同様に、メソッドのExampleもドキュメントに含めることで、より実践的で理解しやすいドキュメンテーションを提供したいと考えていました。メソッドのExampleは、そのメソッドがどのように使われるべきかを示す上で非常に有効であり、特にライブラリの利用者にとっては、コードの理解を深める上で不可欠な情報となります。
このコミットは、godoc
がメソッドのExampleを認識し、適切に表示できるようにするための命名規則と、それを処理するロジックを導入することで、このギャップを埋めることを目的としています。
前提知識の解説
godoc
godoc
は、Go言語のソースコードからドキュメンテーションを生成するためのツールです。Goのコードは、コメントと特定の命名規則に従って記述されたExample関数によって、自己文書化されるように設計されています。godoc
はこれらの情報を解析し、HTML形式などで整形されたドキュメントとして提供します。これにより、開発者はコードとドキュメントを密接に連携させ、常に最新の状態に保つことができます。
GoのExample関数
GoのExample関数は、func ExampleFoo()
やfunc ExampleBar_Baz()
のようにExample
プレフィックスで始まる関数です。これらの関数は、テストコードと同じパッケージ内に配置され、go test
コマンドによって実行されます。Example関数の標準出力は、その関数のドキュメントコメントと比較され、一致すればテストが成功します。このメカニズムにより、Exampleコードが常に動作することが保証され、ドキュメントの信頼性が高まります。
Example関数は、以下の命名規則に従います。
- 関数:
func ExampleFunctionName()
- 型:
func ExampleTypeName()
- メソッド:
func ExampleTypeName_MethodName()
(このコミットで導入)
また、同じ関数、型、またはメソッドに対して複数のExampleを提供したい場合、サフィックスを追加することができます。
- サフィックス付きExample:
func ExampleFunctionName_suffix()
このコミットでは、メソッドのExampleに加えて、サフィックスのルールも明確化されました。特に、サフィックスが小文字で始まる場合にのみ、それがExampleの識別子として扱われるという点が重要です。これにより、ExampleFoo_Bar
のようなケース(Bar
が型名の一部である場合など)と、ExampleFoo_basicUsage
のようなケース(basicUsage
が単なる説明的なサフィックスである場合)を区別できるようになります。
技術的詳細
このコミットの主要な技術的変更点は、godoc
がExample関数を解析するロジックに、メソッドのExampleとサフィックスの新しい命名規則を組み込んだことです。
-
メソッドExampleの認識:
func ExampleT_M()
という形式の関数名を、型T
のメソッドM
のExampleとして認識するようにgodoc
のパーサーが拡張されました。これは、関数名にアンダースコア_
が含まれる場合、その後の部分がメソッド名であると解釈されることを意味します。 -
サフィックスの処理: 複数のExampleを区別するために使用されるサフィックスの処理ロジックが変更されました。以前は、アンダースコア以降の全てをサフィックスとして切り捨てていましたが、新しいロジックでは、サフィックスが小文字で始まる場合にのみ切り捨てるようになりました。これにより、
ExampleFoo_Bar
のようなケースでBar
が型名の一部である場合に、誤って切り捨てられることを防ぎます。ExampleFoo_basicUsage
->Foo
(basicUsage
は小文字で始まるためサフィックスとして切り捨てられる)ExampleFoo_Bar
->Foo_Bar
(もしBar
が型名の一部で、大文字で始まる場合、サフィックスとして切り捨てられない)
このロジックを実現するために、
startsWithUppercase
というヘルパー関数が導入されました。この関数は、文字列の最初の文字が大文字であるかどうかを判定します。 -
ドキュメンテーションの更新:
src/cmd/gotest/doc.go
内のExample関数の命名規則に関するドキュメンテーションが更新され、メソッドのExampleの命名規則と、サフィックスに関する新しいルールが明記されました。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルは以下の2つです。
src/cmd/godoc/godoc.go
:godoc
ツールのExample関数処理ロジックが含まれるファイル。src/cmd/gotest/doc.go
:go test
コマンドのExample機能に関するドキュメンテーションファイル。
src/cmd/godoc/godoc.go
の変更点
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -26,6 +26,8 @@ import (
"strings"
"text/template"
"time"
+ "unicode"
+ "unicode/utf8"
)
// ----------------------------------------------------------------------------
@@ -482,14 +484,24 @@ func comment_textFunc(comment, indent, preIndent string) string {
return buf.String()
}
+func startsWithUppercase(s string) bool {
+ r, _ := utf8.DecodeRuneInString(s)
+ return unicode.IsUpper(r)
+}
+
func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.FileSet) string {
var buf bytes.Buffer
for _, eg := range examples {
- // accept Foo or Foo_.* for funcName == Foo
name := eg.Name
- if i := strings.Index(name, "_"); i >= 0 {
- name = name[:i]
+
+ // strip lowercase braz in Foo_braz or Foo_Bar_braz from name
+ // while keeping uppercase Braz in Foo_Braz
+ if i := strings.LastIndex(name, "_"); i != -1 {
+ if i < len(name)-1 && !startsWithUppercase(name[i+1:]) {
+ name = name[:i]
+ }
}
+
if name != funcName {
continue
}
src/cmd/gotest/doc.go
の変更点
--- a/src/cmd/gotest/doc.go
+++ b/src/cmd/gotest/doc.go
@@ -35,8 +35,15 @@ os.Stdout and os.Stderr is compared against their doc comment.
fmt.Println("The output of this example function.")
}
-Multiple example functions may be provided for a given name XXX if they are
-discriminated by a distinct suffix starting with "_", such as ExampleXXX_2.
+The following naming conventions are used to declare examples for a function F,
+a type T and method M on type T:
+ func ExampleF() { ... } and func ExampleF_suffix() { ... }
+ func ExampleT() { ... } and func ExampleT_suffix() { ... }
+ func ExampleT_M() { ... } and func ExampleT_M_suffix() { ... }
+
+Multiple example functions may be provided by appending a distinct suffix
+to the name. The suffix must start with a lowercase letter.
+
Example functions without doc comments are compiled but not executed.
See the documentation of the testing package for more information.
コアとなるコードの解説
src/cmd/godoc/godoc.go
- インポートの追加:
unicode
とunicode/utf8
パッケージが新しくインポートされています。これらは、文字列のルーン(Unicodeコードポイント)をデコードし、その文字が大文字であるかを判定するために使用されます。 startsWithUppercase
関数の追加:
このヘルパー関数は、与えられた文字列func startsWithUppercase(s string) bool { r, _ := utf8.DecodeRuneInString(s) return unicode.IsUpper(r) }
s
の最初のルーンをデコードし、それが大文字であるかどうかをunicode.IsUpper
関数を使って判定します。この関数は、Example関数のサフィックスが小文字で始まるかどうかをチェックするために利用されます。example_htmlFunc
の変更: この関数は、Example関数をHTMLドキュメントに整形する際に、Example関数の名前を処理するロジックを含んでいます。- 以前は、
strings.Index(name, "_")
を使って最初のアンダースコアを見つけ、それ以降を無条件に切り捨てていました。これは、ExampleFoo_Bar
のようなメソッドのExampleを正しく処理できない可能性がありました。 - 新しいロジックでは、
strings.LastIndex(name, "_")
を使って最後のアンダースコアを見つけます。 - そして、
if i < len(name)-1 && !startsWithUppercase(name[i+1:])
という条件が追加されました。これは、アンダースコアの後に文字があり、かつその文字が大文字で始まらない場合にのみ、アンダースコア以降の部分を切り捨てるというロジックです。ExampleT_M_suffix
の場合、最後のアンダースコアは_suffix
の前にあります。suffix
は小文字で始まるため、!startsWithUppercase("suffix")
はtrue
となり、_suffix
が切り捨てられ、ExampleT_M
が残ります。ExampleT_M
の場合、アンダースコアはT_M
の間にあります。M
は大文字で始まるため、!startsWithUppercase("M")
はfalse
となり、何も切り捨てられず、ExampleT_M
がそのまま残ります。 この変更により、godoc
はメソッドのExample(例:ExampleT_M
)を正しく識別し、さらに複数のExampleを区別するための小文字で始まるサフィックス(例:ExampleT_M_basicUsage
)も適切に処理できるようになりました。
- 以前は、
src/cmd/gotest/doc.go
- Example関数の命名規則に関するドキュメンテーションが大幅に更新されました。
- 関数、型、およびメソッドのExampleの命名規則が明確に示されています。
func ExampleF() { ... }
およびfunc ExampleF_suffix() { ... }
(関数)func ExampleT() { ... }
およびfunc ExampleT_suffix() { ... }
(型)func ExampleT_M() { ... }
およびfunc ExampleT_M_suffix() { ... }
(メソッド)
- 複数のExample関数を提供する場合、サフィックスは小文字で始まる必要があるという重要なルールが明記されました。これにより、
godoc
の新しい解析ロジックとドキュメンテーションが整合します。
関連リンク
- GitHub Issue: https://github.com/golang/go/issues/2465
- Go CL (Change List): https://golang.org/cl/5440100