Add LoadHTMLGlobAppend and LoadHTMLFilesAppend to gin.Engine

Load new html templates to the exists HTMLRender.
This method won't create a new template instance.
So we can load templates from different path and use
golang template `define` tag to give the templates
proper name. Golang's `filepath.Glob` doesn't
support glob dir recursively. This method may be
helpful.

May be related with #1296.
This commit is contained in:
Ganlv 2019-04-23 22:38:14 +08:00
parent ffcbe77b1e
commit 7164a53b54
5 changed files with 172 additions and 13 deletions

52
gin.go
View File

@ -180,7 +180,7 @@ func (engine *Engine) LoadHTMLGlob(pattern string) {
if IsDebugging() { if IsDebugging() {
debugPrintLoadTemplate(templ) debugPrintLoadTemplate(templ)
engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims} engine.HTMLRender = &render.HTMLDebug{Globs: []string{pattern}, FuncMap: engine.FuncMap, Delims: engine.delims}
return return
} }
@ -191,7 +191,7 @@ func (engine *Engine) LoadHTMLGlob(pattern string) {
// and associates the result with HTML renderer. // and associates the result with HTML renderer.
func (engine *Engine) LoadHTMLFiles(files ...string) { func (engine *Engine) LoadHTMLFiles(files ...string) {
if IsDebugging() { if IsDebugging() {
engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims} engine.HTMLRender = &render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims}
return return
} }
@ -199,13 +199,59 @@ func (engine *Engine) LoadHTMLFiles(files ...string) {
engine.SetHTMLTemplate(templ) engine.SetHTMLTemplate(templ)
} }
// loadHTMLGlobAppend loads HTML files identified by a glob pattern
// and append the result to HTML renderer.
// loadHTMLGlobAppend will merge new files with previous template files.
// LoadHTMLGlob will forget old templates and create a new template object.
func (engine *Engine) loadHTMLGlobAppend(pattern string) {
if engine.HTMLRender == nil {
engine.LoadHTMLGlob(pattern)
return
}
if IsDebugging() {
left := engine.delims.Left
right := engine.delims.Right
templ := template.Must(template.New("").Delims(left, right).Funcs(engine.FuncMap).ParseGlob(pattern))
debugPrintLoadTemplate(templ)
}
engine.HTMLRender.ParseGlob(pattern)
}
// LoadHTMLGlobAppend loads HTML files identified by glob patterns
// and append each result to HTML renderer.
// LoadHTMLGlobAppend will merge new files with previous template files.
// LoadHTMLGlob will forget old templates and create a new template object.
func (engine *Engine) LoadHTMLGlobAppend(patterns ...string) {
if len(patterns) <= 0 {
panic("LoadHTMLGlobAppend must have at least 1 arguments")
}
for _, pattern := range patterns {
engine.loadHTMLGlobAppend(pattern)
}
}
// LoadHTMLFiles loads a slice of HTML files
// and append the result to HTML renderer.
// LoadHTMLFilesAppend will merge new files with previous template files.
// LoadHTMLFiles will forget old templates and create a new template object.
func (engine *Engine) LoadHTMLFilesAppend(files ...string) {
if engine.HTMLRender == nil {
engine.LoadHTMLFiles(files...)
return
}
engine.HTMLRender.ParseFiles(files...)
}
// SetHTMLTemplate associate a template with HTML renderer. // SetHTMLTemplate associate a template with HTML renderer.
func (engine *Engine) SetHTMLTemplate(templ *template.Template) { func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
if len(engine.trees) > 0 { if len(engine.trees) > 0 {
debugPrintWARNINGSetHTMLTemplate() debugPrintWARNINGSetHTMLTemplate()
} }
engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)} engine.HTMLRender = &render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)}
} }
// SetFuncMap sets the FuncMap used for template.FuncMap. // SetFuncMap sets the FuncMap used for template.FuncMap.

View File

