From 8b39dde991ef6ee5b8ac6915adf8c64c43ac4dc5 Mon Sep 17 00:00:00 2001 From: Chris Pickett Date: Sun, 17 Jul 2022 13:37:46 -0500 Subject: [PATCH 1/2] First attempt at supporting template delimiters --- dynamic.go | 45 +++++++++++++++++++++++++--------- multitemplate.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ renderer.go | 2 ++ 3 files changed, 99 insertions(+), 11 deletions(-) diff --git a/dynamic.go b/dynamic.go index 766ec89..bd002b5 100644 --- a/dynamic.go +++ b/dynamic.go @@ -54,26 +54,27 @@ type templateBuilder struct { templateString string funcMap template.FuncMap templateStrings []string + options TemplateOptions } func (tb templateBuilder) buildTemplate() *template.Template { switch tb.buildType { case templateType: - return tb.tmpl + return tb.tmpl.Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter) case filesTemplateType: - return template.Must(template.ParseFiles(tb.files...)) + return template.Must(template.ParseFiles(tb.files...)).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter) case globTemplateType: - return template.Must(template.ParseGlob(tb.glob)) + return template.Must(template.ParseGlob(tb.glob)).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter) case stringTemplateType: - return template.Must(template.New(tb.templateName).Parse(tb.templateString)) + return template.Must(template.New(tb.templateName).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter).Parse(tb.templateString)) case stringFuncTemplateType: - tmpl := template.New(tb.templateName).Funcs(tb.funcMap) + tmpl := template.New(tb.templateName).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter).Funcs(tb.funcMap) for _, ts := range tb.templateStrings { tmpl = template.Must(tmpl.Parse(ts)) } return tmpl case filesFuncTemplateType: - return template.Must(template.New(tb.templateName).Funcs(tb.funcMap).ParseFiles(tb.files...)) + return template.Must(template.New(tb.templateName).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter).Funcs(tb.funcMap).ParseFiles(tb.files...)) default: panic("Invalid builder type for dynamic template") } @@ -87,14 +88,14 @@ func (r DynamicRender) Add(name string, tmpl *template.Template) { if len(name) == 0 { panic("template name cannot be empty") } - builder := &templateBuilder{templateName: name, tmpl: tmpl} + builder := &templateBuilder{templateName: name, tmpl: tmpl, options: *NewTemplateOptions()} builder.buildType = templateType r[name] = builder } // AddFromFiles supply add template from files func (r DynamicRender) AddFromFiles(name string, files ...string) *template.Template { - builder := &templateBuilder{templateName: name, files: files} + builder := &templateBuilder{templateName: name, files: files, options: *NewTemplateOptions()} builder.buildType = filesTemplateType r[name] = builder return builder.buildTemplate() @@ -102,7 +103,7 @@ func (r DynamicRender) AddFromFiles(name string, files ...string) *template.Temp // AddFromGlob supply add template from global path func (r DynamicRender) AddFromGlob(name, glob string) *template.Template { - builder := &templateBuilder{templateName: name, glob: glob} + builder := &templateBuilder{templateName: name, glob: glob, options: *NewTemplateOptions()} builder.buildType = globTemplateType r[name] = builder return builder.buildTemplate() @@ -110,7 +111,7 @@ func (r DynamicRender) AddFromGlob(name, glob string) *template.Template { // AddFromString supply add template from strings func (r DynamicRender) AddFromString(name, templateString string) *template.Template { - builder := &templateBuilder{templateName: name, templateString: templateString} + builder := &templateBuilder{templateName: name, templateString: templateString, options: *NewTemplateOptions()} builder.buildType = stringTemplateType r[name] = builder return builder.buildTemplate() @@ -121,6 +122,19 @@ func (r DynamicRender) AddFromStringsFuncs(name string, funcMap template.FuncMap builder := &templateBuilder{ templateName: name, funcMap: funcMap, templateStrings: templateStrings, + options: *NewTemplateOptions(), + } + builder.buildType = stringFuncTemplateType + r[name] = builder + return builder.buildTemplate() +} + +// AddFromStringsFuncsWithOptions supply add template from strings with options +func (r DynamicRender) AddFromStringsFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, templateStrings ...string) *template.Template { + builder := &templateBuilder{ + templateName: name, funcMap: funcMap, + templateStrings: templateStrings, + options: options, } builder.buildType = stringFuncTemplateType r[name] = builder @@ -130,7 +144,16 @@ func (r DynamicRender) AddFromStringsFuncs(name string, funcMap template.FuncMap // AddFromFilesFuncs supply add template from file callback func func (r DynamicRender) AddFromFilesFuncs(name string, funcMap template.FuncMap, files ...string) *template.Template { tname := filepath.Base(files[0]) - builder := &templateBuilder{templateName: tname, funcMap: funcMap, files: files} + builder := &templateBuilder{templateName: tname, funcMap: funcMap, files: files, options: *NewTemplateOptions()} + builder.buildType = filesFuncTemplateType + r[name] = builder + return builder.buildTemplate() +} + +// AddFromFilesFuncs supply add template from file callback func +func (r DynamicRender) AddFromFilesFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, files ...string) *template.Template { + tname := filepath.Base(files[0]) + builder := &templateBuilder{templateName: tname, funcMap: funcMap, files: files, options: options} builder.buildType = filesFuncTemplateType r[name] = builder return builder.buildTemplate() diff --git a/multitemplate.go b/multitemplate.go index 0940aa8..35bc714 100644 --- a/multitemplate.go +++ b/multitemplate.go @@ -10,6 +10,49 @@ import ( // Render type type Render map[string]*template.Template +type TemplateOptions struct { + LeftDelimiter string + RightDelimiter string +} + +type TemplateOption func(*TemplateOptions) + +func WithLeftDelimiter(delim string) TemplateOption { + return func(t *TemplateOptions) { + t.LeftDelimiter = delim + } +} + +func WithRightDelimiter(delim string) TemplateOption { + return func(t *TemplateOptions) { + t.RightDelimiter = delim + } +} + +func Delims(leftDelim, rightDelim string) TemplateOption { + return func(t *TemplateOptions) { + WithLeftDelimiter(leftDelim)(t) + WithRightDelimiter(rightDelim)(t) + } +} + +func NewTemplateOptions(opts ...TemplateOption) *TemplateOptions { + const ( + defaultLeftDelim = "{{" + defaultRightDelim = "}}" + ) + + t := &TemplateOptions{ + LeftDelimiter: defaultLeftDelim, + RightDelimiter: defaultRightDelim, + } + + for _, opt := range opts { + opt(t) + } + + return t +} var ( _ render.HTMLRender = Render{} @@ -68,6 +111,18 @@ func (r Render) AddFromStringsFuncs(name string, funcMap template.FuncMap, templ return tmpl } +// AddFromStringsFuncsWithOptions supply add template from strings with options +func (r Render) AddFromStringsFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, templateStrings ...string) *template.Template { + tmpl := template.New(name).Delims(options.LeftDelimiter, options.RightDelimiter).Funcs(funcMap) + + for _, ts := range templateStrings { + tmpl = template.Must(tmpl.Parse(ts)).Delims(options.LeftDelimiter, options.RightDelimiter) + } + + r.Add(name, tmpl) + return tmpl +} + // AddFromFilesFuncs supply add template from file callback func func (r Render) AddFromFilesFuncs(name string, funcMap template.FuncMap, files ...string) *template.Template { tname := filepath.Base(files[0]) @@ -76,6 +131,14 @@ func (r Render) AddFromFilesFuncs(name string, funcMap template.FuncMap, files . return tmpl } +// AddFromFilesFuncsWithOptions supply add template from file callback func with options +func (r Render) AddFromFilesFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, files ...string) *template.Template { + tname := filepath.Base(files[0]) + tmpl := template.Must(template.New(tname).Delims(options.LeftDelimiter, options.RightDelimiter).Funcs(funcMap).ParseFiles(files...)) + r.Add(name, tmpl) + return tmpl +} + // Instance supply render string func (r Render) Instance(name string, data interface{}) render.Render { return render.HTML{ diff --git a/renderer.go b/renderer.go index 8420133..bf58dbe 100644 --- a/renderer.go +++ b/renderer.go @@ -17,5 +17,7 @@ type Renderer interface { AddFromGlob(name, glob string) *template.Template AddFromString(name, templateString string) *template.Template AddFromStringsFuncs(name string, funcMap template.FuncMap, templateStrings ...string) *template.Template + AddFromStringsFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, templateStrings ...string) *template.Template AddFromFilesFuncs(name string, funcMap template.FuncMap, files ...string) *template.Template + AddFromFilesFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, files ...string) *template.Template } From 50a22c5922ec713715f9515b550560502845a296 Mon Sep 17 00:00:00 2001 From: Parnic Date: Sun, 5 May 2024 13:53:46 -0500 Subject: [PATCH 2/2] Merge upstream master --- .github/workflows/codeql.yml | 34 ++++----- .github/workflows/go.yml | 25 +++--- .github/workflows/goreleaser.yml | 23 +++--- .goreleaser.yaml | 57 ++++---------- dynamic.go | 12 +++ dynamic_test.go | 22 ++++++ go.mod | 37 ++++++++- go.sum | 126 +++++++++++++++---------------- multitemplate.go | 8 ++ multitemplate_test.go | 22 ++++++ renderer.go | 2 + 11 files changed, 216 insertions(+), 152 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2d9bcdd..f3ceec8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,12 +13,12 @@ name: "CodeQL" on: push: - branches: [ master ] + branches: [master] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [master] schedule: - - cron: '41 23 * * 6' + - cron: "41 23 * * 6" jobs: analyze: @@ -32,23 +32,23 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'go' ] + language: ["go"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 4c04167..b3e8d89 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -12,22 +12,25 @@ jobs: lint: runs-on: ubuntu-latest steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: '^1.16' - - name: Checkout repository - uses: actions/checkout@v3 + go-version-file: go.mod + check-latest: true - name: Setup golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v5 with: - version: v1.45.0 args: --verbose test: strategy: matrix: os: [ubuntu-latest] - go: [1.14, 1.15, 1.16, 1.17, 1.18] + go: [1.18, 1.19, "1.20", 1.21, 1.22] include: - os: ubuntu-latest go-build: ~/.cache/go-build @@ -40,16 +43,16 @@ jobs: GOPROXY: https://proxy.golang.org steps: - name: Set up Go ${{ matrix.go }} - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.ref }} - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: | ${{ matrix.go-build }} @@ -62,6 +65,6 @@ jobs: go test -v -covermode=atomic -coverprofile=coverage.out - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: flags: ${{ matrix.os }},go-${{ matrix.go }} diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index 64ed8b2..0392c49 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -3,7 +3,7 @@ name: Goreleaser on: push: tags: - - '*' + - "*" permissions: contents: write @@ -12,23 +12,22 @@ jobs: goreleaser: runs-on: ubuntu-latest steps: - - - name: Checkout - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v4 with: fetch-depth: 0 - - - name: Set up Go - uses: actions/setup-go@v2 + + - name: Setup go + uses: actions/setup-go@v5 with: - go-version: 1.17 - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v3 + go-version-file: go.mod + check-latest: true + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v5 with: # either 'goreleaser' (default) or 'goreleaser-pro' distribution: goreleaser version: latest - args: release --rm-dist + args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yaml b/.goreleaser.yaml index aa5453c..dc3a01f 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,57 +1,26 @@ -project_name: queue - builds: - - - # If true, skip the build. - # Useful for library projects. - # Default is false - skip: true + - skip: true changelog: - # Set it to true if you wish to skip the changelog generation. - # This may result in an empty release notes on GitHub/GitLab/Gitea. - skip: false - - # Changelog generation implementation to use. - # - # Valid options are: - # - `git`: uses `git log`; - # - `github`: uses the compare GitHub API, appending the author login to the changelog. - # - `gitlab`: uses the compare GitLab API, appending the author name and email to the changelog. - # - `github-native`: uses the GitHub release notes generation API, disables the groups feature. - # - # Defaults to `git`. - use: git - - # Sorts the changelog by the commit's messages. - # Could either be asc, desc or empty - # Default is empty - sort: asc - - # Group commits messages by given regex and title. - # Order value defines the order of the groups. - # Proving no regex means all commits will be grouped under the default group. - # Groups are disabled when using github-native, as it already groups things by itself. - # - # Default is no groups. + use: github groups: - title: Features regexp: "^.*feat[(\\w)]*:+.*$" order: 0 - - title: 'Bug fixes' + - title: "Bug fixes" regexp: "^.*fix[(\\w)]*:+.*$" order: 1 - - title: 'Enhancements' + - title: "Enhancements" regexp: "^.*chore[(\\w)]*:+.*$" order: 2 + - title: "Refactor" + regexp: "^.*refactor[(\\w)]*:+.*$" + order: 3 + - title: "Build process updates" + regexp: ^.*?(build|ci)(\(.+\))??!?:.+$ + order: 4 + - title: "Documentation updates" + regexp: ^.*?docs?(\(.+\))??!?:.+$ + order: 4 - title: Others order: 999 - - filters: - # Commit messages matching the regexp listed here will be removed from - # the changelog - # Default is empty - exclude: - - '^docs' - - 'CICD' - - typo diff --git a/dynamic.go b/dynamic.go index bd002b5..ba2d74c 100644 --- a/dynamic.go +++ b/dynamic.go @@ -3,6 +3,7 @@ package multitemplate import ( "fmt" "html/template" + "io/fs" "path/filepath" "github.com/gin-gonic/gin" @@ -39,6 +40,7 @@ const ( templateType builderType = iota filesTemplateType globTemplateType + fsTemplateType stringTemplateType stringFuncTemplateType filesFuncTemplateType @@ -51,6 +53,7 @@ type templateBuilder struct { templateName string files []string glob string + fsys fs.FS templateString string funcMap template.FuncMap templateStrings []string @@ -65,6 +68,8 @@ func (tb templateBuilder) buildTemplate() *template.Template { return template.Must(template.ParseFiles(tb.files...)).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter) case globTemplateType: return template.Must(template.ParseGlob(tb.glob)).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter) + case fsTemplateType: + return template.Must(template.ParseFS(tb.fsys, tb.files...)).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter) case stringTemplateType: return template.Must(template.New(tb.templateName).Delims(tb.options.LeftDelimiter, tb.options.RightDelimiter).Parse(tb.templateString)) case stringFuncTemplateType: @@ -109,6 +114,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, options: *NewTemplateOptions()} diff --git a/dynamic_test.go b/dynamic_test.go index a66077f..0a2cefa 100644 --- a/dynamic_test.go +++ b/dynamic_test.go @@ -2,6 +2,7 @@ package multitemplate import ( "html/template" + "os" "testing" "github.com/gin-gonic/gin" @@ -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") @@ -90,6 +98,20 @@ func TestAddFromGlobDynamic(t *testing.T) { assert.Equal(t, "

