mirror of
https://github.com/danog/liquid.git
synced 2024-11-26 21:14:45 +01:00
Add ParseTemplateLocation
This commit is contained in:
parent
c11cf2aa25
commit
16c3b6ea59
12
engine.go
12
engine.go
@ -67,8 +67,18 @@ func (e *Engine) RegisterTag(name string, td Renderer) {
|
||||
}
|
||||
|
||||
// ParseTemplate creates a new Template using the engine configuration.
|
||||
//
|
||||
// The template is initialized from the engine configuration. It currently
|
||||
// contains a copy. Subsequent changes to the engine configuration (new tags and filters)
|
||||
// will not affect the template.
|
||||
func (e *Engine) ParseTemplate(source []byte) (*Template, SourceError) {
|
||||
return newTemplate(&e.cfg, source)
|
||||
return newTemplate(&e.cfg, source, "", 0)
|
||||
}
|
||||
|
||||
// ParseTemplateLocation is the same as ParseTemplate followed by SetSourceLocation,
|
||||
// except that the source location is available during template compilation.
|
||||
func (e *Engine) ParseTemplateLocation(source []byte, path string, line int) (*Template, SourceError) {
|
||||
return newTemplate(&e.cfg, source, path, line)
|
||||
}
|
||||
|
||||
// ParseAndRender parses and then renders the template.
|
||||
|
@ -18,7 +18,7 @@ func (e InterpreterError) Error() string { return string(e) }
|
||||
type UndefinedFilter string
|
||||
|
||||
func (e UndefinedFilter) Error() string {
|
||||
return fmt.Sprintf("undefined filter: %s", string(e))
|
||||
return fmt.Sprintf("undefined filter %q", string(e))
|
||||
}
|
||||
|
||||
type valueFn func(Context) interface{}
|
||||
|
@ -26,9 +26,20 @@ func WrapError(err error, loc Locatable) Error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// fmt.Println("wrap", err)
|
||||
if e, ok := err.(Error); ok {
|
||||
return e
|
||||
// re-wrap the error, if the inner layer implemented the locatable interface
|
||||
// but didn't actually provide any information
|
||||
// fmt.Println("about to wrap", err, e)
|
||||
if e.Path() != "" || loc.SourceLocation().IsZero() {
|
||||
// fmt.Println("wrapped")
|
||||
return e
|
||||
}
|
||||
if e.Cause() != nil {
|
||||
err = e.Cause()
|
||||
}
|
||||
}
|
||||
// fmt.Println("wrapping in", loc, loc.SourceLocation())
|
||||
re := Errorf(loc, "%s", err)
|
||||
re.cause = err
|
||||
return re
|
||||
|
@ -37,6 +37,10 @@ func (c Token) SourceLocation() SourceLoc { return c.SourceLoc }
|
||||
// SourceText returns the token's source text, for use in error reporting.
|
||||
func (c Token) SourceText() string { return c.Source }
|
||||
|
||||
// IsZero returns a boolean indicating whether the location doesn't have a set path.
|
||||
func (s SourceLoc) IsZero() bool { return s.Pathname == "" }
|
||||
|
||||
|
||||
func (c Token) String() string {
|
||||
switch c.Type {
|
||||
case TextTokenType:
|
||||
|
@ -14,7 +14,9 @@ type Template struct {
|
||||
config *render.Config
|
||||
}
|
||||
|
||||
func newTemplate(cfg *render.Config, source []byte) (*Template, SourceError) {
|
||||
func newTemplate(cfg *render.Config, source []byte, path string, line int) (*Template, SourceError) {
|
||||
cfg.SourcePath = path
|
||||
cfg.LineNo = line
|
||||
root, err := cfg.Compile(string(source))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1,6 +1,8 @@
|
||||
package liquid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/osteele/liquid/render"
|
||||
@ -28,3 +30,68 @@ func TestTemplate_SetSourcePath(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "source.md", out)
|
||||
}
|
||||
|
||||
func TestTemplate_Parse_race(t *testing.T) {
|
||||
var (
|
||||
engine = NewEngine()
|
||||
count = 10
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
for i := 0; i < count; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
path := fmt.Sprintf("path %d", i)
|
||||
_, err := engine.ParseTemplateLocation([]byte("{{ syntax error }}"), path, i)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, path, err.Path())
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestTemplate_Render_race(t *testing.T) {
|
||||
src := []byte(`{{ n | undefined_filter }}`)
|
||||
|
||||
engine := NewEngine()
|
||||
t1, err := engine.ParseTemplateLocation(src, "path1", 1)
|
||||
require.NoError(t, err)
|
||||
t2, err := engine.ParseTemplateLocation(src, "path2", 1)
|
||||
require.NoError(t, err)
|
||||
_, err = t1.Render(Bindings{})
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "path1", err.Path())
|
||||
_, err = t2.Render(Bindings{})
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "path2", err.Path())
|
||||
|
||||
var (
|
||||
count = 4
|
||||
paths = make([]string, count)
|
||||
ts = make([]*Template, count)
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
for i := 0; i < count; i++ {
|
||||
paths[i] = fmt.Sprintf("path %d", i)
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
var err error
|
||||
ts[i], err = engine.ParseTemplateLocation(src, paths[i], i)
|
||||
require.NoError(t, err)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
for i := 0; i < count; i++ {
|
||||
wg2.Add(1)
|
||||
go func(i int) {
|
||||
defer wg2.Done()
|
||||
_, err = ts[i].Render(Bindings{})
|
||||
require.Error(t, err)
|
||||
// require.Equal(t, paths[i], err.Path())
|
||||
}(i)
|
||||
}
|
||||
wg2.Wait()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user