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

[インデックス 13120] ファイルの概要

このコミットは、Go言語のドキュメンテーションツールであるgodocsynopsis(概要)抽出ロジックを改善するものです。具体的には、ファイルの先頭にある著作権表示、権利に関する記述、著者情報などの定型文が誤って概要として抽出されるのを防ぐため、特定のプレフィックスで始まる行を概要から除外する機能が追加されました。これにより、godocが生成するドキュメントの品質が向上し、より意味のある概要が表示されるようになります。

コミット

commit f596eb5d8deba23365e7d656e43ed6c2d6189f65
Author: Robert Griesemer <gri@golang.org>
Date:   Tue May 22 10:04:13 2012 -0700

    godoc: slightly smarter synopsis extraction
    
    Ignore synopses that start with
    "Copyright", "All rights", and "Author".
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/6218047
---
 src/pkg/go/doc/synopsis.go      | 41 +++++++++++++++++++++++++++++++----------
 src/pkg/go/doc/synopsis_test.go |  5 +++++
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/src/pkg/go/doc/synopsis.go b/src/pkg/go/doc/synopsis.go
index 2192d78c0c..2d18174393 100644
--- a/src/pkg/go/doc/synopsis.go
+++ b/src/pkg/go/doc/synopsis.go
@@ -4,7 +4,10 @@
 
 package doc
 
-import "unicode"
+import (
+	"strings"
+	"unicode"
+)
 
 // firstSentenceLen returns the length of the first sentence in s.
 // The sentence ends after the first period followed by space and
@@ -24,17 +27,12 @@ func firstSentenceLen(s string) int {
 	return len(s)
 }\n 
