Skip to content

Commit

Permalink
feat(embed): Implement template loading from embedded filesystem (#48)
Browse files Browse the repository at this point in the history
* Implement template loading from fs.FS

* Use os.DirFS instead of embed.FS for tests

* Remove go versions 1.14 and 1.15 from test workflow

---------

Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
  • Loading branch information
bliepp and appleboy committed Mar 29, 2024
1 parent 5bc92fc commit ea49057
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 0 deletions.
12 changes: 12 additions & 0 deletions dynamic.go
Expand Up @@ -3,6 +3,7 @@ package multitemplate
import (
"fmt"
"html/template"
"io/fs"
"path/filepath"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -39,6 +40,7 @@ const (
templateType builderType = iota
filesTemplateType
globTemplateType
fsTemplateType
stringTemplateType
stringFuncTemplateType
filesFuncTemplateType
Expand All @@ -51,6 +53,7 @@ type templateBuilder struct {
templateName string
files []string
glob string
fsys fs.FS
templateString string
funcMap template.FuncMap
templateStrings []string
Expand All @@ -64,6 +67,8 @@ func (tb templateBuilder) buildTemplate() *template.Template {
return template.Must(template.ParseFiles(tb.files...))
case globTemplateType:
return template.Must(template.ParseGlob(tb.glob))
case fsTemplateType:
return template.Must(template.ParseFS(tb.fsys, tb.files...))
case stringTemplateType:
return template.Must(template.New(tb.templateName).Parse(tb.templateString))
case stringFuncTemplateType:
Expand Down Expand Up @@ -108,6 +113,13 @@ func (r DynamicRender) AddFromGlob(name, glob string) *template.Template {
return builder.buildTemplate()
}

func (r DynamicRender) AddFromFS(name string, fsys fs.FS, files ...string) *template.Template {
builder := &templateBuilder{templateName: name, fsys: fsys, files: files}
builder.buildType = fsTemplateType
r[name] = builder
return builder.buildTemplate()
}

// AddFromString supply add template from strings
func (r DynamicRender) AddFromString(name, templateString string) *template.Template {
builder := &templateBuilder{templateName: name, templateString: templateString}
Expand Down
22 changes: 22 additions & 0 deletions dynamic_test.go
Expand Up @@ -2,6 +2,7 @@ package multitemplate

import (
"html/template"
"os"
"testing"

"github.com/gin-gonic/gin"
Expand All @@ -22,6 +23,13 @@ func createFromGlobDynamic() Renderer {
return r
}

func createFromFSDynamic() Render {
r := New()
r.AddFromFS("index", os.DirFS("."), "tests/base.html", "tests/article.html")

return r
}

func createFromStringDynamic() Renderer {
r := NewRenderer()
r.AddFromString("index", "Welcome to {{ .name }} template")
Expand Down Expand Up @@ -90,6 +98,20 @@ func TestAddFromGlobDynamic(t *testing.T) {
assert.Equal(t, "<p>Test Multiple Template</p>\nHi, this is login template\n", w.Body.String())
}

func TestAddFromFSDynamic(t *testing.T) {
router := gin.New()
router.HTMLRender = createFromFSDynamic()
router.GET("/", func(c *gin.Context) {
c.HTML(200, "index", gin.H{
"title": "Test Multiple Template",
})
})

w := performRequest(router, "GET", "/")
assert.Equal(t, 200, w.Code)
assert.Equal(t, "<p>Test Multiple Template</p>\nHi, this is article template\n", w.Body.String())
}

func TestAddFromStringDynamic(t *testing.T) {
router := gin.New()
router.HTMLRender = createFromStringDynamic()
Expand Down
8 changes: 8 additions & 0 deletions multitemplate.go
Expand Up @@ -3,6 +3,7 @@ package multitemplate
import (
"fmt"
"html/template"
"io/fs"
"path/filepath"

"github.com/gin-gonic/gin/render"
Expand Down Expand Up @@ -49,6 +50,13 @@ func (r Render) AddFromGlob(name, glob string) *template.Template {
return tmpl
}

// AddFromFS supply add template from fs.FS (e.g. embed.FS)
func (r Render) AddFromFS(name string, fsys fs.FS, files ...string) *template.Template {
tmpl := template.Must(template.ParseFS(fsys, files...))
r.Add(name, tmpl)
return tmpl
}

// AddFromString supply add template from strings
func (r Render) AddFromString(name, templateString string) *template.Template {
tmpl := template.Must(template.New(name).Parse(templateString))
Expand Down
22 changes: 22 additions & 0 deletions multitemplate_test.go
Expand Up @@ -5,6 +5,7 @@ import (
"html/template"
"net/http"
"net/http/httptest"
"os"
"testing"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -32,6 +33,13 @@ func createFromGlob() Render {
return r
}

func createFromFS() Render {
r := New()
r.AddFromFS("index", os.DirFS("."), "tests/base.html", "tests/article.html")

return r
}

func createFromString() Render {
r := New()
r.AddFromString("index", "Welcome to {{ .name }} template")
Expand Down Expand Up @@ -93,6 +101,20 @@ func TestAddFromGlob(t *testing.T) {
assert.Equal(t, "<p>Test Multiple Template</p>\nHi, this is login template\n", w.Body.String())
}

func TestAddFromFS(t *testing.T) {
router := gin.New()
router.HTMLRender = createFromFS()
router.GET("/", func(c *gin.Context) {
c.HTML(200, "index", gin.H{
"title": "Test Multiple Template",
})
})

w := performRequest(router, "GET", "/")
assert.Equal(t, 200, w.Code)
assert.Equal(t, "<p>Test Multiple Template</p>\nHi, this is article template\n", w.Body.String())
}

func TestAddFromString(t *testing.T) {
router := gin.New()
router.HTMLRender = createFromString()
Expand Down
2 changes: 2 additions & 0 deletions renderer.go
Expand Up @@ -2,6 +2,7 @@ package multitemplate

import (
"html/template"
"io/fs"

"github.com/gin-gonic/gin/render"
)
Expand All @@ -15,6 +16,7 @@ type Renderer interface {
Add(name string, tmpl *template.Template)
AddFromFiles(name string, files ...string) *template.Template
AddFromGlob(name, glob string) *template.Template
AddFromFS(name string, fsys fs.FS, files ...string) *template.Template
AddFromString(name, templateString string) *template.Template
AddFromStringsFuncs(name string, funcMap template.FuncMap, templateStrings ...string) *template.Template
AddFromFilesFuncs(name string, funcMap template.FuncMap, files ...string) *template.Template
Expand Down

0 comments on commit ea49057

Please sign in to comment.