From 9b17bd6827dd85ffb6867ae419cfc525f335063e Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Thu, 18 Mar 2021 10:55:55 +0000 Subject: [PATCH] Render optimisation --- .../HummingbirdMustache/Template+Parser.swift | 6 -- .../HummingbirdMustache/Template+Render.swift | 76 +++++++++++-------- .../HummingbirdMustacheTests/SpecTests.swift | 4 +- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/Sources/HummingbirdMustache/Template+Parser.swift b/Sources/HummingbirdMustache/Template+Parser.swift index 0910d1f..acdf964 100644 --- a/Sources/HummingbirdMustache/Template+Parser.swift +++ b/Sources/HummingbirdMustache/Template+Parser.swift @@ -143,12 +143,6 @@ extension HBMustacheTemplate { // partial parser.unsafeAdvance() let (name, _) = try parseName(&parser) - /* if newLine && hasLineFinished(&parser) { - setNewLine = true - if parser.current() == "\n" { - parser.unsafeAdvance() - } - } */ if whiteSpaceBefore.count > 0 { tokens.append(.text(whiteSpaceBefore)) } diff --git a/Sources/HummingbirdMustache/Template+Render.swift b/Sources/HummingbirdMustache/Template+Render.swift index 2bbe212..6f5b006 100644 --- a/Sources/HummingbirdMustache/Template+Render.swift +++ b/Sources/HummingbirdMustache/Template+Render.swift @@ -2,47 +2,59 @@ extension HBMustacheTemplate { /// Render template using object /// - Parameters: - /// - object: Object + /// - stack: Object /// - context: Context that render is occurring in. Contains information about position in sequence + /// - indentation: indentation of partial /// - Returns: Rendered text - func render(_ object: [Any], context: HBMustacheContext? = nil, indentation: String? = nil) -> String { + func render(_ stack: [Any], context: HBMustacheContext? = nil, indentation: String? = nil) -> String { var string = "" - for token in tokens { - if let indentation = indentation, string.last == "\n" { - string += indentation + if let indentation = indentation { + for token in tokens { + if string.last == "\n" { + string += indentation + } + string += renderToken(token, stack: stack, context: context) } - switch token { - case let .text(text): - string += text - case let .variable(variable, method): - if let child = getChild(named: variable, from: object, method: method, context: context) { - if let template = child as? HBMustacheTemplate { - string += template.render(object) - } else { - string += String(describing: child).htmlEscape() - } - } - case let .unescapedVariable(variable, method): - if let child = getChild(named: variable, from: object, method: method, context: context) { - string += String(describing: child) - } - case let .section(variable, method, template): - let child = getChild(named: variable, from: object, method: method, context: context) - string += renderSection(child, stack: object, with: template) - - case let .invertedSection(variable, method, template): - let child = getChild(named: variable, from: object, method: method, context: context) - string += renderInvertedSection(child, stack: object, with: template) - - case let .partial(name, indentation): - if let template = library?.getTemplate(named: name) { - string += template.render(object, indentation: indentation) - } + } else { + for token in tokens { + string += renderToken(token, stack: stack, context: context) } } return string } + func renderToken(_ token: Token, stack: [Any], context: HBMustacheContext? = nil) -> String { + switch token { + case let .text(text): + return text + case let .variable(variable, method): + if let child = getChild(named: variable, from: stack, method: method, context: context) { + if let template = child as? HBMustacheTemplate { + return template.render(stack) + } else { + return String(describing: child).htmlEscape() + } + } + case let .unescapedVariable(variable, method): + if let child = getChild(named: variable, from: stack, method: method, context: context) { + return String(describing: child) + } + case let .section(variable, method, template): + let child = getChild(named: variable, from: stack, method: method, context: context) + return renderSection(child, stack: stack, with: template) + + case let .invertedSection(variable, method, template): + let child = getChild(named: variable, from: stack, method: method, context: context) + return renderInvertedSection(child, stack: stack, with: template) + + case let .partial(name, indentation): + if let template = library?.getTemplate(named: name) { + return template.render(stack, indentation: indentation) + } + } + return "" + } + /// Render a section /// - Parameters: /// - child: Object to render section for diff --git a/Tests/HummingbirdMustacheTests/SpecTests.swift b/Tests/HummingbirdMustacheTests/SpecTests.swift index c487390..dcf847c 100644 --- a/Tests/HummingbirdMustacheTests/SpecTests.swift +++ b/Tests/HummingbirdMustacheTests/SpecTests.swift @@ -661,8 +661,8 @@ final class SpecSectionTests: XCTestCase { func testVariables() throws { let object: [String: Any] = ["foo": "bar"] - let template = #""{{#foo}} {{.}} is {{foo}} {{/foo}}""# - let expected = #"" bar is bar ""# + let template = #""{{#foo}}{{.}} is {{foo}}{{/foo}}""# + let expected = #""bar is bar""# try test(object, template, expected) }