From 82b1942cd041ff7b6bccab5bbf9fc2ef316cd084 Mon Sep 17 00:00:00 2001 From: yosssi Date: Sun, 18 May 2014 00:02:40 +0900 Subject: [PATCH 1/4] Add a feature to serve templates from binary data generated by go-bindata --- render.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ render_test.go | 25 +++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/render.go b/render.go index b932983..2fe51ab 100644 --- a/render.go +++ b/render.go @@ -138,6 +138,17 @@ func Renderer(options ...Options) martini.Handler { } } +// RendererBin is same as Renderer but for loading templates from binary data (assets). +func RendererBin(asset func(string) ([]byte, error), assetNames []string, options ...Options) martini.Handler { + opt := prepareOptions(options) + cs := prepareCharset(opt.Charset) + t := compileBin(asset, assetNames, opt) + return func(res http.ResponseWriter, req *http.Request, c martini.Context) { + // use a clone of the initial template + tc, _ := t.Clone() + c.MapTo(&renderer{res, req, tc, opt, cs}, (*Render)(nil)) + } +} func prepareCharset(charset string) string { if len(charset) != 0 { return "; charset=" + charset @@ -209,6 +220,51 @@ func compile(options Options) *template.Template { return t } +// compileBin is same as compile but for loading templates from binary data (assets). +func compileBin(asset func(string) ([]byte, error), assetNames []string, options Options) *template.Template { + dir := options.Directory + t := template.New(dir) + t.Delims(options.Delims.Left, options.Delims.Right) + // parse an initial template in case we don't have any + template.Must(t.Parse("Martini")) + + for _, path := range assetNames { + if !strings.HasPrefix(path, dir) { + continue + } + + r, err := filepath.Rel(dir, path) + if err != nil { + panic(err) + } + + ext := getExt(r) + + for _, extension := range options.Extensions { + if ext == extension { + + buf, err := asset(path) + if err != nil { + panic(err) + } + + name := (r[0 : len(r)-len(ext)]) + tmpl := t.New(filepath.ToSlash(name)) + + // add our funcmaps + for _, funcs := range options.Funcs { + tmpl.Funcs(funcs) + } + + // Bomb out if parse fails. We don't want any silent server starts. + template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf))) + break + } + } + } + + return t +} func getExt(s string) string { if strings.Index(s, ".") == -1 { return "" diff --git a/render_test.go b/render_test.go index 0ea459c..6ddf596 100644 --- a/render_test.go +++ b/render_test.go @@ -56,7 +56,7 @@ func Test_Render_JSON_Prefix(t *testing.T) { expect(t, res.Code, 300) expect(t, res.Header().Get(ContentType), ContentJSON+"; charset=UTF-8") - expect(t, res.Body.String(), prefix + `{"one":"hello","two":"world"}`) + expect(t, res.Body.String(), prefix+`{"one":"hello","two":"world"}`) } func Test_Render_Indented_JSON(t *testing.T) { @@ -124,6 +124,29 @@ func Test_Render_HTML(t *testing.T) { expect(t, res.Body.String(), "

Hello jeremy

\n") } +func Test_Render_HTML_From_Binary_Data(t *testing.T) { + m := martini.Classic() + m.Use(RendererBin( + func(name string) ([]byte, error) { + return []byte("test"), nil + }, + []string{"templates/index.tmpl"}, + )) + + // routing + m.Get("/foobar", func(r Render) { + r.HTML(200, "index", nil) + }) + + res := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/foobar", nil) + + m.ServeHTTP(res, req) + + expect(t, res.Code, 200) + expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8") + expect(t, res.Body.String(), "test") +} func Test_Render_XHTML(t *testing.T) { m := martini.Classic() m.Use(Renderer(Options{ From 26f5d30ec4be5be6b7e0fb783a7d79d83e0b202f Mon Sep 17 00:00:00 2001 From: yosssi Date: Sun, 18 May 2014 00:07:42 +0900 Subject: [PATCH 2/4] Add a new line --- render.go | 1 + 1 file changed, 1 insertion(+) diff --git a/render.go b/render.go index 2fe51ab..d7390de 100644 --- a/render.go +++ b/render.go @@ -265,6 +265,7 @@ func compileBin(asset func(string) ([]byte, error), assetNames []string, options return t } + func getExt(s string) string { if strings.Index(s, ".") == -1 { return "" From ceb0b53905eab94e17c2613400df555cb00e8de8 Mon Sep 17 00:00:00 2001 From: yosssi Date: Sun, 18 May 2014 00:26:10 +0900 Subject: [PATCH 3/4] Add a new line --- render.go | 1 + 1 file changed, 1 insertion(+) diff --git a/render.go b/render.go index d7390de..5702abf 100644 --- a/render.go +++ b/render.go @@ -149,6 +149,7 @@ func RendererBin(asset func(string) ([]byte, error), assetNames []string, option c.MapTo(&renderer{res, req, tc, opt, cs}, (*Render)(nil)) } } + func prepareCharset(charset string) string { if len(charset) != 0 { return "; charset=" + charset From 6ea20bca827716099042fce3c58a736f3807bfd5 Mon Sep 17 00:00:00 2001 From: Keiji Yoshida Date: Sun, 18 May 2014 02:22:56 +0900 Subject: [PATCH 4/4] Update README.md --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index e63185e..a66024c 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,34 @@ func main() { ~~~ +### Loading Templates from Binary Data Generated by [go-bindata](https://github.com/jteeuwen/go-bindata) + +You can load templates from binary data generated by [go-bindata](https://github.com/jteeuwen/go-bindata) by invoking the `RendererBin` function instead of the `Renderer` function: + +~~~go +package main + +import ( + "github.com/go-martini/martini" + "github.com/martini-contrib/render" +) + +func main() { + m := martini.Classic() + + // Load html templates from binary data. + m.Use(render.RendererBin(Asset, AssetNames())) + + m.Get("/", func(r render.Render) { + r.HTML(200, "hello", "world") + }) + + m.Run() +} +~~~ + +You have to pass the `Asset` function and the return value of the `AssetNames` function (these functions are generated by go-bindata) to the `RendererBin` function. + ## Authors * [Jeremy Saenz](http://github.com/codegangsta) * [Cory Jacobsen](http://github.com/unrolled)