write ahead log

ロールフォワード用

html/templateでカスタム関数を追加する

golangのテンプレートエンジン(html/template)ではデフォルトで組み込み関数が用意されていますが, 物足りない場合は自作する事になります.

考え方

基本は以下です.

  • template.FuncMapを作る(関数名と関数のmap)
  • このmapをテンプレートのFuncs関数に渡して登録する

FuncMapに登録する関数は以下の規約があるようです.

  • 引数はいくつでもOK
  • 戻り値は1つだけ
  • ただし2つ目がerrorなら戻り値2つもOK

2つ目の戻り値errorがnilでなければ処理は中断し, Execute関数はtemplate.ExecErrorを返します.

サンプルコード

実用的とは言えない例ですが.

package main

import (
    "fmt"
    "html/template"
    "net/http"
    "time"
)

// 年-月-日にフォーマット
func formatDate(t time.Time) string {
    layout := "2006-01-02"
    return t.Format(layout)
}

// 引数の文字列を頭文字を大文字にして連結して返す.
// 合計文字数が15バイトを超えたらエラーにする
func CatAndUpper(args ...string) (string, error) {
    ret := ""
    for _, s := range args {
        ret += s
    }
    if len(ret) >= 15 {
        return "", fmt.Errorf("too long string")
    }
    return ret, nil
}

// 頭に$を付けるだけ
func formatDollar(c int) string {
    return fmt.Sprintf("$%d", c)
}

func testHandler(w http.ResponseWriter, r *http.Request) {
    // カスタム関数を登録
    fm := template.FuncMap{
        "fdate":   formatDate,
        "fdollar": formatDollar,
        "cat":     CatAndUpper,
    }
    t := template.New("tmpl.html").Funcs(fm)
    t, _ = t.ParseFiles("tmpl.html")

    // 流し込む適当なデータ
    data := &struct {
        Date   time.Time
        Dollar int
    }{}
    data.Date = time.Now()
    data.Dollar = 100

    // テンプレート実行
    fmt.Println(t.Execute(w, data))
}

func main() {
    http.HandleFunc("/", testHandler)
    http.ListenAndServe(":8080", nil)
}

サンプルテンプレート

<html>
    <head>
   </head>
    <body>
        <div>日付: {{fdate .Date}}</div>
        <div>ドル: {{fdollar .Dollar}}</div>
        <div>つなげる: {{cat "string" "string2"}}</div>
        <div>長いのつなげる: {{cat "string" "string2" "string3"}}</div>
    </body>
</html>

生成されるHTML

途中でエラーを返しているので途中まで生成して止まっています.

<html>
    <head>
   </head>
    <body>
        <div>日付: 2017-09-19</div>
        <div>ドル: $100</div>
        <div>つなげる: stringstring2</div>
        <div>長いのつなげる: 

コンソール

テンプレート内でエラーを起こしたのでExecuteメソッドのエラーが帰ってきています.

今回はfmt.Printlnで標準出力へ出してみました.

$ ./sample.exe
template: tmpl.html:8:32: executing "tmpl.html" at <cat "string" "string...>: error calling cat: too long string