diff --git a/Sources/HummingbirdMustache/Lambda.swift b/Sources/HummingbirdMustache/Lambda.swift index e3dee97..5bb3e3f 100644 --- a/Sources/HummingbirdMustache/Lambda.swift +++ b/Sources/HummingbirdMustache/Lambda.swift @@ -1,2 +1,2 @@ -public typealias HBMustacheLambda = (Any, HBMustacheTemplate, HBMustacheLibrary?) -> String +public typealias HBMustacheLambda = (Any, HBMustacheTemplate) -> String diff --git a/Sources/HummingbirdMustache/Library.swift b/Sources/HummingbirdMustache/Library.swift index 6f4970c..c97e232 100644 --- a/Sources/HummingbirdMustache/Library.swift +++ b/Sources/HummingbirdMustache/Library.swift @@ -10,6 +10,7 @@ public class HBMustacheLibrary { } public func register(_ template: HBMustacheTemplate, named name: String) { + template.setLibrary(self) templates[name] = template } @@ -19,7 +20,7 @@ public class HBMustacheLibrary { public func render(_ object: Any, withTemplateNamed name: String) -> String? { guard let template = templates[name] else { return nil } - return template.render(object, library: self) + return template.render(object) } private var templates: [String: HBMustacheTemplate] diff --git a/Sources/HummingbirdMustache/Template+Render.swift b/Sources/HummingbirdMustache/Template+Render.swift index a20d9c8..3d5be7a 100644 --- a/Sources/HummingbirdMustache/Template+Render.swift +++ b/Sources/HummingbirdMustache/Template+Render.swift @@ -1,6 +1,6 @@ extension HBMustacheTemplate { - func render(_ object: Any, library: HBMustacheLibrary? = nil, context: HBMustacheContext? = nil) -> String { + func render(_ object: Any, context: HBMustacheContext? = nil) -> String { var string = "" for token in tokens { switch token { @@ -9,7 +9,7 @@ extension HBMustacheTemplate { case .variable(let variable, let method): if let child = getChild(named: variable, from: object, method: method) { if let template = child as? HBMustacheTemplate { - string += template.render(object, library: library) + string += template.render(object) } else { string += htmlEscape(String(describing: child)) } @@ -20,11 +20,11 @@ extension HBMustacheTemplate { } case .section(let variable, let method, let template): let child = getChild(named: variable, from: object, method: method) - string += renderSection(child, parent: object, with: template, library: library) + string += renderSection(child, parent: object, with: template) case .invertedSection(let variable, let method, let template): let child = getChild(named: variable, from: object, method: method) - string += renderInvertedSection(child, parent: object, with: template, library: library) + string += renderInvertedSection(child, parent: object, with: template) case .partial(let name): if let text = library?.render(object, withTemplateNamed: name) { @@ -35,31 +35,31 @@ extension HBMustacheTemplate { return string } - func renderSection(_ child: Any?, parent: Any, with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderSection(_ child: Any?, parent: Any, with template: HBMustacheTemplate) -> String { switch child { case let array as HBSequence: - return array.renderSection(with: template, library: library) + return array.renderSection(with: template) case let bool as Bool: - return bool ? template.render(parent, library: library) : "" + return bool ? template.render(parent) : "" case let lambda as HBMustacheLambda: - return lambda(parent, template, library) + return lambda(parent, template) case .some(let value): - return template.render(value, library: library) + return template.render(value) case .none: return "" } } - func renderInvertedSection(_ child: Any?, parent: Any, with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderInvertedSection(_ child: Any?, parent: Any, with template: HBMustacheTemplate) -> String { switch child { case let array as HBSequence: - return array.renderInvertedSection(with: template, library: library) + return array.renderInvertedSection(with: template) case let bool as Bool: - return bool ? "" : template.render(parent, library: library) + return bool ? "" : template.render(parent) case .some: return "" case .none: - return template.render(parent, library: library) + return template.render(parent) } } @@ -127,56 +127,56 @@ extension Dictionary: HBMustacheParent where Key == String { } protocol HBSequence { - func renderSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String - func renderInvertedSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String + func renderSection(with template: HBMustacheTemplate) -> String + func renderInvertedSection(with template: HBMustacheTemplate) -> String } extension Array: HBSequence { - func renderSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderSection(with template: HBMustacheTemplate) -> String { var string = "" for obj in self { - string += template.render(obj, library: library) + string += template.render(obj) } return string } - func renderInvertedSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderInvertedSection(with template: HBMustacheTemplate) -> String { if count == 0 { - return template.render(self, library: library) + return template.render(self) } return "" } } extension ReversedCollection: HBSequence { - func renderSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderSection(with template: HBMustacheTemplate) -> String { var string = "" for obj in self { - string += template.render(obj, library: library) + string += template.render(obj) } return string } - func renderInvertedSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderInvertedSection(with template: HBMustacheTemplate) -> String { if count == 0 { - return template.render(self, library: library) + return template.render(self) } return "" } } extension EnumeratedSequence: HBSequence { - func renderSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderSection(with template: HBMustacheTemplate) -> String { var string = "" for obj in self { - string += template.render(obj, library: library) + string += template.render(obj) } return string } - func renderInvertedSection(with template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { + func renderInvertedSection(with template: HBMustacheTemplate) -> String { if self.underestimatedCount == 0 { - return template.render(self, library: library) + return template.render(self) } return "" } diff --git a/Sources/HummingbirdMustache/Template.swift b/Sources/HummingbirdMustache/Template.swift index 762495e..3c8cf1e 100644 --- a/Sources/HummingbirdMustache/Template.swift +++ b/Sources/HummingbirdMustache/Template.swift @@ -8,8 +8,20 @@ public class HBMustacheTemplate { self.tokens = tokens } - public func render(_ object: Any, library: HBMustacheLibrary? = nil) -> String { - self.render(object, library: library, context: nil) + public func render(_ object: Any) -> String { + self.render(object, context: nil) + } + + internal func setLibrary(_ library: HBMustacheLibrary) { + self.library = library + for token in tokens { + switch token { + case .section(_, _, let template), .invertedSection(_, _, let template): + template.setLibrary(library) + default: + break + } + } } enum Token { @@ -22,5 +34,6 @@ public class HBMustacheTemplate { } let tokens: [Token] + var library: HBMustacheLibrary? } diff --git a/Tests/HummingbirdMustacheTests/LibraryTests.swift b/Tests/HummingbirdMustacheTests/LibraryTests.swift index efa30d4..b94bfef 100644 --- a/Tests/HummingbirdMustacheTests/LibraryTests.swift +++ b/Tests/HummingbirdMustacheTests/LibraryTests.swift @@ -4,7 +4,7 @@ import XCTest final class LibraryTests: XCTestCase { func testDirectoryLoad() throws { let fs = FileManager() - try fs.createDirectory(atPath: "./templates", withIntermediateDirectories: false) + try fs.createDirectory(atPath: "templates", withIntermediateDirectories: false) let mustache = "{{#value}}{{.}}{{/value}}" let data = Data(mustache.utf8) defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates")) } diff --git a/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift b/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift index 35283f4..c8f3ea3 100644 --- a/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift +++ b/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift @@ -91,6 +91,7 @@ final class TemplateRendererTests: XCTestCase { XCTAssertEqual(template.render(Test(test: .init(string: "sub"))), "test sub") } + /// variables func testMustacheManualExample1() throws { let template = try HBMustacheTemplate(string: """ Hello {{name}} @@ -108,6 +109,7 @@ final class TemplateRendererTests: XCTestCase { """) } + /// test esacped and unescaped text func testMustacheManualExample2() throws { let template = try HBMustacheTemplate(string: """ *{{name}} @@ -124,6 +126,7 @@ final class TemplateRendererTests: XCTestCase { """) } + /// test boolean func testMustacheManualExample3() throws { let template = try HBMustacheTemplate(string: """ Shown. @@ -138,6 +141,7 @@ final class TemplateRendererTests: XCTestCase { """) } + /// test non-empty lists func testMustacheManualExample4() throws { let template = try HBMustacheTemplate(string: """ {{#repo}} @@ -153,12 +157,13 @@ final class TemplateRendererTests: XCTestCase { """) } + /// test lambdas func testMustacheManualExample5() throws { let template = try HBMustacheTemplate(string: """ {{#wrapped}}{{name}} is awesome.{{/wrapped}} """) - func wrapped(object: Any, template: HBMustacheTemplate, library: HBMustacheLibrary?) -> String { - return "\(template.render(object, library: library))" + func wrapped(object: Any, template: HBMustacheTemplate) -> String { + return "\(template.render(object))" } let object: [String: Any] = ["name": "Willy", "wrapped": wrapped] XCTAssertEqual(template.render(object), """ @@ -166,6 +171,7 @@ final class TemplateRendererTests: XCTestCase { """) } + /// test setting context object func testMustacheManualExample6() throws { let template = try HBMustacheTemplate(string: """ {{#person?}} @@ -179,6 +185,7 @@ final class TemplateRendererTests: XCTestCase { """) } + /// test inverted sections func testMustacheManualExample7() throws { let template = try HBMustacheTemplate(string: """ {{#repo}} @@ -195,6 +202,7 @@ final class TemplateRendererTests: XCTestCase { """) } + /// test comments func testMustacheManualExample8() throws { let template = try HBMustacheTemplate(string: """

Today{{! ignore me }}.