[インデックス 12251] ファイルの概要
このコミットは、Go言語の標準ライブラリである text/template
パッケージに、カスタム関数を使用する方法を示す新しいテスト例を追加するものです。具体的には、strings.Title
関数をテンプレート内でカスタム関数として登録し、テキストをタイトルケースに変換する例が示されています。
コミット
commit 26c2443d80904d167b1ae062cc02a2a593bdf6c2
Author: Rob Pike <r@golang.org>
Date: Tue Feb 28 15:50:41 2012 +1100
text/template: add example showing use of custom function
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5694100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/26c2443d80904d167b1ae062cc02a2a593bdf6c2
元コミット内容
text/template: add example showing use of custom function
このコミットは、text/template
パッケージにカスタム関数の使用例を追加するものです。
変更の背景
Go言語の text/template
パッケージは、テキストベースの出力を生成するための強力なテンプレートエンジンを提供します。しかし、テンプレート内で利用できる組み込み関数だけでは、すべてのユースケースに対応できない場合があります。このような場合、ユーザーは独自のGo関数をテンプレートに登録し、テンプレート内で呼び出すことができる「カスタム関数」の機能を利用します。
このコミットが作成された背景には、text/template
のカスタム関数の利用方法を開発者により明確に示し、理解を深めるための公式な例が不足していたことが考えられます。新しい ExampleTemplate_func
というテスト関数を追加することで、FuncMap
を使用してGoの関数をテンプレートにどのようにマッピングし、パイプラインでどのように利用するかを具体的に示すことが目的です。これにより、開発者が text/template
をより効果的に活用できるようになります。
前提知識の解説
Go言語の text/template
パッケージ
text/template
パッケージは、Go言語でテキスト出力を生成するためのデータ駆動型テンプレートエンジンです。HTML生成には html/template
パッケージが推奨されますが、text/template
は任意のテキスト形式の生成に利用できます。
主な特徴:
- データ駆動: テンプレートはGoのデータ構造(構造体、マップ、スライスなど)を処理し、そのデータに基づいて出力を生成します。
- アクション: テンプレート内では、データへのアクセス、条件分岐 (
if
)、繰り返し (range
)、変数の定義 (with
)、関数の呼び出しなどの「アクション」を使用できます。アクションは{{...}}
で囲まれます。 - パイプライン: 複数の関数呼び出しを
|
(パイプ) で連結し、前の関数の出力を次の関数の入力として渡すことができます。例:{{.Name | upper | html}}
- カスタム関数: ユーザーはGoの関数をテンプレートに登録し、テンプレート内で呼び出すことができます。これにより、テンプレートの表現力を拡張できます。
template.FuncMap
template.FuncMap
は、string
型のキー(テンプレート内で関数を呼び出す際に使用する名前)と、interface{}
型の値(登録するGoの関数)を持つマップです。Goの関数は、テンプレートエンジンが期待するシグネチャ(引数と戻り値の型)に合致している必要があります。通常、Goの関数は任意の数の引数を取り、最大2つの戻り値(結果とエラー)を返すことができます。
例:
funcMap := template.FuncMap{
"add": func(a, b int) int { return a + b },
"upper": strings.ToUpper,
}
strings.Title
関数
Go言語の標準ライブラリ strings
パッケージに含まれる Title
関数は、文字列をタイトルケースに変換します。タイトルケースとは、各単語の最初の文字を大文字にし、残りを小文字にする形式です。
例:
s := "the go programming language"
titledS := strings.Title(s) // "The Go Programming Language"
この関数は、このコミットの例でカスタム関数としてテンプレートに登録され、その動作が示されています。
技術的詳細
このコミットで追加された ExampleTemplate_func
関数は、text/template
パッケージでカスタム関数を定義し、使用する一連のステップを具体的に示しています。
-
template.FuncMap
の作成:funcMap := template.FuncMap{"title": strings.Title}
ここでは、"title"
という名前でstrings.Title
関数を登録しています。テンプレート内で{{title .}}
のように呼び出すと、strings.Title
が実行されます。 -
テンプレートの定義:
const templateText =
...` このテンプレートは、入力テキストを様々な方法で表示します。Input: {{printf "%q" .}}
: 元の入力テキストを引用符付きで表示。Output 0: {{title .}}
:title
カスタム関数を直接適用。Output 1: {{title . | printf "%q"}}
:title
関数を適用した後、その結果をprintf "%q"
にパイプして引用符付きで表示。Output 2: {{printf "%q" . | title}}
: 入力テキストをprintf "%q"
で引用符付きにした後、その結果をtitle
関数にパイプしてタイトルケースに変換。このケースは、strings.Title
が引用符を含む文字列を処理するため、意図した結果とは異なる可能性があることを示唆しています(実際にはstrings.Title
は単語の区切りを適切に処理するため、この例では引用符は単語の一部として扱われず、期待通りの出力が得られます)。
-
テンプレートの作成、関数マップの登録、解析:
tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
template.New
で新しいテンプレートインスタンスを作成し、Funcs(funcMap)
メソッドで先ほど定義したfuncMap
を登録します。その後、Parse(templateText)
でテンプレート文字列を解析します。この順序が重要で、カスタム関数はテンプレートが解析される前に登録されている必要があります。 -
テンプレートの実行:
err = tmpl.Execute(os.Stdout, "the go programming language")
Execute
メソッドは、テンプレートを標準出力 (os.Stdout
) に書き込み、データとして"the go programming language"
を渡します。このデータがテンプレート内の.
(ドット) で参照されます。
この例は、カスタム関数がテンプレート内でどのように機能し、特にパイプライン処理においてその適用順序が結果にどのように影響するかを明確に示しています。
コアとなるコードの変更箇所
src/pkg/text/template/examplefunc_test.go
が新規追加されています。
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package template_test
import (
"log"
"os"
"strings"
"text/template"
)
// This example demonstrates a custom function to process template text.
// It installs the strings.Title function and uses it to
// Make Title Text Look Good In Our Template's Output.
func ExampleTemplate_func() {
// First we create a FuncMap with which to register the function.
funcMap := template.FuncMap{
// The name "title" is what the function will be called in the template text.
"title": strings.Title,
}
// A simple template definition to test our function.
// We print the input text several ways:
// - the original
// - title-cased
// - title-cased and then printed with %q
// - printed with %q and then title-cased.
const templateText = `
Input: {{printf "%q" .}}
Output 0: {{title .}}
Output 1: {{title . | printf "%q"}}
Output 2: {{printf "%q" . | title}}
`
// Create a template, add the function map, and parse the text.
tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
if err != nil {
log.Fatalf("parsing: %s", err)
}
// Run the template to verify the output.
err = tmpl.Execute(os.Stdout, "the go programming language")
if err != nil {
log.Fatalf("execution: %s", err)
}
// Output:
// Input: "the go programming language"
// Output 0: The Go Programming Language
// Output 1: "The Go Programming Language"
// Output 2: "The Go Programming Language"
}
コアとなるコードの解説
この追加されたファイルは、Goのテストフレームワークにおける「Example関数」です。Example
プレフィックスを持つ関数は、go test
コマンド実行時に自動的にテストとして実行され、その出力がコメントアウトされた Output:
セクションと一致するかどうかが検証されます。これにより、ドキュメントとテストの両方の役割を果たすことができます。
コードの主要な部分は以下の通りです。
-
package template_test
: これはtemplate
パッケージの外部にあるテストパッケージであることを示します。これにより、template
パッケージをインポートして、その公開されたAPIをテストすることができます。 -
import
ステートメント:log
,os
,strings
,text/template
パッケージがインポートされています。log
: エラー発生時にログを出力するために使用。os
: テンプレートの出力を標準出力に書き込むために使用。strings
: カスタム関数として登録されるstrings.Title
関数を提供。text/template
: テンプレートエンジン自体を提供。
-
ExampleTemplate_func()
関数: この関数がカスタム関数の使用例を実装しています。funcMap := template.FuncMap{"title": strings.Title}
:strings.Title
関数をtitle
という名前でテンプレートに登録するためのマップを作成します。const templateText =
...``: テンプレート文字列を定義します。この文字列には、title
カスタム関数が様々なコンテキストでどのように使用されるかを示す複数の行が含まれています。特に、パイプライン (|
) を使用して関数の連鎖を試しています。tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
: 新しいテンプレートを作成し、Funcs
メソッドでfuncMap
を登録してから、Parse
メソッドでテンプレート文字列を解析します。この順序は、カスタム関数がテンプレートの解析時に利用可能であることを保証するために重要です。err = tmpl.Execute(os.Stdout, "the go programming language")
: テンプレートを実行し、結果を標準出力に書き込みます。"the go programming language"
がテンプレートのデータコンテキスト (.
) として渡されます。// Output:
: このコメントブロックは、Example
関数の期待される出力を定義します。go test
はこのセクションと実際のプログラム出力を比較し、一致しない場合はテストを失敗させます。これにより、例が常に正しく動作することが保証されます。
このコードは、text/template
のカスタム関数機能の基本的な使い方を、非常に明確かつ実行可能な形で示しており、Goのドキュメントにおける「Example」のベストプラクティスに従っています。
関連リンク
- Go言語の
text/template
パッケージ公式ドキュメント: https://pkg.go.dev/text/template - Go言語の
strings
パッケージ公式ドキュメント: https://pkg.go.dev/strings - Go言語の
Example
テストに関する公式ドキュメント (Testing Go Code): https://go.dev/doc/tutorial/add-a-test#example-tests
参考にした情報源リンク
- https://github.com/golang/go/commit/26c2443d80904d167b1ae062cc02a2a593bdf6c2
- https://golang.org/cl/5694100 (Go Code Review System の変更リスト)
- Go言語の公式ドキュメント (上記「関連リンク」に記載の各パッケージドキュメント)