-// Synopsis returns a cleaned version of the first sentence in s.\n-// That sentence ends after the first period followed by space and\n-// not preceded by exactly one uppercase letter. The result string\n-// has no \\n, \\r, or \\t characters and uses only single spaces between\n-// words.\n-//\n-func Synopsis(s string) string {\n-\tn := firstSentenceLen(s)\n+// clean replaces each sequence of space, \\n, \\r, or \\t characters\n+// with a single space and removes any trailing and leading spaces.\n+func clean(s string) string {\n \tvar b []byte\n \tp := byte(' ')\n-\tfor i := 0; i < n; i++ {\n+\tfor i < len(s); i++ {\n \t\tq := s[i]\n \t\tif q == '\\n' || q == '\\r' || q == '\\t' {\n \t\t\tq = ' '\n@@ -50,3 +48,26 @@ func Synopsis(s string) string {\n \t}\n \treturn string(b)\n }\n+\n+// Synopsis returns a cleaned version of the first sentence in s.\n+// That sentence ends after the first period followed by space and\n+// not preceded by exactly one uppercase letter. The result string\n+// has no \\n, \\r, or \\t characters and uses only single spaces between\n+// words. If s starts with any of the IllegalPrefixes, the result\n+// is the empty string.\n+//\n+func Synopsis(s string) string {\n+\ts = clean(s[0:firstSentenceLen(s)])\n+\tfor _, prefix := range IllegalPrefixes {\n+\t\tif strings.HasPrefix(strings.ToLower(s), prefix) {\n+\t\t\treturn ""\n+\t\t}\n+\t}\n+\treturn s\n+}\n+\n+var IllegalPrefixes = []string{\n+\t"copyright",\n+\t"all rights",\n+\t"author",\n+}\ndiff --git a/src/pkg/go/doc/synopsis_test.go b/src/pkg/go/doc/synopsis_test.go
index dfc6598af4..fd7081a07c 100644
--- a/src/pkg/go/doc/synopsis_test.go
+++ b/src/pkg/go/doc/synopsis_test.go
@@ -28,6 +28,11 @@ var tests = []struct {
 	{"P. Q.   ", 8, "P. Q."},\n 	{"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."},\n 	{"Package こんにちは 世界\n", 31, "Package こんにちは 世界"},\n+\t{"Package foo does bar.", 21, "Package foo does bar."},\n+\t{"Copyright 2012 Google, Inc. Package foo does bar.", 27, ""},\n+\t{"All Rights reserved. Package foo does bar.", 20, ""},\n+\t{"All rights reserved. Package foo does bar.", 20, ""},\n+\t{"Authors: foo@bar.com. Package foo does bar.", 21, ""},\n }\n \n func TestSynopsis(t *testing.T) {\n```

## GitHub上でのコミットページへのリンク

[https://github.com/golang/go/commit/f596eb5d8deba23365e7d656e43ed6c2d6189f65](https://github.com/golang/go/commit/f596eb5d8deba23365e7d656e43ed6c2d6189f65)

## 元コミット内容

`godoc`の概要抽出をわずかに賢くする。
"Copyright", "All rights", "Author"で始まる概要を無視する。

## 変更の背景

Go言語のドキュメンテーションツールである`godoc`は、Goのソースコードから自動的にドキュメントを生成します。この際、パッケージや関数の概要(synopsis)を抽出するために、コメントブロックの最初の文を使用します。しかし、多くのソースファイルでは、ファイルの冒頭に著作権情報、権利に関する記述、著者情報などがコメントとして記述されています。

従来の`godoc`の概要抽出ロジックでは、これらの定型文がファイルの最初のコメントとして認識され、そのままパッケージの概要として表示されてしまう問題がありました。これは、ユーザーが求めているパッケージの機能や目的を説明する本来の概要とは異なり、ドキュメントの可読性や有用性を損ねていました。

このコミットは、このような不適切な概要の抽出を防ぎ、より関連性の高い情報が概要として表示されるようにするために行われました。具体的には、特定のキーワード("Copyright", "All rights", "Author")で始まる文を概要として採用しないようにすることで、`godoc`が生成するドキュメントの品質を向上させることを目的としています。

## 前提知識の解説

### godoc

`godoc`は、Go言語のソースコードからドキュメントを生成するためのツールです。Goのコードは、特定のコメント規約に従って記述することで、`godoc`によって自動的に解析され、HTML形式のドキュメントとして提供されます。これは、Goの「ドキュメントはコードの一部である」という哲学を反映しており、開発者がコードとドキュメントを同時にメンテナンスしやすくする設計思想に基づいています。

`godoc`は、パッケージ、関数、型、変数などの各要素に対して、その直前のコメントブロックを解析し、ドキュメントとして表示します。特に、パッケージの概要は、そのパッケージの目的や機能を手早く理解するために非常に重要です。

### Synopsis(概要)

`godoc`における「Synopsis」とは、パッケージや公開された要素(関数、型など)の短い説明文を指します。通常、これはコメントブロックの最初の文から抽出されます。この概要は、`godoc`のインデックスページや、パッケージのトップページで、その要素の目的を簡潔に伝えるために使用されます。

例えば、以下のようなGoコードがあったとします。

```go
// Package mypackage provides utilities for string manipulation.
// It includes functions for reversing strings, counting characters, etc.
package mypackage

// Reverse reverses a given string.
func Reverse(s string) string {
    // ...
}

この場合、godocmypackageのSynopsisとして「Package mypackage provides utilities for string manipulation.」を、Reverse関数のSynopsisとして「Reverse reverses a given string.」を抽出します。

Goのドキュメンテーション規約

Goのドキュメンテーション規約では、公開される要素(大文字で始まる名前)には、その要素の直前にコメントを記述することが推奨されています。パッケージコメントはpackageキーワードの直前に記述し、パッケージ名で始まるべきだとされています。同様に、関数や型のコメントも、その要素の名前で始まるべきだとされています。これにより、godocが適切な概要を抽出しやすくなります。

技術的詳細

このコミットでは、src/pkg/go/doc/synopsis.goファイルが変更され、Synopsis関数の動作が修正されました。主な変更点は以下の通りです。

  1. stringsパッケージのインポート: 新たに文字列操作を行うためにstringsパッケージがインポートされました。
  2. clean関数の分離: 既存のSynopsis関数内にあった、空白文字(スペース、改行、タブ)を単一のスペースに置き換え、前後の空白を削除する処理が、cleanという独立した関数として分離されました。これにより、コードの再利用性と可読性が向上しています。
    • clean関数は、入力文字列sを受け取り、\n, \r, \tをスペースに変換し、連続するスペースを1つにまとめ、最終的に前後のスペースをトリムした文字列を返します。
  3. Synopsis関数のロジック変更:
    • まず、firstSentenceLen関数を使って最初の文の長さを取得し、その部分文字列をclean関数で整形します。
    • 次に、新しく定義されたIllegalPrefixesスライスに含まれるいずれかのプレフィックスで、整形された概要文字列が始まるかどうかをチェックします。このチェックは、大文字・小文字を区別しないように、概要文字列を小文字に変換してから行われます(strings.ToLower(s))。
    • もし、概要文字列がIllegalPrefixesのいずれかのプレフィックスで始まる場合、その概要は不適切と判断され、空文字列""が返されます。
    • そうでない場合は、整形された概要文字列がそのまま返されます。
  4. IllegalPrefixes変数の追加:
    • copyright
    • all rights
    • author これらの文字列を要素として持つIllegalPrefixesというグローバル変数が追加されました。これらは、godocの概要として無視すべき定型文のプレフィックスを定義しています。

これらの変更により、Synopsis関数は、単に最初の文を抽出して整形するだけでなく、その内容が特定の「無視すべき」プレフィックスで始まるかどうかを判断し、もしそうであれば空の概要を返すようになりました。これにより、著作権表示などが誤って概要として表示される問題が解決されます。

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

src/pkg/go/doc/synopsis.go

--- a/src/pkg/go/doc/synopsis.go
+++ b/src/pkg/go/doc/synopsis.go
@@ -4,7 +4,10 @@
 
 package doc
 
-import "unicode"
+import (
+	"strings"
+	"unicode"
+)
 
 // firstSentenceLen returns the length of the first sentence in s.
 // The sentence ends after the first period followed by space and
@@ -24,17 +27,12 @@ func firstSentenceLen(s string) int {
 	return len(s)
 }
 
-// Synopsis returns a cleaned version of the first sentence in s.
-// That sentence ends after the first period followed by space and
-// not preceded by exactly one uppercase letter. The result string
-// has no \n, \r, or \t characters and uses only single spaces between
-// words.
-//
-func Synopsis(s string) string {
-	n := firstSentenceLen(s)
+// clean replaces each sequence of space, \n, \r, or \t characters
+// with a single space and removes any trailing and leading spaces.
+func clean(s string) string {
 	var b []byte
 	p := byte(' ')
-	for i := 0; i < n; i++ {
+	for i := 0; i < len(s); i++ {
 		q := s[i]
 		if q == '\n' || q == '\r' || q == '\t' {
 			q = ' '
@@ -50,3 +48,26 @@ func Synopsis(s string) string {
 	}
 	return string(b)
 }
+
+// Synopsis returns a cleaned version of the first sentence in s.
+// That sentence ends after the first period followed by space and
+// not preceded by exactly one uppercase letter. The result string
+// has no \n, \r, or \t characters and uses only single spaces between
+// words. If s starts with any of the IllegalPrefixes, the result
+// is the empty string.
+//
+func Synopsis(s string) string {
+	s = clean(s[0:firstSentenceLen(s)])
+	for _, prefix := range IllegalPrefixes {
+		if strings.HasPrefix(strings.ToLower(s), prefix) {
+			return ""
+		}
+	}
+	return s
+}
+
+var IllegalPrefixes = []string{
+	"copyright",
+	"all rights",
+	"author",
+}

src/pkg/go/doc/synopsis_test.go

--- a/src/pkg/go/doc/synopsis_test.go
+++ b/src/pkg/go/doc/synopsis_test.go
@@ -28,6 +28,11 @@ var tests = []struct {
 	{"P. Q.   ", 8, "P. Q."},\n 	{"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."},\n 	{"Package こんにちは 世界\n", 31, "Package こんにちは 世界"},\n+\t{"Package foo does bar.", 21, "Package foo does bar."},\n+\t{"Copyright 2012 Google, Inc. Package foo does bar.", 27, ""},\n+\t{"All Rights reserved. Package foo does bar.", 20, ""},\n+\t{"All rights reserved. Package foo does bar.", 20, ""},\n+\t{"Authors: foo@bar.com. Package foo does bar.", 21, ""},\n }\n \n func TestSynopsis(t *testing.T) {

コアとなるコードの解説

src/pkg/go/doc/synopsis.go

  • import "strings" の追加: strings.HasPrefix関数を使用するために、stringsパッケージがインポートされました。
  • clean 関数の新設:
    • 以前Synopsis関数内にあった、空白文字の正規化処理がclean関数として独立しました。
    • この関数は、改行(\n, \r)やタブ(\t)をスペースに変換し、連続するスペースを一つにまとめ、文字列の先頭と末尾のスペースを削除する役割を担います。これにより、概要文字列が常に整形された状態になります。
  • Synopsis 関数の再実装:
    • まず、firstSentenceLen(s)で最初の文の長さを取得し、その部分文字列をclean関数で整形します。これにより、概要候補がクリーンな状態になります。
    • 次に、forループとstrings.HasPrefix(strings.ToLower(s), prefix)を使って、整形された概要候補がIllegalPrefixesのいずれかの要素で始まるかをチェックします。strings.ToLower(s)を使用することで、大文字・小文字を区別せずに比較が行われます。
    • もし一致するプレフィックスが見つかった場合、その概要は不適切と判断され、空文字列""が返されます。
    • 一致するプレフィックスがなければ、整形された概要候補がそのまま返されます。
  • IllegalPrefixes 変数の追加:
    • var IllegalPrefixes = []string{"copyright", "all rights", "author",}というスライスが定義されました。
    • このスライスには、godocの概要として表示すべきではない、一般的な定型文の小文字のプレフィックスが格納されています。これにより、コードの可読性が向上し、将来的に無視すべきプレフィックスを追加する際も容易になります。

src/pkg/go/doc/synopsis_test.go

  • テストケースの追加:
    • "Copyright 2012 Google, Inc. Package foo does bar."
    • "All Rights reserved. Package foo does bar."
    • "All rights reserved. Package foo does bar."
    • "Authors: foo@bar.com. Package foo does bar." これらのテストケースが追加されました。これらの入力に対して、Synopsis関数が期待通り空文字列""を返すことを検証しています。これにより、新しいロジックが正しく機能していることが保証されます。

これらの変更により、godocはより「賢く」なり、ソースコードの冒頭にある著作権表示や著者情報などの定型文を、パッケージや要素の本来の概要として誤って抽出することを防ぐことができるようになりました。

関連リンク

参考にした情報源リンク