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:
parent
8d9df82787
commit
05597307bd
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -1,5 +1,3 @@
|
||||
//go:generate stringer -type=ChunkType
|
||||
|
||||
package chunks
|
||||
|
||||
import (
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user