diff --git a/Sources/HummingbirdMustache/Context.swift b/Sources/HummingbirdMustache/Context.swift index 27744fd..07053f3 100644 --- a/Sources/HummingbirdMustache/Context.swift +++ b/Sources/HummingbirdMustache/Context.swift @@ -1,10 +1,22 @@ -struct HBMustacheContext { - let first: Bool - let last: Bool +struct HBMustacheContext: HBMustacheMethods { + var first: Bool + var last: Bool init(first: Bool = false, last: Bool = false) { self.first = first self.last = last } + + func runMethod(_ name: String) -> Any? { + switch name { + case "first": + return self.first + case "last": + return self.last + default: + return nil + } + } + } diff --git a/Sources/HummingbirdMustache/Sequence.swift b/Sources/HummingbirdMustache/Sequence.swift index ee73da1..dbd6ff5 100644 --- a/Sources/HummingbirdMustache/Sequence.swift +++ b/Sources/HummingbirdMustache/Sequence.swift @@ -7,9 +7,19 @@ protocol HBMustacheSequence { extension Sequence { func renderSection(with template: HBMustacheTemplate) -> String { var string = "" - for obj in self { - string += template.render(obj) + var context = HBMustacheContext(first: true) + var iterator = self.makeIterator() + guard var currentObject = iterator.next() else { return "" } + + while let object = iterator.next() { + string += template.render(currentObject, context: context) + currentObject = object + context.first = false } + + context.last = true + string += template.render(currentObject, context: context) + return string } diff --git a/Sources/HummingbirdMustache/Template+Render.swift b/Sources/HummingbirdMustache/Template+Render.swift index 7854828..5499e1f 100644 --- a/Sources/HummingbirdMustache/Template+Render.swift +++ b/Sources/HummingbirdMustache/Template+Render.swift @@ -7,7 +7,7 @@ extension HBMustacheTemplate { case .text(let text): string += text case .variable(let variable, let method): - if let child = getChild(named: variable, from: object, method: method) { + if let child = getChild(named: variable, from: object, method: method, context: context) { if let template = child as? HBMustacheTemplate { string += template.render(object) } else { @@ -15,15 +15,15 @@ extension HBMustacheTemplate { } } case .unescapedVariable(let variable, let method): - if let child = getChild(named: variable, from: object, method: method) { + if let child = getChild(named: variable, from: object, method: method, context: context) { string += String(describing: child) } case .section(let variable, let method, let template): - let child = getChild(named: variable, from: object, method: method) + let child = getChild(named: variable, from: object, method: method, context: context) string += renderSection(child, parent: object, with: template) case .invertedSection(let variable, let method, let template): - let child = getChild(named: variable, from: object, method: method) + let child = getChild(named: variable, from: object, method: method, context: context) string += renderInvertedSection(child, parent: object, with: template) case .partial(let name): @@ -63,7 +63,7 @@ extension HBMustacheTemplate { } } - func getChild(named name: String, from object: Any, method: String?) -> Any? { + func getChild(named name: String, from object: Any, method: String?, context: HBMustacheContext?) -> Any? { func _getChild(named names: ArraySlice, from object: Any) -> Any? { guard let name = names.first else { return object } let childObject: Any? @@ -81,6 +81,8 @@ extension HBMustacheTemplate { let child: Any? if name == "." { child = object + } else if name == "", method != nil { + child = context } else { let nameSplit = name.split(separator: ".").map { String($0) } child = _getChild(named: nameSplit[...], from: object) diff --git a/Tests/HummingbirdMustacheTests/MethodTests.swift b/Tests/HummingbirdMustacheTests/MethodTests.swift index 9255ffd..549f56f 100644 --- a/Tests/HummingbirdMustacheTests/MethodTests.swift +++ b/Tests/HummingbirdMustacheTests/MethodTests.swift @@ -18,6 +18,21 @@ final class MethodTests: XCTestCase { XCTAssertEqual(template.render(object), "TEST") } + func testFirstLast() throws { + let template = try HBMustacheTemplate(string: """ + {{#repo}} + {{#first()}}first: {{/}}{{#last()}}last: {{/}}{{ name }} + {{/repo}} + """) + let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] + XCTAssertEqual(template.render(object), """ + first: resque + hub + last: rip + + """) + } + func testReversed() throws { let template = try HBMustacheTemplate(string: """ {{#reversed(repo)}} diff --git a/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift b/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift index c8f3ea3..360f8a9 100644 --- a/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift +++ b/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift @@ -25,6 +25,7 @@ final class TemplateRendererTests: XCTestCase { func testArraySection() throws { let template = try HBMustacheTemplate(string: "test {{#value}}*{{.}}{{/value}}") XCTAssertEqual(template.render(["value": ["test2", "bool"]]), "test *test2*bool") + XCTAssertEqual(template.render(["value": ["test2"]]), "test *test2") XCTAssertEqual(template.render(["value": []]), "test ") }