1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-26 17:24:42 +01:00

Merge pull request #41 from heyvito/feat/cache

Add support to cached templates
This commit is contained in:
Oliver Steele 2022-02-11 16:29:32 +08:00 committed by GitHub
commit 26d973c198
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 2 deletions

View File

@ -110,3 +110,19 @@ func (e *Engine) Delims(objectLeft, objectRight, tagLeft, tagRight string) *Engi
e.cfg.Delims = []string{objectLeft, objectRight, tagLeft, tagRight}
return e
}
// ParseTemplateAndCache is the same as ParseTemplateLocation, except that the
// source location is used for error reporting and for the {% include %} tag.
// If parsing is successful, provided source is then cached, and can be retrieved
// by {% include %} tags, as long as there is not a real file in the provided path.
//
// The path and line number are used for error reporting.
// The path is also the reference for relative pathnames in the {% include %} tag.
func (e *Engine) ParseTemplateAndCache(source []byte, path string, line int) (*Template, SourceError) {
t, err := e.ParseTemplateLocation(source, path, line)
if err != nil {
return t, err
}
e.cfg.Cache[path] = source
return t, err
}

View File

@ -99,3 +99,19 @@ func BenchmarkEngine_Parse(b *testing.B) {
require.NoError(b, err)
}
}
func TestEngine_ParseTemplateAndCache(t *testing.T) {
// Given two templates...
templateA := []byte("Foo")
templateB := []byte(`{% include "template_a.html" %}, Bar`)
// Cache the first
eng := NewEngine()
_, err := eng.ParseTemplateAndCache(templateA, "template_a.html", 1)
require.NoError(t, err)
// ...and execute the second.
result, err := eng.ParseAndRender(templateB, Bindings{})
require.NoError(t, err)
require.Equal(t, string(result), "Foo, Bar")
}

View File

@ -8,6 +8,7 @@ import (
type Config struct {
parser.Config
grammar
Cache map[string][]byte
}
type grammar struct {
@ -21,5 +22,5 @@ func NewConfig() Config {
tags: map[string]TagCompiler{},
blockDefs: map[string]*blockSyntax{},
}
return Config{parser.NewConfig(g), g}
return Config{Config: parser.NewConfig(g), grammar: g, Cache: map[string][]byte{}}
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"io"
"io/ioutil"
"os"
"strings"
"github.com/osteele/liquid/expressions"
@ -111,7 +112,14 @@ func (c rendererContext) RenderChildren(w io.Writer) Error {
func (c rendererContext) RenderFile(filename string, b map[string]interface{}) (string, error) {
source, err := ioutil.ReadFile(filename)
if err != nil {
if err != nil && os.IsNotExist(err) {
// Is it cached?
if cval, ok := c.ctx.config.Cache[filename]; ok {
source = cval
} else {
return "", err
}
} else if err != nil {
return "", err
}
root, err := c.ctx.config.Compile(string(source), c.node.SourceLoc)

View File

@ -58,3 +58,18 @@ func TestIncludeTag_file_not_found_error(t *testing.T) {
require.Error(t, err)
require.True(t, os.IsNotExist(err.Cause()))
}
func TestIncludeTag_cached_value_handling(t *testing.T) {
config := render.NewConfig()
// foo.html does not exist on testdata.
config.Cache["testdata/foo.html"] = []byte("bar")
loc := parser.SourceLoc{Pathname: "testdata/include_source.html", LineNo: 1}
AddStandardTags(config)
root, err := config.Compile(`{% include "foo.html" %}`, loc)
require.NoError(t, err)
buf := new(bytes.Buffer)
err = render.Render(root, buf, includeTestBindings, config)
require.NoError(t, err)
require.Equal(t, "bar", strings.TrimSpace(buf.String()))
}