Test Multiple Template

\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, "

Test Multiple Template

\nHi, this is article template\n", w.Body.String()) +} + func TestAddFromStringDynamic(t *testing.T) { router := gin.New() router.HTMLRender = createFromStringDynamic() diff --git a/go.mod b/go.mod index 652f2b2..2b1ce3c 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,39 @@ module github.com/gin-contrib/multitemplate +go 1.18 + require ( - github.com/gin-gonic/gin v1.8.1 - github.com/stretchr/testify v1.8.0 + github.com/gin-gonic/gin v1.9.1 + github.com/stretchr/testify v1.9.0 ) -go 1.13 +require ( + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + google.golang.org/protobuf v1.34.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index ad787ad..a721f8a 100644 --- a/go.sum +++ b/go.sum @@ -1,90 +1,86 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= -github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= -github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= +google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/multitemplate.go b/multitemplate.go index 35bc714..ef0d1a2 100644 --- a/multitemplate.go +++ b/multitemplate.go @@ -3,6 +3,7 @@ package multitemplate import ( "fmt" "html/template" + "io/fs" "path/filepath" "github.com/gin-gonic/gin/render" @@ -92,6 +93,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)) diff --git a/multitemplate_test.go b/multitemplate_test.go index debf16f..6b631de 100644 --- a/multitemplate_test.go +++ b/multitemplate_test.go @@ -5,6 +5,7 @@ import ( "html/template" "net/http" "net/http/httptest" + "os" "testing" "github.com/gin-gonic/gin" @@ -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") @@ -93,6 +101,20 @@ func TestAddFromGlob(t *testing.T) { assert.Equal(t, "

Test Multiple Template

\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, "

Test Multiple Template

\nHi, this is article template\n", w.Body.String()) +} + func TestAddFromString(t *testing.T) { router := gin.New() router.HTMLRender = createFromString() diff --git a/renderer.go b/renderer.go index bf58dbe..ac457ea 100644 --- a/renderer.go +++ b/renderer.go @@ -2,6 +2,7 @@ package multitemplate import ( "html/template" + "io/fs" "github.com/gin-gonic/gin/render" ) @@ -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 AddFromStringsFuncsWithOptions(name string, funcMap template.FuncMap, options TemplateOptions, templateStrings ...string) *template.Template