1
0
mirror of https://github.com/danog/liquid.git synced 2024-12-03 12:37:46 +01:00

New top-level Context wrapper

This commit is contained in:
Oliver Steele 2017-07-01 23:52:38 -04:00
parent e71bc95d5f
commit d6bc456ee4
5 changed files with 51 additions and 26 deletions

15
context.go Normal file
View File

@ -0,0 +1,15 @@
package liquid
type context struct {
bindings map[string]interface{}
}
// NewContext creates a new context from a variable binding map.
func NewContext(bindings map[string]interface{}) Context {
return &context{bindings}
}
// Bindings is in the Render interface.
func (c *context) Bindings() map[string]interface{} {
return c.bindings
}

View File

@ -47,17 +47,17 @@ func (e engine) ParseTemplate(text []byte) (Template, error) {
} }
// ParseAndRender is in the Engine interface. // ParseAndRender is in the Engine interface.
func (e engine) ParseAndRender(text []byte, bindings map[string]interface{}) ([]byte, error) { func (e engine) ParseAndRender(text []byte, c Context) ([]byte, error) {
t, err := e.ParseTemplate(text) t, err := e.ParseTemplate(text)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return t.Render(bindings) return t.Render(c)
} }
// ParseAndRenderString is in the Engine interface. // ParseAndRenderString is in the Engine interface.
func (e engine) ParseAndRenderString(text string, bindings map[string]interface{}) (string, error) { func (e engine) ParseAndRenderString(text string, c Context) (string, error) {
b, err := e.ParseAndRender([]byte(text), bindings) b, err := e.ParseAndRender([]byte(text), c)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -28,15 +28,34 @@ type Engine interface {
DefineTag(string, TagDefinition) DefineTag(string, TagDefinition)
DefineStartTag(string, func(io.Writer, chunks.RenderContext) error) DefineStartTag(string, func(io.Writer, chunks.RenderContext) error)
ParseTemplate(b []byte) (Template, error) ParseTemplate([]byte) (Template, error)
// ParseAndRender parses and then renders the template. // ParseAndRender parses and then renders the template.
ParseAndRender(b []byte, bindings map[string]interface{}) ([]byte, error) ParseAndRender([]byte, Context) ([]byte, error)
// ParseAndRenderString is a convenience wrapper for ParseAndRender, that has string input and output. // ParseAndRenderString is a convenience wrapper for ParseAndRender, that has string input and output.
ParseAndRenderString(s string, bindings map[string]interface{}) (string, error) ParseAndRenderString(string, Context) (string, error)
}
// Template renders a template according to scope.
//
// Bindings is a map of liquid variable names to objects.
type Template interface {
// Render executes the template with the specified bindings.
Render(Context) ([]byte, error)
// RenderString is a convenience wrapper for Render, that has string input and output.
RenderString(Context) (string, error)
}
// Context supplies variable bindings and other information to a
// Render.
//
// In the future, it will hold methods to get and set the current
// filename.
type Context interface {
Bindings() map[string]interface{}
} }
// Renderer is the type of a function that is evaluated within a context and writes to output. // Renderer is the type of a function that is evaluated within a context and writes to output.
type Renderer func(io.Writer, chunks.Context) error // type Renderer func(io.Writer, chunks.Context) error
// TagDefinition is the type of a function that parses the argument string "args" from a tag "{% tagname args %}", // TagDefinition is the type of a function that parses the argument string "args" from a tag "{% tagname args %}",
// and returns a renderer. // and returns a renderer.

View File

@ -16,19 +16,19 @@ var liquidTests = []struct{ in, expected string }{
{`{{ "upper" | upcase }}`, "UPPER"}, {`{{ "upper" | upcase }}`, "UPPER"},
} }
var liquidTestScope = map[string]interface{}{ var testContext = NewContext(map[string]interface{}{
"x": 123, "x": 123,
"ar": []string{"first", "second", "third"}, "ar": []string{"first", "second", "third"},
"page": map[string]interface{}{ "page": map[string]interface{}{
"title": "Introduction", "title": "Introduction",
}, },
} })
func TestLiquid(t *testing.T) { func TestLiquid(t *testing.T) {
engine := NewEngine() engine := NewEngine()
for i, test := range liquidTests { for i, test := range liquidTests {
t.Run(fmt.Sprint(i+1), func(t *testing.T) { t.Run(fmt.Sprint(i+1), func(t *testing.T) {
out, err := engine.ParseAndRenderString(test.in, liquidTestScope) out, err := engine.ParseAndRenderString(test.in, testContext)
require.NoErrorf(t, err, test.in) require.NoErrorf(t, err, test.in)
require.Equalf(t, test.expected, out, test.in) require.Equalf(t, test.expected, out, test.in)
}) })
@ -43,7 +43,8 @@ func Example() {
"title": "Introduction", "title": "Introduction",
}, },
} }
out, err := engine.ParseAndRenderString(template, bindings) context := NewContext(bindings)
out, err := engine.ParseAndRenderString(template, context)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }

View File

@ -6,25 +6,15 @@ import (
"github.com/osteele/liquid/chunks" "github.com/osteele/liquid/chunks"
) )
// Template renders a template according to scope.
//
// Bindings is a map of liquid variable names to objects.
type Template interface {
// Render executes the template with the specified bindings.
Render(bindings map[string]interface{}) ([]byte, error)
// RenderString is a convenience wrapper for Render, that has string input and output.
RenderString(bindings map[string]interface{}) (string, error)
}
type template struct { type template struct {
ast chunks.ASTNode ast chunks.ASTNode
settings chunks.Settings settings chunks.Settings
} }
// Render executes the template within the bindings environment. // Render executes the template within the bindings environment.
func (t *template) Render(bindings map[string]interface{}) ([]byte, error) { func (t *template) Render(c Context) ([]byte, error) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := t.ast.Render(buf, chunks.NewContext(bindings, t.settings)) err := t.ast.Render(buf, chunks.NewContext(c.Bindings(), t.settings))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -32,8 +22,8 @@ func (t *template) Render(bindings map[string]interface{}) ([]byte, error) {
} }
// RenderString is a convenience wrapper for Render, that has string input and output. // RenderString is a convenience wrapper for Render, that has string input and output.
func (t *template) RenderString(bindings map[string]interface{}) (string, error) { func (t *template) RenderString(c Context) (string, error) {
b, err := t.Render(bindings) b, err := t.Render(c)
if err != nil { if err != nil {
return "", err return "", err
} }