1
0
mirror of https://github.com/danog/liquid.git synced 2025-01-22 14:02:34 +01:00

Render uses a switch instead of polymorphism

This commit is contained in:
Oliver Steele 2017-07-04 10:25:29 -04:00
parent 8d9df82787
commit 05597307bd
9 changed files with 50 additions and 62 deletions

View File

@ -9,7 +9,7 @@ import (
// ASTNode is a node of an AST.
type ASTNode interface {
// Render evaluates an AST node and writes the result to an io.Writer.
Render(io.Writer, Context) error
// Render(io.Writer, Context) error
}
// ASTRaw holds the text between the start and end of a raw tag.

View File

@ -18,6 +18,8 @@ type Chunk struct {
// ChunkType is the type of a Chunk
type ChunkType int
//go:generate stringer -type=ChunkType
const (
// TextChunkType is the type of a text Chunk
TextChunkType ChunkType = iota

View File

@ -8,65 +8,53 @@ import (
"github.com/osteele/liquid/generics"
)
// Render is in the ASTNode interface.
func (n *ASTSeq) Render(w io.Writer, ctx Context) error {
for _, c := range n.Children {
if err := c.Render(w, ctx); err != nil {
return err
// Render renders the AST rooted at node to the writer.
func Render(node ASTNode, w io.Writer, ctx Context) error {
return renderNode(node, w, ctx)
}
func renderNode(node ASTNode, w io.Writer, ctx Context) error { // nolint: gocyclo
switch n := node.(type) {
case *ASTSeq:
for _, c := range n.Children {
if err := renderNode(c, w, ctx); err != nil {
return err
}
}
}
return nil
}
// Render is in the ASTNode interface.
func (n *ASTFunctional) Render(w io.Writer, ctx Context) error {
err := n.render(w, renderContext{ctx, n, nil})
// TODO restore something like this
// if err != nil {
// fmt.Println("while parsing", n.Source)
// }
return err
}
// Render is in the ASTNode interface.
func (n *ASTText) Render(w io.Writer, _ Context) error {
_, err := w.Write([]byte(n.Source))
return err
}
// Render is in the ASTNode interface.
func (n *ASTRaw) Render(w io.Writer, _ Context) error {
for _, s := range n.slices {
_, err := w.Write([]byte(s))
case *ASTFunctional:
return n.render(w, renderContext{ctx, n, nil})
case *ASTText:
_, err := w.Write([]byte(n.Source))
return err
case *ASTRaw:
for _, s := range n.slices {
_, err := w.Write([]byte(s))
if err != nil {
return err
}
}
case *ASTBlock:
cd, ok := ctx.settings.findBlockDef(n.Name)
if !ok || cd.parser == nil {
return fmt.Errorf("unknown tag: %s", n.Name)
}
renderer := n.renderer
if renderer == nil {
panic(fmt.Errorf("unset renderer for %v", n))
}
return renderer(w, renderContext{ctx, nil, n})
case *ASTObject:
value, err := ctx.Evaluate(n.expr)
if err != nil {
return err
return fmt.Errorf("%s in %s", err, n.Source)
}
return writeObject(value, w)
default:
panic(fmt.Errorf("unknown node type %T", node))
}
return nil
}
// Render is in the ASTNode interface.
func (n *ASTBlock) Render(w io.Writer, ctx Context) error {
cd, ok := ctx.settings.findBlockDef(n.Name)
if !ok || cd.parser == nil {
return fmt.Errorf("unknown tag: %s", n.Name)
}
renderer := n.renderer
if renderer == nil {
panic(fmt.Errorf("unset renderer for %v", n))
}
return renderer(w, renderContext{ctx, nil, n})
}
// Render is in the ASTNode interface.
func (n *ASTObject) Render(w io.Writer, ctx Context) error {
value, err := ctx.Evaluate(n.expr)
if err != nil {
return fmt.Errorf("%s in %s", err, n.Source)
}
return writeObject(value, w)
}
// writeObject writes a value used in an object node
func writeObject(value interface{}, w io.Writer) error {
value = generics.ToLiquid(value)
@ -94,7 +82,7 @@ func writeObject(value interface{}, w io.Writer) error {
// RenderASTSequence renders a sequence of nodes.
func (c Context) RenderASTSequence(w io.Writer, seq []ASTNode) error {
for _, n := range seq {
if err := n.Render(w, c); err != nil {
if err := renderNode(n, w, c); err != nil {
return err
}
}

View File

@ -96,7 +96,7 @@ func (c renderContext) RenderFile(filename string) (string, error) {
return "", err
}
buf := new(bytes.Buffer)
if err := ast.Render(buf, c.ctx); err != nil {
if err := renderNode(ast, buf, c.ctx); err != nil {
return "", err
}
return buf.String(), nil
@ -119,7 +119,7 @@ func (c renderContext) ParseTagArgs() (string, error) {
return "", err
}
buf := new(bytes.Buffer)
err = p.Render(buf, c.ctx)
err = renderNode(p, buf, c.ctx)
if err != nil {
return "", err
}

View File

@ -84,7 +84,7 @@ func TestRender(t *testing.T) {
ast, err := settings.Parse(test.in)
require.NoErrorf(t, err, test.in)
buf := new(bytes.Buffer)
err = ast.Render(buf, context)
err = renderNode(ast, buf, context)
require.NoErrorf(t, err, test.in)
require.Equalf(t, test.out, buf.String(), test.in)
})
@ -99,7 +99,7 @@ func TestRenderErrors(t *testing.T) {
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
ast, err := settings.Parse(test.in)
require.NoErrorf(t, err, test.in)
err = ast.Render(ioutil.Discard, context)
err = renderNode(ast, ioutil.Discard, context)
require.Errorf(t, err, test.in)
require.Containsf(t, err.Error(), test.out, test.in)
})

View File

@ -1,5 +1,3 @@
//go:generate stringer -type=ChunkType
package chunks
import (

View File

@ -153,7 +153,7 @@ func TestRender(t *testing.T) {
ast, err := settings.Parse(test.in)
require.NoErrorf(t, err, test.in)
buf := new(bytes.Buffer)
err = ast.Render(buf, context)
err = chunks.Render(ast, buf, context)
require.NoErrorf(t, err, test.in)
require.Equalf(t, test.expected, buf.String(), test.in)
})

View File

@ -14,7 +14,7 @@ type template struct {
// Render executes the template within the bindings environment.
func (t *template) Render(b Bindings) ([]byte, error) {
buf := new(bytes.Buffer)
err := t.ast.Render(buf, chunks.NewContext(b, t.settings))
err := chunks.Render(t.ast, buf, chunks.NewContext(b, t.settings))
if err != nil {
return nil, err
}