1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-26 21:34:44 +01:00

Simplify external tag interface

This commit is contained in:
Oliver Steele 2017-07-01 10:36:47 -04:00
parent a3c646cea2
commit f6c4299739
11 changed files with 49 additions and 29 deletions

View File

@ -49,7 +49,7 @@ type tagBuilder struct {
tag *controlTagDefinition
}
// DefineStartTag defines a control tag and its matching end tag.
// AddStartTag defines a control tag and its matching end tag.
func (s Settings) AddStartTag(name string) tagBuilder {
ct := &controlTagDefinition{name: name}
s.addControlTagDefinition(ct)

View File

@ -16,7 +16,7 @@ func assignTagDef(source string) (func(io.Writer, RenderContext) error, error) {
}, nil
}
// DefineTag creates a tag definition.
// AddTag creates a tag definition.
func (s *Settings) AddTag(name string, td TagDefinition) {
s.tags[name] = td
}

View File

@ -6,9 +6,9 @@ import (
yaml "gopkg.in/yaml.v2"
)
// MustYAML returns the YAML of an interface.
func MustYAML(val interface{}) string {
b, err := yaml.Marshal(val)
// MustYAML is like yaml.Marshal, but panics if the value cannot be marshalled.
func MustYAML(value interface{}) string {
b, err := yaml.Marshal(value)
if err != nil {
panic(err)
}

View File

@ -47,7 +47,7 @@ func (n *ASTRaw) Render(w io.Writer, _ Context) error {
func (n *ASTControlTag) Render(w io.Writer, ctx Context) error {
cd, ok := ctx.settings.findControlTagDefinition(n.Name)
if !ok || cd.parser == nil {
return fmt.Errorf("unimplemented tag: %s", n.Name)
return fmt.Errorf("unknown tag: %s", n.Name)
}
renderer := n.renderer
if renderer == nil {

View File

@ -23,6 +23,8 @@ type RenderContext interface {
RenderChild(io.Writer, *ASTControlTag) error
RenderChildren(io.Writer) error
RenderFile(w io.Writer, filename string) error
TagArgs() string
TagName() string
UpdateBindings(map[string]interface{})
}
@ -106,13 +108,7 @@ func (c renderContext) InnerString() (string, error) {
}
func (c renderContext) ParseTagArgs() (string, error) {
var args string
switch {
case c.node != nil:
args = c.node.Chunk.Args
case c.cn != nil:
args = c.cn.Chunk.Args
}
args := c.TagArgs()
if strings.Contains(args, "{{") {
p, err := c.ctx.settings.Parse(args)
if err != nil {
@ -133,3 +129,25 @@ func (c renderContext) UpdateBindings(bindings map[string]interface{}) {
c.ctx.bindings[k] = v
}
}
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 ""
}
}

View File

@ -25,14 +25,16 @@ func (e engine) DefineStartTag(name string, td func(io.Writer, chunks.RenderCont
// DefineFilter is in the Engine interface.
func (e engine) DefineFilter(name string, fn interface{}) {
// TODO define this on the engine, not globally
e.settings.AddFilter(name, fn)
}
// ParseAndRenderString is in the Engine interface.
// DefineTag is in the Engine interface.
func (e engine) DefineTag(name string, td TagDefinition) {
// TODO define this on the engine, not globally
e.settings.AddTag(name, chunks.TagDefinition(td))
// For simplicity, don't expose the two stage parsing/rendering process to clients.
// Client tags do everything at runtime.
e.settings.AddTag(name, func(_ string) (func(io.Writer, chunks.RenderContext) error, error) {
return td, nil
})
}
// ParseTemplate is in the Engine interface.

View File

@ -1,25 +1,25 @@
package expressions
type wrapper struct {
type expressionWrapper struct {
fn func(ctx Context) (interface{}, error)
}
func (w wrapper) Evaluate(ctx Context) (interface{}, error) {
func (w expressionWrapper) Evaluate(ctx Context) (interface{}, error) {
return w.fn(ctx)
}
// True returns the same value each time.
// Constant creates an expression that returns a constant value.
func Constant(k interface{}) Expression {
return wrapper{
return expressionWrapper{
func(_ Context) (interface{}, error) {
return k, nil
},
}
}
// Negate negates its argument.
func Negate(e Expression) Expression {
return wrapper{
// Not creates an expression that returns ! of the wrapped expression.
func Not(e Expression) Expression {
return expressionWrapper{
func(ctx Context) (interface{}, error) {
value, err := e.Evaluate(ctx)
if err != nil {

View File

@ -18,7 +18,7 @@ import (
"github.com/osteele/liquid/generics"
)
// StandardFilters defines the standard Liquid filters.
// AddStandardFilters defines the standard Liquid filters.
func AddStandardFilters(settings expressions.Settings) {
// values
settings.AddFilter("default", func(value, defaultValue interface{}) interface{} {

View File

@ -94,14 +94,14 @@ func Convert(value interface{}, target reflect.Type) (interface{}, error) {
return nil, err
}
out = reflect.Append(out, reflect.ValueOf(item))
return out.Interface(), nil
}
return out.Interface(), nil
}
}
return nil, conversionError("", value, target)
}
// MustConvert wraps Convert, but panics on error.
// MustConvert is like Convert, but panics if conversion fails.
func MustConvert(value interface{}, t reflect.Type) interface{} {
out, err := Convert(value, t)
if err != nil {

View File

@ -40,4 +40,4 @@ 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 %}",
// and returns a renderer.
type TagDefinition func(args string) (func(io.Writer, chunks.RenderContext) error, error)
type TagDefinition func(io.Writer, chunks.RenderContext) error

View File

@ -87,7 +87,7 @@ func ifTagParser(polarity bool) func(chunks.ASTControlTag) (func(io.Writer, chun
return nil, err
}
if !polarity {
expr = expressions.Negate(expr)
expr = expressions.Not(expr)
}
branches := []branchRec{
{expr, &node},