Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
58 changes: 58 additions & 0 deletions render.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 ""
Expand Down
25 changes: 24 additions & 1 deletion render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -124,6 +124,29 @@ func Test_Render_HTML(t *testing.T) {
expect(t, res.Body.String(), "<h1>Hello jeremy</h1>\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{
Expand Down