diff --git a/Stencil/Node.swift b/Stencil/Node.swift index c0551a9..2aadd47 100644 --- a/Stencil/Node.swift +++ b/Stencil/Node.swift @@ -79,10 +79,13 @@ public class VariableNode : NodeType { public class NowNode : NodeType { public let format:Variable - public class func parse(parser:TokenParser, token:Token) -> NodeType { + public class func parse(parser:TokenParser, token:Token) throws -> NodeType { var format:Variable? let components = token.components() + guard components.count <= 2 else { + throw TemplateSyntaxError("'now' tags may only have one argument: the format string `\(token.contents)`.") + } if components.count == 2 { format = Variable(components[1]) } @@ -91,11 +94,7 @@ public class NowNode : NodeType { } public init(format:Variable?) { - if let format = format { - self.format = format - } else { - self.format = Variable("\"yyyy-MM-dd 'at' HH:mm\"") - } + self.format = format ?? Variable("\"yyyy-MM-dd 'at' HH:mm\"") } public func render(context: Context) throws -> String { @@ -124,33 +123,34 @@ public class ForNode : NodeType { public class func parse(parser:TokenParser, token:Token) throws -> NodeType { let components = token.components() - if components.count == 4 && components[2] == "in" { - let loopVariable = components[1] - let variable = components[3] - - var emptyNodes = [NodeType]() - - let forNodes = try parser.parse(until(["endfor", "empty"])) - - if let token = parser.nextToken() { - if token.contents == "empty" { - emptyNodes = try parser.parse(until(["endfor"])) - parser.nextToken() - } - } else { - throw TemplateSyntaxError("`endfor` was not found.") - } - - return ForNode(variable: variable, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes) + guard components.count == 4 && components[2] == "in" else { + throw TemplateSyntaxError("'for' statements should use the following 'for x in y' `\(token.contents)`.") } - - throw TemplateSyntaxError("'for' statements should use the following 'for x in y' `\(token.contents)`.") + + let loopVariable = components[1] + let variable = components[3] + + var emptyNodes = [NodeType]() + + let forNodes = try parser.parse(until(["endfor", "empty"])) + + guard let token = parser.nextToken() else { + throw TemplateSyntaxError("`endfor` was not found.") + } + + if token.contents == "empty" { + emptyNodes = try parser.parse(until(["endfor"])) + parser.nextToken() + } + + return ForNode(variable: variable, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes) } public init(variable:String, loopVariable:String, nodes:[NodeType], emptyNodes:[NodeType]) { self.variable = Variable(variable) self.loopVariable = loopVariable self.nodes = nodes + // TODO: Handle emptyNodes } public func render(context: Context) throws -> String { @@ -175,39 +175,47 @@ public class IfNode : NodeType { public let falseNodes:[NodeType] public class func parse(parser:TokenParser, token:Token) throws -> NodeType { - let variable = token.components()[1] + let components = token.components() + guard components.count == 2 else { + throw TemplateSyntaxError("'if' statements should use the following 'if condition' `\(token.contents)`.") + } + let variable = components[1] var trueNodes = [NodeType]() var falseNodes = [NodeType]() trueNodes = try parser.parse(until(["endif", "else"])) - if let token = parser.nextToken() { - if token.contents == "else" { - falseNodes = try parser.parse(until(["endif"])) - parser.nextToken() - } - } else { + guard let token = parser.nextToken() else { throw TemplateSyntaxError("`endif` was not found.") } + + if token.contents == "else" { + falseNodes = try parser.parse(until(["endif"])) + parser.nextToken() + } return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes) } public class func parse_ifnot(parser:TokenParser, token:Token) throws -> NodeType { - let variable = token.components()[1] + let components = token.components() + guard components.count == 2 else { + throw TemplateSyntaxError("'ifnot' statements should use the following 'if condition' `\(token.contents)`.") + } + let variable = components[1] var trueNodes = [NodeType]() var falseNodes = [NodeType]() falseNodes = try parser.parse(until(["endif", "else"])) - if let token = parser.nextToken() { - if token.contents == "else" { - trueNodes = try parser.parse(until(["endif"])) - parser.nextToken() - } - } else { + guard let token = parser.nextToken() else { throw TemplateSyntaxError("`endif` was not found.") } + + if token.contents == "else" { + trueNodes = try parser.parse(until(["endif"])) + parser.nextToken() + } return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes) } diff --git a/Stencil/Parser.swift b/Stencil/Parser.swift index 3bcd599..48a975f 100644 --- a/Stencil/Parser.swift +++ b/Stencil/Parser.swift @@ -69,11 +69,9 @@ public class TokenParser { case .Block: let tag = token.components().first - if let parse_until = parse_until { - if parse_until(parser: self, token: token) { + if let parse_until = parse_until where parse_until(parser: self, token: token) { prependToken(token) return nodes - } } if let tag = tag, let parser = self.tags[tag] { diff --git a/Stencil/Template.swift b/Stencil/Template.swift index 605f1ae..e0984ce 100644 --- a/Stencil/Template.swift +++ b/Stencil/Template.swift @@ -9,11 +9,11 @@ public class Template { /// Create a template with the given name inside the given bundle public convenience init(named:String, inBundle bundle:NSBundle? = nil) throws { let useBundle = bundle ?? NSBundle.mainBundle() - if let url = useBundle.URLForResource(named, withExtension: nil) { - try self.init(URL:url) - } else { + guard let url = useBundle.URLForResource(named, withExtension: nil) else { throw NSError(domain: NSCocoaErrorDomain, code: NSFileNoSuchFileError, userInfo: nil) } + + try self.init(URL:url) } /// Create a template with a file found at the given URL diff --git a/Stencil/TemplateLoader/Include.swift b/Stencil/TemplateLoader/Include.swift index 76c1b7e..d9de642 100644 --- a/Stencil/TemplateLoader/Include.swift +++ b/Stencil/TemplateLoader/Include.swift @@ -8,7 +8,7 @@ public class IncludeNode : NodeType { public class func parse(parser:TokenParser, token:Token) throws -> NodeType { let bits = token.contents.componentsSeparatedByString("\"") - if bits.count != 3 { + guard bits.count == 3 else { throw TemplateSyntaxError("'include' tag takes one argument, the template file to be included") } @@ -20,18 +20,16 @@ public class IncludeNode : NodeType { } public func render(context: Context) throws -> String { - if let loader = context["loader"] as? TemplateLoader { - if let template = loader.loadTemplate(templateName) { - return try template.render(context) - } - - let paths:String = loader.paths.map { path in - return path.description - }.joinWithSeparator(", ") - throw TemplateSyntaxError("'\(templateName)' template not found in \(paths)") + guard let loader = context["loader"] as? TemplateLoader else { + throw TemplateSyntaxError("Template loader not in context") } - throw TemplateSyntaxError("Template loader not in context") + guard let template = loader.loadTemplate(templateName) else { + let paths:String = loader.paths.map { $0.description }.joinWithSeparator(", ") + throw TemplateSyntaxError("'\(templateName)' template not found in \(paths)") + } + + return try template.render(context) } } diff --git a/Stencil/TemplateLoader/Inheritence.swift b/Stencil/TemplateLoader/Inheritence.swift index 1edc4c6..8d1e591 100644 --- a/Stencil/TemplateLoader/Inheritence.swift +++ b/Stencil/TemplateLoader/Inheritence.swift @@ -31,12 +31,12 @@ class ExtendsNode : NodeType { class func parse(parser:TokenParser, token:Token) throws -> NodeType { let bits = token.contents.componentsSeparatedByString("\"") - if bits.count != 3 { + guard bits.count == 3 else { throw TemplateSyntaxError("'extends' takes one argument, the template file to be extended") } let parsedNodes = try parser.parse() - if (any(parsedNodes) { ($0 as? ExtendsNode) != nil }) != nil { + guard (any(parsedNodes) { $0 is ExtendsNode }) == nil else { throw TemplateSyntaxError("'extends' cannot appear more than once in the same template") } @@ -58,22 +58,20 @@ class ExtendsNode : NodeType { } func render(context: Context) throws -> String { - if let loader = context["loader"] as? TemplateLoader { - if let template = loader.loadTemplate(templateName) { - let blockContext = BlockContext(blocks: blocks) - context.push([BlockContext.contextKey: blockContext]) - let result = try template.render(context) - context.pop() - return result - } - - let paths:String = loader.paths.map { path in - return path.description - }.joinWithSeparator(", ") + guard let loader = context["loader"] as? TemplateLoader else { + throw TemplateSyntaxError("Template loader not in context") + } + + guard let template = loader.loadTemplate(templateName) else { + let paths:String = loader.paths.map { $0.description }.joinWithSeparator(", ") throw TemplateSyntaxError("'\(templateName)' template not found in \(paths)") } - throw TemplateSyntaxError("Template loader not in context") + let blockContext = BlockContext(blocks: blocks) + context.push([BlockContext.contextKey: blockContext]) + let result = try template.render(context) + context.pop() + return result } } @@ -84,7 +82,7 @@ class BlockNode : NodeType { class func parse(parser:TokenParser, token:Token) throws -> NodeType { let bits = token.components() - if bits.count != 2 { + guard bits.count == 2 else { throw TemplateSyntaxError("'block' tag takes one argument, the template file to be included") }