From 780127d9c7b0dfb74815ee6aa0398fd15784dad0 Mon Sep 17 00:00:00 2001 From: Toby Webb Date: Sat, 29 Aug 2015 23:18:20 +0200 Subject: [PATCH] Implement amber templates --- render.go | 35 +++++++++++++++++++++++++++++++++-- render_test.go | 10 +++++----- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/render.go b/render.go index 0cacb97..9a0da24 100644 --- a/render.go +++ b/render.go @@ -41,7 +41,7 @@ import ( "encoding/xml" "fmt" "html/template" - "io" + "io" "io/ioutil" "net/http" "os" @@ -51,6 +51,8 @@ import ( "github.com/oxtoacart/bpool" "github.com/go-martini/martini" + + "github.com/eknkc/amber" ) const ( @@ -153,17 +155,33 @@ func Renderer(options ...Options) martini.Handler { opt := prepareOptions(options) cs := prepareCharset(opt.Charset) t := compile(opt) + compiledAmberFiles, err := compileAmberFiles(opt) + if err != nil { + panic(err) + } + + // Check no name conflicts between template and amber + for n := range compiledAmberFiles { + found := t.Lookup(n) + if found != nil { + panic(fmt.Errorf("Template name conflict: \"%s\"", n)) + } + } + bufpool = bpool.NewBufferPool(64) return func(res http.ResponseWriter, req *http.Request, c martini.Context) { var tc *template.Template + var at map[string]*template.Template if martini.Env == martini.Dev { // recompile for easy development tc = compile(opt) + at, _ = compileAmberFiles(opt) } else { // use a clone of the initial template tc, _ = t.Clone() + at = compiledAmberFiles } - c.MapTo(&renderer{res, req, tc, opt, cs}, (*Render)(nil)) + c.MapTo(&renderer{res, req, tc, opt, cs, at}, (*Render)(nil)) } } @@ -251,6 +269,7 @@ type renderer struct { t *template.Template opt Options compiledCharset string + amberFiles map[string]*template.Template } func (r *renderer) JSON(status int, v interface{}) { @@ -358,6 +377,9 @@ func (r *renderer) Template() *template.Template { func (r *renderer) execute(name string, binding interface{}) (*bytes.Buffer, error) { buf := bufpool.Get() + if amb, ok := r.amberFiles[name]; ok && amb != nil { + return buf, amb.Execute(buf, binding) + } return buf, r.t.ExecuteTemplate(buf, name, binding) } @@ -384,3 +406,12 @@ func (r *renderer) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { Layout: r.opt.Layout, } } + +func compileAmberFiles(opt Options) (map[string]*template.Template, error) { + ret, err := amber.CompileDir(opt.Directory, amber.DefaultDirOptions, amber.DefaultOptions) + if os.IsNotExist(err) { + return nil, nil + } + + return ret, err +} diff --git a/render_test.go b/render_test.go index 2777177..3558cc7 100644 --- a/render_test.go +++ b/render_test.go @@ -393,21 +393,21 @@ func Test_Render_BinaryData_CustomMimeType(t *testing.T) { func Test_Render_Status204(t *testing.T) { res := httptest.NewRecorder() - r := renderer{res, nil, nil, Options{}, ""} + r := renderer{res, nil, nil, Options{}, "", nil} r.Status(204) expect(t, res.Code, 204) } func Test_Render_Error404(t *testing.T) { res := httptest.NewRecorder() - r := renderer{res, nil, nil, Options{}, ""} + r := renderer{res, nil, nil, Options{}, "", nil} r.Error(404) expect(t, res.Code, 404) } func Test_Render_Error500(t *testing.T) { res := httptest.NewRecorder() - r := renderer{res, nil, nil, Options{}, ""} + r := renderer{res, nil, nil, Options{}, "", nil} r.Error(500) expect(t, res.Code, 500) } @@ -420,7 +420,7 @@ func Test_Render_Redirect_Default(t *testing.T) { } res := httptest.NewRecorder() - r := renderer{res, &req, nil, Options{}, ""} + r := renderer{res, &req, nil, Options{}, "", nil} r.Redirect("two") expect(t, res.Code, 302) @@ -435,7 +435,7 @@ func Test_Render_Redirect_Code(t *testing.T) { } res := httptest.NewRecorder() - r := renderer{res, &req, nil, Options{}, ""} + r := renderer{res, &req, nil, Options{}, "", nil} r.Redirect("two", 307) expect(t, res.Code, 307)