From dc8759ba34c763457c5ca7b648b24e5058773e29 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 3 Mar 2017 09:56:41 +0000 Subject: [PATCH] feat(if): Support `elif` tags --- CHANGELOG.md | 17 ++++++ Sources/IfTag.swift | 27 ++++++--- Tests/StencilTests/IfNodeSpec.swift | 94 +++++++++++++++++++++++++++++ docs/builtins.rst | 8 ++- 4 files changed, 135 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2945898..de58a4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Stencil Changelog +## Master + +### Enhancements + +- `if` blocks may now contain else if (`elif`) conditions. + + ```html+django + {% if one or two and not three %} + one or two but not three + {% elif four %} + four + {% else %} + not one, two, or four + {% endif %} + ``` + + ## 0.8.0 ### Breaking diff --git a/Sources/IfTag.swift b/Sources/IfTag.swift index 02097ee..16c926d 100644 --- a/Sources/IfTag.swift +++ b/Sources/IfTag.swift @@ -186,19 +186,30 @@ class IfNode : NodeType { var components = token.components() components.removeFirst() - var conditions: [IfCondition] = [] - let expression = try parseExpression(components: components, tokenParser: parser) - let nodes = try parser.parse(until(["endif", "else"])) - conditions.append(IfCondition(expression: expression, nodes: nodes)) + let nodes = try parser.parse(until(["endif", "elif", "else"])) + var conditions: [IfCondition] = [ + IfCondition(expression: expression, nodes: nodes) + ] - guard let token = parser.nextToken() else { - throw TemplateSyntaxError("`endif` was not found.") + var token = parser.nextToken() + while let current = token, current.contents.hasPrefix("elif") { + var components = current.components() + components.removeFirst() + let expression = try parseExpression(components: components, tokenParser: parser) + + let nodes = try parser.parse(until(["endif", "elif", "else"])) + token = parser.nextToken() + conditions.append(IfCondition(expression: expression, nodes: nodes)) } - if token.contents == "else" { + if let current = token, current.contents == "else" { conditions.append(IfCondition(expression: nil, nodes: try parser.parse(until(["endif"])))) - _ = parser.nextToken() + token = parser.nextToken() + } + + guard let current = token, current.contents == "endif" else { + throw TemplateSyntaxError("`endif` was not found.") } return IfNode(conditions: conditions) diff --git a/Tests/StencilTests/IfNodeSpec.swift b/Tests/StencilTests/IfNodeSpec.swift index b5a7112..f174b6a 100644 --- a/Tests/StencilTests/IfNodeSpec.swift +++ b/Tests/StencilTests/IfNodeSpec.swift @@ -48,6 +48,100 @@ func testIfNode() { try expect(falseNode?.text) == "false" } + $0.it("can parse an if with elif block") { + let tokens: [Token] = [ + .block(value: "if value"), + .text(value: "true"), + .block(value: "elif something"), + .text(value: "some"), + .block(value: "else"), + .text(value: "false"), + .block(value: "endif") + ] + + let parser = TokenParser(tokens: tokens, environment: Environment()) + let nodes = try parser.parse() + let node = nodes.first as? IfNode + + let conditions = node?.conditions + try expect(conditions?.count) == 3 + + try expect(conditions?[0].nodes.count) == 1 + let trueNode = conditions?[0].nodes.first as? TextNode + try expect(trueNode?.text) == "true" + + try expect(conditions?[1].nodes.count) == 1 + let elifNode = conditions?[1].nodes.first as? TextNode + try expect(elifNode?.text) == "some" + + try expect(conditions?[2].nodes.count) == 1 + let falseNode = conditions?[2].nodes.first as? TextNode + try expect(falseNode?.text) == "false" + } + + $0.it("can parse an if with elif block without else") { + let tokens: [Token] = [ + .block(value: "if value"), + .text(value: "true"), + .block(value: "elif something"), + .text(value: "some"), + .block(value: "endif") + ] + + let parser = TokenParser(tokens: tokens, environment: Environment()) + let nodes = try parser.parse() + let node = nodes.first as? IfNode + + let conditions = node?.conditions + try expect(conditions?.count) == 2 + + try expect(conditions?[0].nodes.count) == 1 + let trueNode = conditions?[0].nodes.first as? TextNode + try expect(trueNode?.text) == "true" + + try expect(conditions?[1].nodes.count) == 1 + let elifNode = conditions?[1].nodes.first as? TextNode + try expect(elifNode?.text) == "some" + } + + $0.it("can parse an if with multiple elif block") { + let tokens: [Token] = [ + .block(value: "if value"), + .text(value: "true"), + .block(value: "elif something1"), + .text(value: "some1"), + .block(value: "elif something2"), + .text(value: "some2"), + .block(value: "else"), + .text(value: "false"), + .block(value: "endif") + ] + + let parser = TokenParser(tokens: tokens, environment: Environment()) + let nodes = try parser.parse() + let node = nodes.first as? IfNode + + let conditions = node?.conditions + try expect(conditions?.count) == 4 + + try expect(conditions?[0].nodes.count) == 1 + let trueNode = conditions?[0].nodes.first as? TextNode + try expect(trueNode?.text) == "true" + + try expect(conditions?[1].nodes.count) == 1 + let elifNode = conditions?[1].nodes.first as? TextNode + try expect(elifNode?.text) == "some1" + + try expect(conditions?[2].nodes.count) == 1 + let elif2Node = conditions?[2].nodes.first as? TextNode + try expect(elif2Node?.text) == "some2" + + try expect(conditions?[3].nodes.count) == 1 + let falseNode = conditions?[3].nodes.first as? TextNode + try expect(falseNode?.text) == "false" + } + + $0.it("can parse an if with complex expression") { let tokens: [Token] = [ .block(value: "if value == \"test\" and not name"), diff --git a/docs/builtins.rst b/docs/builtins.rst index b4657c8..424c4ec 100644 --- a/docs/builtins.rst +++ b/docs/builtins.rst @@ -52,10 +52,12 @@ true the contents of the block are processed. Being true is defined as: .. code-block:: html+django - {% if variable %} - The variable was found in the current context. + {% if admin %} + The user is an administrator. + {% elif user %} + A user is logged in. {% else %} - The variable was not found. + No user was found. {% endif %} Operators