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

[インデックス 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 パッケージでカスタム関数を定義し、使用する一連のステップを具体的に示しています。

  1. template.FuncMap の作成: funcMap := template.FuncMap{"title": strings.Title} ここでは、"title" という名前で strings.Title 関数を登録しています。テンプレート内で {{title .}} のように呼び出すと、strings.Title が実行されます。

  2. テンプレートの定義: 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 は単語の区切りを適切に処理するため、この例では引用符は単語の一部として扱われず、期待通りの出力が得られます)。
  3. テンプレートの作成、関数マップの登録、解析: tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText) template.New で新しいテンプレートインスタンスを作成し、Funcs(funcMap) メソッドで先ほど定義した funcMap を登録します。その後、Parse(templateText) でテンプレート文字列を解析します。この順序が重要で、カスタム関数はテンプレートが解析される前に登録されている必要があります。

  4. テンプレートの実行: 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: セクションと一致するかどうかが検証されます。これにより、ドキュメントとテストの両方の役割を果たすことができます。

コードの主要な部分は以下の通りです。

  1. package template_test: これは template パッケージの外部にあるテストパッケージであることを示します。これにより、template パッケージをインポートして、その公開されたAPIをテストすることができます。

  2. import ステートメント: log, os, strings, text/template パッケージがインポートされています。

    • log: エラー発生時にログを出力するために使用。
    • os: テンプレートの出力を標準出力に書き込むために使用。
    • strings: カスタム関数として登録される strings.Title 関数を提供。
    • text/template: テンプレートエンジン自体を提供。
  3. 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」のベストプラクティスに従っています。

関連リンク

参考にした情報源リンク