「みんなのGo言語」が本日発売となりました。
現在、プログラミング言語のカテゴリで1位の様です。めでたい。
僕も執筆に参加させて頂いたので興味ある方はぜひ読んで欲しいです。
さて最近の僕がGo言語で何を書いていたかというとGitHub - mattn/go-slim: Slim Template Engine for golang
Rslim template engine for golang
https://github.com/mattn/go-slim
slim template の golang 版です。忙しくてまだ完成はしていないんですが、ちょっとした物であれば使えるレベルまで出来ていると思っています。haml を golang で実装している物はいくらかあったのですが、僕は haml よりも slim が好きなので何も迷わず実装しました。
doctype 5
html lang="ja"
head
meta charset="UTF-8"
title
body
ul
- for x in foo
li = x
こんな slim のテンプレートを用意して
tmpl, err := slim.ParseFile("template.slim")
if err != nil {
t.Fatal(err)
}
err = tmpl.Execute(os.Stdout, slim.Values{
"foo": []string{"foo", "bar", "baz"},
})
テンプレートを読み込んで値を渡しながら Execute を呼び出します。すると
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8"/>
<title>
</title>
</head>
<body>
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
</ul>
</body>
</html>
綺麗な HTML が生成されます。slim 内での式にも対応していて for in 文だけでなく
= foo[0] + foo[1].Bar[0]
式も書けるし以下の様なコードに対して
m := make(map[string]string)
m["baz"] = "Baz!"
type Baz struct {
Fuga string
}
var buf bytes.Buffer
err = tmpl.Execute(&buf, Values{
"foo": struct {
Baz []Baz
}{
Baz: []Baz{
{Fuga: "hello"},
{Fuga: "world"},
{Fuga: "golang"},
},
},
"bar": m,
})
構造体や map を参照してテンプレートから扱う事も出来ます。
= bar.baz
- for x in foo.Baz
p = x.Fuga
ruby を内部で実行する代わりに slim 用の専用のインタプリタ言語を作っています。はじめは anko を埋め込もうと思ったのですが高機能すぎるので文法の小さい物にしています。割と綺麗に書けました。おそらくですが他のテンプレートエンジンに使いまわしたり、「プログラミング言語の実装ちょっと興味ある」という方には良い教材になると思います。vm というフォルダだけ持っていけば他のプロダクトにも埋め込められるはずです。
面白いところでは for in 文の右辺に配列だけでなく channel を指定できる様にしてあります。
ch := make(chan string)
go func() {
for _, a := range []string{"foo", "bar", "baz"} {
ch <- a
}
close(ch)
}()
var buf bytes.Buffer
err = tmpl.Execute(&buf, Values{
"foo": ch,
})
こんな風に chan をテンプレートに渡して
ul
- for x in foo
li = x
slim から呼び出すと
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
</ul>
ループを回してくれます。実用的かどうかなんて関係ないです。面白ければいいんです。
まだやりかけというだけあって slim から使える関数は trim, to_upper, to_lower, split 程度しかありませんが、適当に時間を見つけて作って行きたいと思います。