diff --git a/core/template.go b/core/template.go index 3732fbe..6e43619 100644 --- a/core/template.go +++ b/core/template.go @@ -11,23 +11,44 @@ import ( type Renderer struct { multitemplate.Renderer TemplatesBox *packr.Box - FuncMap template.FuncMap + FuncMap template.FuncMap + alreadyAdded map[string]*template.Template } // NewRenderer is a Renderer constructor func NewRenderer(funcMap template.FuncMap) Renderer { + return newRendererWithMultitemplate(funcMap, multitemplate.NewRenderer()) +} + +// NewStaticRenderer is a Renderer constructor with multitemplate.Render +func NewStaticRenderer(funcMap template.FuncMap) Renderer { + return newRendererWithMultitemplate(funcMap, multitemplate.New()) +} + +// NewStaticRenderer is a Renderer constructor with multitemplate.DynamicRender +func NewDynamicRenderer(funcMap template.FuncMap) Renderer { + return newRendererWithMultitemplate(funcMap, multitemplate.NewDynamic()) +} + +// newRendererWithMultitemplate initializes Renderer with provided multitemplate.Renderer instance +func newRendererWithMultitemplate(funcMap template.FuncMap, renderer multitemplate.Renderer) Renderer { return Renderer{ - Renderer: multitemplate.NewRenderer(), - FuncMap: funcMap, + Renderer: renderer, + FuncMap: funcMap, + alreadyAdded: map[string]*template.Template{}, } } // Push is an AddFromFilesFuncs wrapper func (r *Renderer) Push(name string, files ...string) *template.Template { + if tpl := r.getTemplate(name); tpl != nil { + return tpl + } + if r.TemplatesBox == nil { - return r.AddFromFilesFuncs(name, r.FuncMap, files...) + return r.storeTemplate(name, r.AddFromFilesFuncs(name, r.FuncMap, files...)) } else { - return r.addFromBox(name, r.FuncMap, files...) + return r.storeTemplate(name, r.addFromBox(name, r.FuncMap, files...)) } } @@ -42,4 +63,32 @@ func (r *Renderer) addFromBox(name string, funcMap template.FuncMap, files ...st } return r.AddFromStringsFuncs(name, funcMap, filesData...) -} \ No newline at end of file +} + +// storeTemplate stores built template if multitemplate.DynamicRender is used. +// Dynamic render doesn't store templates - it stores builders, that's why we can't just extract them. +// It possibly can cause data inconsistency in developer enviroments where return value from Renderer.Push is used. +func (r *Renderer) storeTemplate(name string, tpl *template.Template) *template.Template { + if _, ok := r.Renderer.(multitemplate.DynamicRender); ok { + r.alreadyAdded[name] = tpl + } + + return tpl +} + +// getTemplate returns template from render or from storage +func (r *Renderer) getTemplate(name string) *template.Template { + if renderer, ok := r.Renderer.(multitemplate.Render); ok { + if i, ok := renderer[name]; ok { + return i + } + } + + if _, ok := r.Renderer.(multitemplate.DynamicRender); ok { + if i, ok := r.alreadyAdded[name]; ok { + return i + } + } + + return nil +} diff --git a/core/template_test.go b/core/template_test.go index c32dec7..21ab439 100644 --- a/core/template_test.go +++ b/core/template_test.go @@ -8,6 +8,7 @@ import ( "path" "testing" + "github.com/gin-contrib/multitemplate" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -20,10 +21,17 @@ var ( type TemplateTest struct { suite.Suite - renderer Renderer + static Renderer + dynamic Renderer } func (t *TemplateTest) SetupSuite() { + t.initTestData() + t.static = t.initStatic() + t.dynamic = t.initDynamic() +} + +func (t *TemplateTest) initTestData() { if _, err := os.Stat(testTemplatesDir); err != nil && os.IsNotExist(err) { err := os.Mkdir(testTemplatesDir, os.ModePerm) require.Nil(t.T(), err) @@ -34,8 +42,22 @@ func (t *TemplateTest) SetupSuite() { require.Nil(t.T(), err1) require.Nil(t.T(), err2) } +} - t.renderer = NewRenderer(template.FuncMap{ +func (t *TemplateTest) initStatic() Renderer { + return NewStaticRenderer(template.FuncMap{ + "trans": func(data string) string { + if data == "test" { + return "ok" + } + + return "fail" + }, + }) +} + +func (t *TemplateTest) initDynamic() Renderer { + return NewDynamicRenderer(template.FuncMap{ "trans": func(data string) string { if data == "test" { return "ok" @@ -47,10 +69,60 @@ func (t *TemplateTest) SetupSuite() { } func (t *TemplateTest) Test_Push() { - tpl := t.renderer.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) + tplStatic := t.static.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) + tplDynamic := t.dynamic.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) + assert.Equal(t.T(), 3, len(tplStatic.Templates())) + assert.Equal(t.T(), 3, len(tplDynamic.Templates())) +} + +func (t *TemplateTest) Test_PushAlreadyExists() { + defer func() { + assert.Nil(t.T(), recover()) + }() + + tplStatic := t.static.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) + tplDynamic := t.dynamic.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) + assert.Equal(t.T(), 3, len(tplStatic.Templates())) + assert.Equal(t.T(), 3, len(tplDynamic.Templates())) +} + +func (t *TemplateTest) Test_PushNewInstanceStatic() { + defer func() { + assert.Nil(t.T(), recover()) + }() + + newInstance := t.initStatic() + tpl := newInstance.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) assert.Equal(t.T(), 3, len(tpl.Templates())) } +func (t *TemplateTest) Test_PushNewInstanceDynamic() { + defer func() { + assert.Nil(t.T(), recover()) + }() + + newInstance := t.initDynamic() + tpl := newInstance.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) + assert.Equal(t.T(), 3, len(tpl.Templates())) +} + +func TestTemplate_NewRenderer(t *testing.T) { + r := NewRenderer(template.FuncMap{}) + assert.NotNil(t, r) +} + +func TestTemplate_NewStaticRenderer(t *testing.T) { + r := NewStaticRenderer(template.FuncMap{}) + assert.NotNil(t, r) + assert.IsType(t, multitemplate.New(), r.Renderer) +} + +func TestTemplate_NewDynamicRenderer(t *testing.T) { + r := NewDynamicRenderer(template.FuncMap{}) + assert.NotNil(t, r) + assert.IsType(t, multitemplate.NewDynamic(), r.Renderer) +} + func TestTemplate_Suite(t *testing.T) { suite.Run(t, new(TemplateTest)) }