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) diff --git a/render.go b/render.go index b932983..5702abf 100644 --- a/render.go +++ b/render.go @@ -138,6 +138,18 @@ 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 +221,52 @@ 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(), "