1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-30 08:28:58 +01:00
liquid/render/context.go

155 lines
3.6 KiB
Go
Raw Normal View History

2017-07-04 17:03:18 +02:00
package render
2017-06-26 21:36:05 +02:00
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"strings"
2017-07-04 17:12:40 +02:00
"github.com/osteele/liquid/expression"
2017-06-26 21:36:05 +02:00
)
// Context provides the rendering context for a tag renderer.
type Context interface {
Get(name string) interface{}
Evaluate(expr expression.Expression) (interface{}, error)
EvaluateString(source string) (interface{}, error)
EvaluateStatement(tag, source string) (interface{}, error)
2017-07-06 05:25:03 +02:00
ExpandTagArg() (string, error)
InnerString() (string, error)
RenderChild(io.Writer, *BlockNode) error
RenderChildren(io.Writer) error
2017-07-04 22:48:38 +02:00
RenderFile(string, map[string]interface{}) (string, error)
Set(name string, value interface{})
SourceFile() string
TagArgs() string
TagName() string
2017-06-26 21:36:05 +02:00
}
type renderContext struct {
ctx nodeContext
node *FunctionalNode
cn *BlockNode
2017-06-26 21:36:05 +02:00
}
2017-06-27 19:18:01 +02:00
// Evaluate evaluates an expression within the template context.
func (c renderContext) Evaluate(expr expression.Expression) (out interface{}, err error) {
return c.ctx.Evaluate(expr)
}
2017-07-04 22:48:38 +02:00
func (c renderContext) EvaluateStatement(tag, source string) (interface{}, error) {
return c.EvaluateString(fmt.Sprintf("%%%s %s", tag, source))
}
// EvaluateString evaluates an expression within the template context.
func (c renderContext) EvaluateString(source string) (out interface{}, err error) {
2017-06-27 19:18:01 +02:00
defer func() {
if r := recover(); r != nil {
switch e := r.(type) {
2017-07-04 17:12:40 +02:00
case expression.InterpreterError:
2017-06-27 19:18:01 +02:00
err = e
default:
// fmt.Println(string(debug.Stack()))
2017-07-06 01:09:59 +02:00
panic(Errorf("%s during evaluation of %s", e, source))
2017-06-27 19:18:01 +02:00
}
}
}()
2017-07-04 22:48:38 +02:00
return expression.EvaluateString(source, expression.NewContext(c.ctx.bindings, c.ctx.config.Config))
}
// Get gets a variable value within an evaluation context.
func (c renderContext) Get(name string) interface{} {
return c.ctx.bindings[name]
}
2017-07-06 05:25:03 +02:00
func (c renderContext) ExpandTagArg() (string, error) {
2017-07-04 22:48:38 +02:00
args := c.TagArgs()
if strings.Contains(args, "{{") {
2017-07-06 14:07:53 +02:00
p, err := c.ctx.config.Compile(args)
2017-07-04 22:48:38 +02:00
if err != nil {
return "", err
}
buf := new(bytes.Buffer)
err = renderNode(p, buf, c.ctx)
if err != nil {
return "", err
}
return buf.String(), nil
}
return args, nil
}
// RenderChild renders a node.
func (c renderContext) RenderChild(w io.Writer, b *BlockNode) error {
return c.ctx.RenderSequence(w, b.Body)
}
// RenderChildren renders the current node's children.
func (c renderContext) RenderChildren(w io.Writer) error {
if c.cn == nil {
return nil
}
return c.ctx.RenderSequence(w, c.cn.Body)
}
2017-07-04 22:48:38 +02:00
func (c renderContext) RenderFile(filename string, b map[string]interface{}) (string, error) {
source, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
2017-07-06 14:07:53 +02:00
ast, err := c.ctx.config.Compile(string(source))
if err != nil {
return "", err
}
2017-07-04 22:48:38 +02:00
nc := c.ctx.Clone()
for k, v := range b {
c.ctx.bindings[k] = v
}
buf := new(bytes.Buffer)
2017-07-04 22:48:38 +02:00
if err := renderNode(ast, buf, nc); err != nil {
return "", err
}
return buf.String(), nil
}
// InnerString renders the children to a string.
func (c renderContext) InnerString() (string, error) {
buf := new(bytes.Buffer)
if err := c.RenderChildren(buf); err != nil {
return "", err
}
return buf.String(), nil
}
2017-07-04 22:48:38 +02:00
// Set sets a variable value from an evaluation context.
func (c renderContext) Set(name string, value interface{}) {
c.ctx.bindings[name] = value
}
2017-07-04 22:48:38 +02:00
func (c renderContext) SourceFile() string {
return c.ctx.config.Filename
}
func (c renderContext) TagArgs() string {
switch {
case c.node != nil:
return c.node.Chunk.Args
case c.cn != nil:
return c.cn.Chunk.Args
default:
return ""
}
}
func (c renderContext) TagName() string {
switch {
case c.node != nil:
return c.node.Chunk.Name
case c.cn != nil:
return c.cn.Chunk.Name
default:
return ""
}
2017-06-27 19:18:01 +02:00
}