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:
parent
a3c646cea2
commit
f6c4299739
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 ""
|
||||
}
|
||||
}
|
||||
|
10
engine.go
10
engine.go
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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{} {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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},
|
||||
|
Loading…
Reference in New Issue
Block a user