Skip to content

Commit

Permalink
fix gtemplate
Browse files Browse the repository at this point in the history
  • Loading branch information
snail007 committed Jan 8, 2024
1 parent 3856983 commit 0771ee6
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 5 deletions.
92 changes: 92 additions & 0 deletions http/template/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package gtemplate

import (
"errors"
ghash "github.com/snail007/gmc/util/hash"
"sync"
)

var DefaultRender = NewRender()

type Render struct {
tplCache map[string]*Template
tplLock sync.Mutex
funcMap map[string]interface{}
leftDelims,
rightDelims string
}

func NewRender() *Render {
return &Render{
tplCache: map[string]*Template{},
funcMap: map[string]interface{}{},
}
}

func (s *Render) clearTemplateCache() {
s.tplLock.Lock()
defer s.tplLock.Unlock()
s.tplCache = map[string]*Template{}
}

func (s *Render) Delims(left, right string) *Render {
s.clearTemplateCache()
s.leftDelims = left
s.rightDelims = right
return s
}

func (s *Render) AddFuncMap(m map[string]interface{}) *Render {
if len(m) == 0 {
return s
}
s.clearTemplateCache()
for k, v := range m {
s.funcMap[k] = v
}
return s
}

func (s *Render) getTemplate(tplBytes []byte) (*Template, error) {
s.tplLock.Lock()
defer s.tplLock.Unlock()
id := ghash.Md5Bytes(tplBytes)
if t, ok := s.tplCache[id]; ok {
return t, nil
}
t := New()
t.SetCtx(ctx)
t.DdisableLogging()
t.DisableLoadDefaultBinData()
t.SetBinBytes(map[string][]byte{"tpl": tplBytes})
if s.leftDelims != "" && s.rightDelims != "" {
t.Delims(s.leftDelims, s.rightDelims)
}
if len(s.funcMap) > 0 {
t.Funcs(s.funcMap)
}
err := t.Parse()
if err != nil {
return nil, err
}
s.tplCache[id] = t
return t, nil
}

// Parse the template, tplBytesOrString is []byte or string template
func (s *Render) Parse(tplBytesOrString interface{}, tplData map[string]interface{}) (d []byte, err error) {
var b []byte
switch v := tplBytesOrString.(type) {
case []byte:
b = v
case string:
b = []byte(v)
default:
return nil, errors.New("wrong type of tpl data")
}
t, err := s.getTemplate(b)
if err != nil {
return
}
return t.Execute("tpl", tplData)
}
76 changes: 76 additions & 0 deletions http/template/render_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package gtemplate

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestRender_Parse(t *testing.T) {
// 创建一个 Render 实例
renderer := NewRender()

// 定义模板内容
tplContent := `Hello, {{.Name}}!`

// 定义模板数据
tplData := map[string]interface{}{
"Name": "World",
}

// 调用 Parse 方法解析模板
result, err := renderer.Parse([]byte(tplContent), tplData)
if err != nil {
t.Fatalf("Error parsing template: %v", err)
}

// 验证结果是否符合预期
expectedResult := "Hello, World!"
if string(result) != expectedResult {
t.Errorf("Expected result: %s, but got: %s", expectedResult, result)
}

// 测试 Delims 方法
renderer.Delims("[[", "]]")
result, err = renderer.Parse([]byte(`Hello, [[.Name]]!`), tplData)
if err != nil {
t.Fatalf("Error parsing template with custom delimiters: %v", err)
}

expectedResult = "Hello, World!"
if string(result) != expectedResult {
t.Errorf("Expected result with custom delimiters: %s, but got: %s", expectedResult, result)
}
renderer.Delims("{{", "}}")

// 测试 AddFuncMap 方法
funcMap := map[string]interface{}{
"Double": func(s string) string {
return s + s
},
}
renderer.AddFuncMap(funcMap)
result, err = renderer.Parse(`Doubled: {{Double .Name}}`, tplData)
if err != nil {
t.Fatalf("Error parsing template with added function: %v", err)
}

expectedResult = "Doubled: WorldWorld"
if string(result) != expectedResult {
t.Errorf("Expected result with added function: %s, but got: %s", expectedResult, result)
}

_, err = renderer.Parse(`Doubled: {{Double .Name}}`, tplData)
assert.Nil(t, err)

_, err = renderer.Parse(123, nil)
assert.NotNil(t, err)

_, err = renderer.Parse(`{{none .Name}}`, nil)
assert.NotNil(t, err)

_, err = renderer.Parse(`{{none .Name}`, nil)
assert.NotNil(t, err)

renderer.AddFuncMap(nil)
assert.NotEmpty(t, renderer.funcMap)
}
21 changes: 16 additions & 5 deletions http/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package gtemplate
import (
"bytes"
"encoding/base64"
"fmt"
gcore "github.com/snail007/gmc/core"
"io/ioutil"
"os"
Expand Down Expand Up @@ -53,6 +52,7 @@ type Template struct {
binData map[string][]byte
disableLoadDefaultBinData bool
disableLogging bool
left, right string
}

func (s *Template) DisableLoadDefaultBinData() {
Expand Down Expand Up @@ -98,6 +98,8 @@ func New() (t *Template) {
tpl: tpl,
ext: ".html",
binData: map[string][]byte{},
left: "{{",
right: "}}",
}
return
}
Expand All @@ -120,6 +122,8 @@ func NewTemplate(ctx gcore.Ctx, rootDir string) (t *Template, err error) {
ext: ".html",
ctx: ctx,
binData: map[string][]byte{},
left: "{{",
right: "}}",
}
ctx.SetTemplate(t)
return
Expand All @@ -131,6 +135,7 @@ func NewTemplate(ctx gcore.Ctx, rootDir string) (t *Template, err error) {
// corresponding default: {{ or }}.
// The return value is the template, so calls can be chained.
func (s *Template) Delims(left, right string) {
s.left, s.right = left, right
s.tpl.Delims(left, right)
}

Expand Down Expand Up @@ -199,23 +204,29 @@ func (s *Template) Parse() (err error) {
}
return
}

func (s *Template) wrapDelims(str string) string {
return s.left + str + s.right
}

func (s *Template) parseFromBinData() (err error) {
for k, v := range s.binData {
// template without extension
html := fmt.Sprintf("{{define \"%s\"}}%s{{end}}", k, string(v))
html := s.wrapDelims(`define "`+k+`"`) + string(v) + s.wrapDelims("end")
_, err = s.tpl.Parse(html)
if err != nil {
return
}
// template with extension
html = fmt.Sprintf("{{define \"%s\"}}%s{{end}}", k+s.ext, string(v))
html = s.wrapDelims(`define "`+k+s.ext+`"`) + string(v) + s.wrapDelims("end")
_, err = s.tpl.Parse(html)
if err != nil {
return
}
}
return
}

func (s *Template) parseFromDisk() (err error) {
names := []string{}
err = s.tree(s.rootDir, &names)
Expand All @@ -230,11 +241,11 @@ func (s *Template) parseFromDisk() (err error) {
}

// template without extension
html := fmt.Sprintf("{{define \"%s\"}}%s{{end}}", v, string(b))
html := s.wrapDelims(`define "`+v+`"`) + string(b) + s.wrapDelims("end")
_, err = s.tpl.Parse(html)

// template with extension
html = fmt.Sprintf("{{define \"%s\"}}%s{{end}}", v+s.ext, string(b))
html = s.wrapDelims(`define "`+v+s.ext+`"`) + string(b) + s.wrapDelims("end")
_, err = s.tpl.Parse(html)
if err != nil {
return
Expand Down

0 comments on commit 0771ee6

Please sign in to comment.