Prechádzať zdrojové kódy

Merge pull request #962 from gin-gonic/feat/func-maps

Made funMaps for the templates configurable and hot-reloadable
Javier Provecho Fernandez 8 rokov pred
rodič
commit
54fe9df889
4 zmenil súbory, kde vykonal 75 pridanie a 12 odobranie
  1. 1 0
      fixtures/basic/raw.tmpl
  2. 12 6
      gin.go
  3. 53 1
      gin_test.go
  4. 9 5
      render/html.go

+ 1 - 0
fixtures/basic/raw.tmpl

@@ -0,0 +1 @@
+Date: {[{.now | formatAsDate}]}

+ 12 - 6
gin.go

@@ -47,6 +47,7 @@ type (
 		RouterGroup
 		delims      render.Delims
 		HTMLRender  render.HTMLRender
+		FuncMap     template.FuncMap
 		allNoRoute  HandlersChain
 		allNoMethod HandlersChain
 		noRoute     HandlersChain
@@ -112,6 +113,7 @@ func New() *Engine {
 			basePath: "/",
 			root:     true,
 		},
+		FuncMap:                template.FuncMap{},
 		RedirectTrailingSlash:  true,
 		RedirectFixedPath:      false,
 		HandleMethodNotAllowed: false,
@@ -147,19 +149,19 @@ func (engine *Engine) Delims(left, right string) *Engine {
 
 func (engine *Engine) LoadHTMLGlob(pattern string) {
 	if IsDebugging() {
-		debugPrintLoadTemplate(template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).ParseGlob(pattern)))
-		engine.HTMLRender = render.HTMLDebug{Glob: pattern, Delims: engine.delims}
+		debugPrintLoadTemplate(template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseGlob(pattern)))
+		engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims}
 	} else {
-		templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).ParseGlob(pattern))
+		templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseGlob(pattern))
 		engine.SetHTMLTemplate(templ)
 	}
 }
 
 func (engine *Engine) LoadHTMLFiles(files ...string) {
 	if IsDebugging() {
-		engine.HTMLRender = render.HTMLDebug{Files: files, Delims: engine.delims}
+		engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims}
 	} else {
-		templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).ParseFiles(files...))
+		templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseFiles(files...))
 		engine.SetHTMLTemplate(templ)
 	}
 }
@@ -169,7 +171,11 @@ func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
 		debugPrintWARNINGSetHTMLTemplate()
 	}
 
-	engine.HTMLRender = render.HTMLProduction{Template: templ}
+	engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)}
+}
+
+func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
+	engine.FuncMap = funcMap
 }
 
 // NoRoute adds handlers for NoRoute. It return a 404 code by default.

+ 53 - 1
gin_test.go

@@ -6,6 +6,7 @@ package gin
 
 import (
 	"fmt"
+	"html/template"
 	"io/ioutil"
 	"net/http"
 	"reflect"
@@ -15,14 +16,28 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func formatAsDate(t time.Time) string {
+	year, month, day := t.Date()
+	return fmt.Sprintf("%d/%02d/%02d", year, month, day)
+}
+
 func setupHTMLFiles(t *testing.T) func() {
 	go func() {
+		SetMode(TestMode)
 		router := New()
 		router.Delims("{[{", "}]}")
-		router.LoadHTMLFiles("./fixtures/basic/hello.tmpl")
+		router.SetFuncMap(template.FuncMap{
+			"formatAsDate": formatAsDate,
+		})
+		router.LoadHTMLFiles("./fixtures/basic/hello.tmpl", "./fixtures/basic/raw.tmpl")
 		router.GET("/test", func(c *Context) {
 			c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
 		})
+		router.GET("/raw", func(c *Context) {
+			c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
+				"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
+			})
+		})
 		router.Run(":8888")
 	}()
 	t.Log("waiting 1 second for server startup")
@@ -32,12 +47,21 @@ func setupHTMLFiles(t *testing.T) func() {
 
 func setupHTMLGlob(t *testing.T) func() {
 	go func() {
+		SetMode(DebugMode)
 		router := New()
 		router.Delims("{[{", "}]}")
+		router.SetFuncMap(template.FuncMap{
+			"formatAsDate": formatAsDate,
+		})
 		router.LoadHTMLGlob("./fixtures/basic/*")
 		router.GET("/test", func(c *Context) {
 			c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"})
 		})
+		router.GET("/raw", func(c *Context) {
+			c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
+				"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
+			})
+		})
 		router.Run(":8888")
 	}()
 	t.Log("waiting 1 second for server startup")
@@ -59,6 +83,20 @@ func TestLoadHTMLGlob(t *testing.T) {
 	td()
 }
 
+func TestLoadHTMLGlobFromFuncMap(t *testing.T) {
+	time.Now()
+	td := setupHTMLGlob(t)
+	res, err := http.Get("http://127.0.0.1:8888/raw")
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	resp, _ := ioutil.ReadAll(res.Body)
+	assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))
+
+	td()
+}
+
 // func (engine *Engine) LoadHTMLFiles(files ...string) {
 // func (engine *Engine) RunTLS(addr string, cert string, key string) error {
 
@@ -100,6 +138,20 @@ func TestLoadHTMLFiles(t *testing.T) {
 	td()
 }
 
+func TestLoadHTMLFilesFuncMap(t *testing.T) {
+	time.Now()
+	td := setupHTMLFiles(t)
+	res, err := http.Get("http://127.0.0.1:8888/raw")
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	resp, _ := ioutil.ReadAll(res.Body)
+	assert.Equal(t, "Date: 2017/07/01\n", string(resp[:]))
+
+	td()
+}
+
 func TestLoadHTMLReleaseMode(t *testing.T) {
 
 }

+ 9 - 5
render/html.go

@@ -25,9 +25,10 @@ type (
 	}
 
 	HTMLDebug struct {
-		Files  []string
-		Glob   string
-		Delims Delims
+		Files   []string
+		Glob    string
+		Delims  Delims
+		FuncMap template.FuncMap
 	}
 
 	HTML struct {
@@ -55,11 +56,14 @@ func (r HTMLDebug) Instance(name string, data interface{}) Render {
 	}
 }
 func (r HTMLDebug) loadTemplate() *template.Template {
+	if r.FuncMap == nil {
+		r.FuncMap = template.FuncMap{}
+	}
 	if len(r.Files) > 0 {
-		return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).ParseFiles(r.Files...))
+		return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseFiles(r.Files...))
 	}
 	if len(r.Glob) > 0 {
-		return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).ParseGlob(r.Glob))
+		return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseGlob(r.Glob))
 	}
 	panic("the HTML debug render was created without files or glob pattern")
 }