1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-27 06:24:39 +01:00

Implement case (w/out else)

This commit is contained in:
Oliver Steele 2017-06-28 16:00:46 -04:00
parent c433c0894e
commit c5e7e6c277
2 changed files with 79 additions and 32 deletions

View File

@ -6,6 +6,7 @@ import (
"io"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/generics"
)
// DefineStandardTags defines the standard Liquid tags.
@ -14,13 +15,13 @@ func DefineStandardTags() {
// but it ignores any syntax specified here.
loopTags := []string{"break", "continue", "cycle"}
chunks.DefineControlTag("capture").Action(captureTag)
chunks.DefineControlTag("case").Branch("when")
chunks.DefineControlTag("case").Branch("when").Action(caseTag)
chunks.DefineControlTag("comment")
chunks.DefineControlTag("for").Governs(loopTags).Action(loopTag)
chunks.DefineControlTag("if").Branch("else").Branch("elsif").Action(ifTagAction(true))
chunks.DefineControlTag("if").Branch("else").Branch("elsif").Action(ifTag(true))
chunks.DefineControlTag("raw")
chunks.DefineControlTag("tablerow").Governs(loopTags)
chunks.DefineControlTag("unless").SameSyntaxAs("if").Action(ifTagAction(false))
chunks.DefineControlTag("unless").SameSyntaxAs("if").Action(ifTag(false))
}
func captureTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
@ -36,10 +37,51 @@ func captureTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error
}
}
func ifTagAction(polarity bool) func(chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
func caseTag(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
// TODO parse error on non-empty node.Body
// TODO case can include an else
expr, err := chunks.MakeExpressionValueFn(node.Args)
// TODO change the API to let this return the error directly
if err != nil {
return func(io.Writer, chunks.Context) error { return err }
}
type branchRec struct {
fn func(chunks.Context) (interface{}, error)
node *chunks.ASTControlTag
}
cases := []branchRec{}
for _, branch := range node.Branches {
bfn, err := chunks.MakeExpressionValueFn(branch.Args)
if err != nil {
return func(io.Writer, chunks.Context) error { return err }
}
cases = append(cases, branchRec{bfn, branch})
}
return func(w io.Writer, ctx chunks.Context) error {
value, err := expr(ctx)
if err != nil {
return err
}
for _, branch := range cases {
b, err := branch.fn(ctx)
if err != nil {
return err
}
if generics.Equal(value, b) {
return ctx.RenderASTSequence(w, branch.node.Body)
}
}
return nil
}
}
func ifTag(polarity bool) func(chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
// TODO parse error if the order of branches is other than ifelse*else?
// TODO parse the tests into a table evaluator -> []AST
return func(node chunks.ASTControlTag) func(io.Writer, chunks.Context) error {
expr, err := chunks.MakeExpressionValueFn(node.Args)
if err != nil {
// TODO allow these to return the error directly
return func(io.Writer, chunks.Context) error { return err }
}
return func(w io.Writer, ctx chunks.Context) error {

View File

@ -18,42 +18,47 @@ var parseErrorTests = []struct{ in, expected string }{
}
var tagTests = []struct{ in, expected string }{
{"{%assign av = 1%}{{av}}", "1"},
{"{%assign av = obj.a%}{{av}}", "1"},
{`{%assign av = 1%}{{av}}`, "1"},
{`{%assign av = obj.a%}{{av}}`, "1"},
// TODO test whether this requires matching interior tags
{"{%comment%}{{a}}{%unknown%}{%endcomment%}", ""},
{`{%comment%}{{a}}{%unknown%}{%endcomment%}`, ""},
{"{%capture x%}captured{%endcapture%}{{x}}", "captured"},
{`{%capture x%}captured{%endcapture%}{{x}}`, "captured"},
{"{%for a in ar%}{{a}} {%endfor%}", "first second third "},
{"{%for a in ar reversed%}{{a}} {%endfor%}", "third second first "},
{`{%case 1%}{%when 1%}a{%when 2%}b{%endcase%}`, "a"},
{`{%case 2%}{%when 1%}a{%when 2%}b{%endcase%}`, "b"},
{`{%case 3%}{%when 1%}a{%when 2%}b{%endcase%}`, ""},
// {`{%case 2%}{%when 1%}a{%else 2%}b{%endcase%}`, "captured"},
{"{%if true%}true{%endif%}", "true"},
{"{%if false%}false{%endif%}", ""},
{"{%if 0%}true{%endif%}", "true"},
{"{%if 1%}true{%endif%}", "true"},
{"{%if x%}true{%endif%}", "true"},
{"{%if y%}true{%endif%}", ""},
{"{%if true%}true{%endif%}", "true"},
{"{%if false%}false{%endif%}", ""},
{"{%if true%}true{%else%}false{%endif%}", "true"},
{"{%if false%}false{%else%}true{%endif%}", "true"},
{"{%if true%}0{%elsif true%}1{%else%}2{%endif%}", "0"},
{"{%if false%}0{%elsif true%}1{%else%}2{%endif%}", "1"},
{"{%if false%}0{%elsif false%}1{%else%}2{%endif%}", "2"},
{`{%for a in ar%}{{a}} {%endfor%}`, "first second third "},
{`{%for a in ar reversed%}{{a}} {%endfor%}`, "third second first "},
{`{%if true%}true{%endif%}`, "true"},
{`{%if false%}false{%endif%}`, ""},
{`{%if 0%}true{%endif%}`, "true"},
{`{%if 1%}true{%endif%}`, "true"},
{`{%if x%}true{%endif%}`, "true"},
{`{%if y%}true{%endif%}`, ""},
{`{%if true%}true{%endif%}`, "true"},
{`{%if false%}false{%endif%}`, ""},
{`{%if true%}true{%else%}false{%endif%}`, "true"},
{`{%if false%}false{%else%}true{%endif%}`, "true"},
{`{%if true%}0{%elsif true%}1{%else%}2{%endif%}`, "0"},
{`{%if false%}0{%elsif true%}1{%else%}2{%endif%}`, "1"},
{`{%if false%}0{%elsif false%}1{%else%}2{%endif%}`, "2"},
// TODO test whether this requires matching interior tags
{"pre{%raw%}{{a}}{%unknown%}{%endraw%}post", "pre{{a}}{%unknown%}post"},
{"pre{%raw%}{%if false%}anyway-{%endraw%}post", "pre{%if false%}anyway-post"},
{`pre{%raw%}{{a}}{%unknown%}{%endraw%}post`, "pre{{a}}{%unknown%}post"},
{`pre{%raw%}{%if false%}anyway-{%endraw%}post`, "pre{%if false%}anyway-post"},
{"{%unless true%}false{%endunless%}", ""},
{"{%unless false%}true{%endunless%}", "true"},
{"{%unless true%}false{%else%}true{%endunless%}", "true"},
{"{%unless false%}true{%else%}false{%endunless%}", "true"},
{"{%unless false%}0{%elsif true%}1{%else%}2{%endunless%}", "0"},
{"{%unless true%}0{%elsif true%}1{%else%}2{%endunless%}", "1"},
{"{%unless true%}0{%elsif false%}1{%else%}2{%endunless%}", "2"},
{`{%unless true%}false{%endunless%}`, ""},
{`{%unless false%}true{%endunless%}`, "true"},
{`{%unless true%}false{%else%}true{%endunless%}`, "true"},
{`{%unless false%}true{%else%}false{%endunless%}`, "true"},
{`{%unless false%}0{%elsif true%}1{%else%}2{%endunless%}`, "0"},
{`{%unless true%}0{%elsif true%}1{%else%}2{%endunless%}`, "1"},
{`{%unless true%}0{%elsif false%}1{%else%}2{%endunless%}`, "2"},
}
var tagTestContext = chunks.NewContext(map[string]interface{}{