@ -118,6 +118,48 @@ func TestLoadHTMLGlobReleaseMode(t *testing.T) {
assert.Equal(t, "<h1>Hello world</h1>", string(resp)) assert.Equal(t, "<h1>Hello world</h1>", string(resp))
} }
func TestLoadHTMLGlobAppendDebugMode(t *testing.T) {
ts := setupHTMLFiles(
t,
DebugMode,
false,
func(router *Engine) {
router.LoadHTMLGlobAppend("./testdata/template/hello*")
router.LoadHTMLGlobAppend("./testdata/template/raw*")
},
)
defer ts.Close()
res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
if err != nil {
fmt.Println(err)
}
resp, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
}
func TestLoadHTMLGlobAppendReleaseMode(t *testing.T) {
ts := setupHTMLFiles(
t,
ReleaseMode,
false,
func(router *Engine) {
router.LoadHTMLGlobAppend("./testdata/template/hello*")
router.LoadHTMLGlobAppend("./testdata/template/raw*")
},
)
defer ts.Close()
res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
if err != nil {
fmt.Println(err)
}
resp, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
}
func TestLoadHTMLGlobUsingTLS(t *testing.T) { func TestLoadHTMLGlobUsingTLS(t *testing.T) {
ts := setupHTMLFiles( ts := setupHTMLFiles(
t, t,
@ -236,6 +278,48 @@ func TestLoadHTMLFilesReleaseMode(t *testing.T) {
assert.Equal(t, "<h1>Hello world</h1>", string(resp)) assert.Equal(t, "<h1>Hello world</h1>", string(resp))
} }
func TestLoadHTMLFilesAppendDebugMode(t *testing.T) {
ts := setupHTMLFiles(
t,
DebugMode,
false,
func(router *Engine) {
router.LoadHTMLFilesAppend("./testdata/template/raw.tmpl")
router.LoadHTMLFilesAppend("./testdata/template/hello.tmpl")
},
)
defer ts.Close()
res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
if err != nil {
fmt.Println(err)
}
resp, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
}
func TestLoadHTMLFilesAppendReleaseMode(t *testing.T) {
ts := setupHTMLFiles(
t,
ReleaseMode,
false,
func(router *Engine) {
router.LoadHTMLFilesAppend("./testdata/template/raw.tmpl")
router.LoadHTMLFilesAppend("./testdata/template/hello.tmpl")
},
)
defer ts.Close()
res, err := http.Get(fmt.Sprintf("%s/test", ts.URL))
if err != nil {
fmt.Println(err)
}
resp, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, "<h1>Hello world</h1>", string(resp))
}
func TestLoadHTMLFilesUsingTLS(t *testing.T) { func TestLoadHTMLFilesUsingTLS(t *testing.T) {
ts := setupHTMLFiles( ts := setupHTMLFiles(
t, t,

View File

@ -21,6 +21,10 @@ type Delims struct {
type HTMLRender interface { type HTMLRender interface {
// Instance returns an HTML instance. // Instance returns an HTML instance.
Instance(string, interface{}) Render Instance(string, interface{}) Render
// Add new template files to this instance with glob
ParseGlob(pattern string)
// Add new template files to this instance
ParseFiles(files ...string)
} }
// HTMLProduction contains template reference and its delims. // HTMLProduction contains template reference and its delims.
@ -32,7 +36,7 @@ type HTMLProduction struct {
// HTMLDebug contains template delims and pattern and function with file list. // HTMLDebug contains template delims and pattern and function with file list.
type HTMLDebug struct { type HTMLDebug struct {
Files []string Files []string
Glob string Globs []string
Delims Delims Delims Delims
FuncMap template.FuncMap FuncMap template.FuncMap
} }
@ -55,6 +59,16 @@ func (r HTMLProduction) Instance(name string, data interface{}) Render {
} }
} }
// Add new template files to this instance (HTMLProduction) with glob
func (r *HTMLProduction) ParseGlob(pattern string) {
template.Must(r.Template.ParseGlob(pattern))
}
// Add new template files to this instance (HTMLProduction) with glob
func (r *HTMLProduction) ParseFiles(files ...string) {
template.Must(r.Template.ParseFiles(files...))
}
// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface. // Instance (HTMLDebug) returns an HTML instance which it realizes Render interface.
func (r HTMLDebug) Instance(name string, data interface{}) Render { func (r HTMLDebug) Instance(name string, data interface{}) Render {
return HTML{ return HTML{
@ -63,17 +77,32 @@ func (r HTMLDebug) Instance(name string, data interface{}) Render {
Data: data, Data: data,
} }
} }
// Add new template files to this instance (HTMLProduction) with glob
func (r *HTMLDebug) ParseGlob(pattern string) {
r.Globs = append(r.Globs, pattern)
}
// Add new template files to this instance (HTMLDebug) with glob
func (r *HTMLDebug) ParseFiles(files ...string) {
r.Files = append(r.Files, files...)
}
func (r HTMLDebug) loadTemplate() *template.Template { func (r HTMLDebug) loadTemplate() *template.Template {
if r.FuncMap == nil { if r.FuncMap == nil {
r.FuncMap = template.FuncMap{} r.FuncMap = template.FuncMap{}
} }
if len(r.Files) > 0 { if len(r.Files) == 0 && len(r.Globs) == 0 {
return template.Must(template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap).ParseFiles(r.Files...))
}
if 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") panic("the HTML debug render was created without files or glob pattern")
}
t := template.New("").Delims(r.Delims.Left, r.Delims.Right).Funcs(r.FuncMap)
if len(r.Files) > 0 {
template.Must(t.ParseFiles(r.Files...))
}
for _, glob := range r.Globs {
template.Must(t.ParseGlob(glob))
}
return t
} }
// Render (HTML) executes template and writes its result with custom ContentType for response. // Render (HTML) executes template and writes its result with custom ContentType for response.

View File

@ -24,8 +24,8 @@ var (
_ Render = Redirect{} _ Render = Redirect{}
_ Render = Data{} _ Render = Data{}
_ Render = HTML{} _ Render = HTML{}
_ HTMLRender = HTMLDebug{} _ HTMLRender = &HTMLDebug{}
_ HTMLRender = HTMLProduction{} _ HTMLRender = &HTMLProduction{}
_ Render = YAML{} _ Render = YAML{}
_ Render = MsgPack{} _ Render = MsgPack{}
_ Render = Reader{} _ Render = Reader{}

View File

@ -422,7 +422,7 @@ func TestRenderHTMLTemplateEmptyName(t *testing.T) {
func TestRenderHTMLDebugFiles(t *testing.T) { func TestRenderHTMLDebugFiles(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
htmlRender := HTMLDebug{Files: []string{"../testdata/template/hello.tmpl"}, htmlRender := HTMLDebug{Files: []string{"../testdata/template/hello.tmpl"},
Glob: "", Globs: []string{},
Delims: Delims{Left: "{[{", Right: "}]}"}, Delims: Delims{Left: "{[{", Right: "}]}"},
FuncMap: nil, FuncMap: nil,
} }
@ -440,7 +440,7 @@ func TestRenderHTMLDebugFiles(t *testing.T) {
func TestRenderHTMLDebugGlob(t *testing.T) { func TestRenderHTMLDebugGlob(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
htmlRender := HTMLDebug{Files: nil, htmlRender := HTMLDebug{Files: nil,
Glob: "../testdata/template/hello*", Globs: []string{"../testdata/template/hello*"},
Delims: Delims{Left: "{[{", Right: "}]}"}, Delims: Delims{Left: "{[{", Right: "}]}"},
FuncMap: nil, FuncMap: nil,
} }
@ -457,7 +457,7 @@ func TestRenderHTMLDebugGlob(t *testing.T) {
func TestRenderHTMLDebugPanics(t *testing.T) { func TestRenderHTMLDebugPanics(t *testing.T) {
htmlRender := HTMLDebug{Files: nil, htmlRender := HTMLDebug{Files: nil,
Glob: "", Globs: []string{},
Delims: Delims{"{{", "}}"}, Delims: Delims{"{{", "}}"},
FuncMap: nil, FuncMap: nil,
} }