Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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とサフィックスの新しい命名規則を組み込んだことです。

  1. メソッドExampleの認識: func ExampleT_M()という形式の関数名を、型TのメソッドMのExampleとして認識するようにgodocのパーサーが拡張されました。これは、関数名にアンダースコア_が含まれる場合、その後の部分がメソッド名であると解釈されることを意味します。

  2. サフィックスの処理: 複数のExampleを区別するために使用されるサフィックスの処理ロジックが変更されました。以前は、アンダースコア以降の全てをサフィックスとして切り捨てていましたが、新しいロジックでは、サフィックスが小文字で始まる場合にのみ切り捨てるようになりました。これにより、ExampleFoo_BarのようなケースでBarが型名の一部である場合に、誤って切り捨てられることを防ぎます。

    • ExampleFoo_basicUsage -> Foo (basicUsageは小文字で始まるためサフィックスとして切り捨てられる)
    • ExampleFoo_Bar -> Foo_Bar (もしBarが型名の一部で、大文字で始まる場合、サフィックスとして切り捨てられない)

    このロジックを実現するために、startsWithUppercaseというヘルパー関数が導入されました。この関数は、文字列の最初の文字が大文字であるかどうかを判定します。

  3. ドキュメンテーションの更新: src/cmd/gotest/doc.go内のExample関数の命名規則に関するドキュメンテーションが更新され、メソッドのExampleの命名規則と、サフィックスに関する新しいルールが明記されました。

コアとなるコードの変更箇所

このコミットで変更された主要なファイルは以下の2つです。

  1. src/cmd/godoc/godoc.go: godocツールのExample関数処理ロジックが含まれるファイル。
  2. 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

  • インポートの追加: unicodeunicode/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の新しい解析ロジックとドキュメンテーションが整合します。

関連リンク

参考にした情報源リンク