Windows10で.
- IMEバー右クリック
- プロパティを開く
- Microsoft IMEの設定画面で詳細設定ボタンクリック
- 全般タブ
- 編集操作 => キー設定の変更ボタンをクリック
- GridViewのCtrl+SpaceにIME-オン/オフを設定
Windows10で.
テンプレートが定義済みの場合と未定義の場合で処理を分けられる.
割と便利そう.
とりあえずコードを置いておく.
{{define "layout"}} <html> <head></head> <div> {{block "contents" .}} not found {{end}} </div> </html> {{end}}
{{define "contents"}} <h1>contents</h1> {{end}}
package main import ( "html/template" "os" ) func main() { if len(os.Args) > 1 && os.Args[1] == "no" { t, _ := template.ParseFiles("layout.html") t.ExecuteTemplate(os.Stdout, "layout", nil) } else { t, _ := template.ParseFiles("layout.html", "contents.html") t.ExecuteTemplate(os.Stdout, "layout", nil) } }
外部テンプレートを使う場合.
$ ./sample.exe <html> <head></head> <div> <h1>contents</h1> </div> </html>
blockアクションで表示.
<html> <head></head> <div> not found </div> </html>
golangのテンプレートエンジン(html/template)ではデフォルトで組み込み関数が用意されていますが, 物足りない場合は自作する事になります.
基本は以下です.
FuncMapに登録する関数は以下の規約があるようです.
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> <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
以前, templateパッケージを利用する方法を調べたけど, 構成的な意味でもうちょっと実用的な例が欲しいので書き残しました.
コードはgithubに置いておきます.
https://github.com/twinbird/go-template-samplegithub.com
ブログシステムを考えてみます.
一般に2種類のページ枠があるでしょう.
もう少し具体的に以下のページを考えます.
一般公開ページと管理者ページではメニューが異なるという事にします.
挙げるとキリがないのでこの辺で.
長いですが, メモなのでそれぞれ全部載せます.
テンプレートは全体的に適当です.
$ tree . . ├── main.go └── templates ├── admin_menu.html # 管理者用メニュー(define "menu") ├── entry_editor.html # 記事エディタ(define "contents") ├── entry_view.html # 記事ビュワー(define "contents") ├── layout.html # 共通レイアウト(define "layout") └── public_menu.html # 公開用メニュー(define "menu") 1 directory, 6 files
layout.html
ここでdefine "layout"としています.
{{define "layout"}} <!DOCTYPE html> <html> <head> <title>{{.Title}}</title> <meta charset="utf-8"> </head> <body> <div class="menu"> {{template "menu" .}} </div> <div class="container"> {{template "contents" .}} </div> </body> </html> {{end}}
admin_menu.html
ここと公開用メニューでdefine "menu"としています.
{{define "menu"}} <!-- Admin menu --> <ul> <li><a href="">New Entry</a></li> <li><a href="">Edit Entry</a></li> </ul> {{end}}
public_menu.html
{{define "menu"}} <!-- Public menu --> <ul> <li><a href="">About me</a></li> <li><a href="">Latest Entry</a></li> </ul> {{end}}
以下2つはdefine "contents"です.
entry_editor.html
{{define "contents"}} <textarea>{{.Entry.Text}}</textarea> {{end}}
entry_view.html
{{define "contents"}} <pre> {{.Entry.Text}} </pre> {{end}}
package main import ( "fmt" "html/template" "net/http" ) // RenderData はテンプレートへ引き渡す表示用のデータです type RenderData struct { Title string Entry *Entry } // Entry は1記事に相当します type Entry struct { Text string } var ( // サンプルデータ sampleEntry *Entry = &Entry{Text: "This is a sample entry"} sampleData *RenderData = &RenderData{Title: "sample", Entry: sampleEntry} // テンプレートディレクトリ templatesDir string = "templates" ) func main() { // admin:編集ページ http.HandleFunc("/admin/edit/someEntry", editAdminSomeEntry) // admin:参照ページ http.HandleFunc("/admin/refer/someEntry", referAdminSomeEntry) // public:参照ページ http.HandleFunc("/refer/someEntry", referSomeEntry) http.ListenAndServe(":8080", nil) } // admin用:編集ページ func editAdminSomeEntry(w http.ResponseWriter, r *http.Request) { execTemplate(w, sampleData, "layout", "admin_menu", "entry_editor") } // admin用:参照ページ func referAdminSomeEntry(w http.ResponseWriter, r *http.Request) { execTemplate(w, sampleData, "layout", "admin_menu", "entry_view") } // public用:参照ページ func referSomeEntry(w http.ResponseWriter, r *http.Request) { execTemplate(w, sampleData, "layout", "public_menu", "entry_view") } // execTemplate はfilesのテンプレートからHTMLを構築して, // wに対して書き込みます. // HTML構築の際にはdataを利用します. // filesで指定するテンプレートには必ず{{define "layout"}}された // ものを1つだけ含む必要があります. func execTemplate(w http.ResponseWriter, data interface{}, files ...string) { // 渡された引数からテンプレートパスの集合を作る var pathes []string for _, f := range files { p := fmt.Sprintf("%s/%s.html", templatesDir, f) pathes = append(pathes, p) } //上記で作ったパスの一覧を使ってテンプレートを作る template := template.Must(template.ParseFiles(pathes...)) // layoutが必ず基点になるという事にする template.ExecuteTemplate(w, "layout", data) }
init時に全てのテンプレートをParseしてmapなどに保存しておくことが出来るはずです.
今回のexecTemplate関数をmapからテンプレートを取得し, パッケージ標準のExecuteTemplateを呼び出す仕組みに変えるだけで高速化もできそうです.
(どの程度早くなるかはわかりませんが)
vimには標準プラグインとしてnetrwというファイラが付属している.
あんまり触ってなかったんだけど,ふと思い立って使い方を調べてみた.
コマンド | 機能 |
---|---|
:Ex | カレントバッファでnetrwを開く |
:Tex | タブを開いてnetrwを開く |
操作 | 機能 |
---|---|
Enter | 選択中のディレクトリを開く |
o | バッファを水平分割して開く |
v | バッファを垂直分割して開く |
t | 新しいタブで開く |
- | 1つ上の階層へ戻る |
u | 以前にいたディレクトリへ戻る |
U | uで戻る前にいたディレクトリへ戻る |
c | 開いているバッファのカレントをvimのカレントに変更 |
操作 | 機能 |
---|---|
Enter | 選択中のファイルを開く |
% | 新規ファイルを作成 |
d | ディレクトリを作成 |
D | カーソル下orマークしたファイル/ディレクトリを削除 |
R | ファイル/ディレクトリをリネーム |
操作 | 機能 |
---|---|
mf | ファイルのマーク/アンマーク |
mu | 全てのアンマーク |
mr | ファイル名指定でのマーク(*でのワイルドカード可) |
mt | コピー/移動先にカーソル下のディレクトリを設定 |
mc | マークしたファイルをコピー |
mm | マークしたファイルを移動 |
md | マークしたファイルを差分を見る |
mz | マークしたファイルを圧縮/展開 |
複雑な操作は手順がややこしいのでメモっておく.
操作 | 機能 |
---|---|
i | 表示を切り替え |
s | 表示をソート |
何度も調べたり考えたりしている気がする...
他にももっといい方法があるのかもしれない.
シェルスクリプト内で引数をsha256化した結果を使いまわしたかった.
コマンドラインで素直に書くとこんな感じ.
echo -n 'pass'| shasum -a 256 | tr -d ' *-'
これをスクリプト内で実行して, 結果を変数に設定したい.
こんな感じになった.
password='pass' hashingCommand="echo -n "$password" | shasum -a 256 | tr -d ' *-'" sha256Password=$(eval $hashingCommand) echo $sha256Password # デバッグ表示
これでいいの?
なんだこれと思いつつ放置していたけど, いい加減不便なので解消した.
メモらないとどうせまた忘れる.
現在のリポジトリのみの場合.
$ git config --local core.quotepath false
ずっと適用したいとき.
$ git config --global core.quotepath false
どうもgitはデフォルトではUTF-8の文字は処理しないらしい.
この業界は英語圏で回っているのだ.