diff --git a/Sources/HummingbirdMustache/Context.swift b/Sources/HummingbirdMustache/Context.swift index 23852e3..9b758ae 100644 --- a/Sources/HummingbirdMustache/Context.swift +++ b/Sources/HummingbirdMustache/Context.swift @@ -18,6 +18,10 @@ struct HBMustacheContext: HBMustacheMethods { return self.last case "index": return self.index + case "even": + return (self.index & 1) == 0 + case "odd": + return (self.index & 1) == 1 default: return nil } diff --git a/Sources/HummingbirdMustache/Method.swift b/Sources/HummingbirdMustache/Method.swift index bb5d785..4bd8705 100644 --- a/Sources/HummingbirdMustache/Method.swift +++ b/Sources/HummingbirdMustache/Method.swift @@ -10,19 +10,39 @@ extension String: HBMustacheMethods { return self.lowercased() case "uppercased": return self.uppercased() + case "reversed": + return self.reversed() default: return nil } } } +protocol HBComparableSequence { + func runComparableMethod(_ name: String) -> Any? +} + extension Array: HBMustacheMethods { func runMethod(_ name: String) -> Any? { switch name { case "reversed": return self.reversed() - case "enumerated": - return self.enumerated() + case "count": + return self.count + default: + if let comparableSeq = self as? HBComparableSequence { + return comparableSeq.runComparableMethod(name) + } + return nil + } + } +} + +extension Array: HBComparableSequence where Element: Comparable { + func runComparableMethod(_ name: String) -> Any? { + switch name { + case "sorted": + return self.sorted() default: return nil } @@ -32,8 +52,24 @@ extension Array: HBMustacheMethods { extension Dictionary: HBMustacheMethods { func runMethod(_ name: String) -> Any? { switch name { + case "count": + return self.count case "enumerated": - return self.enumerated() + return self.map { (key: $0.key, value: $0.value) } + default: + if let comparableSeq = self as? HBComparableSequence { + return comparableSeq.runComparableMethod(name) + } + return nil + } + } +} + +extension Dictionary: HBComparableSequence where Key: Comparable { + func runComparableMethod(_ name: String) -> Any? { + switch name { + case "sorted": + return self.map { (key: $0.key, value: $0.value) }.sorted { $0.key < $1.key } default: return nil } @@ -43,7 +79,7 @@ extension Dictionary: HBMustacheMethods { extension Int: HBMustacheMethods { func runMethod(_ name: String) -> Any? { switch name { - case "plus1": + case "plusone": return self + 1 default: return nil diff --git a/Tests/HummingbirdMustacheTests/MethodTests.swift b/Tests/HummingbirdMustacheTests/MethodTests.swift index ee7730f..505e8e2 100644 --- a/Tests/HummingbirdMustacheTests/MethodTests.swift +++ b/Tests/HummingbirdMustacheTests/MethodTests.swift @@ -26,9 +26,9 @@ final class MethodTests: XCTestCase { """) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] XCTAssertEqual(template.render(object), """ - first: resque - hub - last: rip + first: resque + hub + last: rip """) } @@ -36,7 +36,7 @@ final class MethodTests: XCTestCase { func testIndex() throws { let template = try HBMustacheTemplate(string: """ {{#repo}} - {{#index()}}{{plus1(.)}}) {{/}}{{ name }} + {{#index()}}{{plusone(.)}}{{/}}) {{ name }} {{/repo}} """) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] @@ -48,6 +48,21 @@ final class MethodTests: XCTestCase { """) } + func testEvenOdd() throws { + let template = try HBMustacheTemplate(string: """ + {{#repo}} + {{index()}}) {{#even()}}even {{/}}{{#odd()}}odd {{/}}{{ name }} + {{/repo}} + """) + let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] + XCTAssertEqual(template.render(object), """ + 0) even resque + 1) odd hub + 2) even rip + + """) + } + func testReversed() throws { let template = try HBMustacheTemplate(string: """ {{#reversed(repo)}} @@ -63,10 +78,10 @@ final class MethodTests: XCTestCase { """) } - func testArrayEnumerated() throws { + func testArrayIndex() throws { let template = try HBMustacheTemplate(string: """ - {{#enumerated(repo)}} - {{ offset }}) {{ element.name }} + {{#repo}} + {{ index() }}) {{ name }} {{/repo}} """) let object: [String: Any] = ["repo": [["name": "resque"], ["name": "hub"], ["name": "rip"]]] @@ -78,13 +93,37 @@ final class MethodTests: XCTestCase { """) } + func testArraySorted() throws { + let template = try HBMustacheTemplate(string: """ + {{#sorted(repo)}} + {{ index() }}) {{ . }} + {{/repo}} + """) + let object: [String: Any] = ["repo": ["resque", "hub", "rip"]] + XCTAssertEqual(template.render(object), """ + 0) hub + 1) resque + 2) rip + + """) + } + func testDictionaryEnumerated() throws { let template = try HBMustacheTemplate(string: """ - {{#enumerated(.)}}{{ element.key }} = {{ element.value }}{{/.}} + {{#enumerated(.)}}{{ key }} = {{ value }}{{/.}} """) let object: [String: Any] = ["one": 1, "two": 2] let result = template.render(object) XCTAssertTrue(result == "one = 1two = 2" || result == "two = 2one = 1") } + func testDictionarySortedByKey() throws { + let template = try HBMustacheTemplate(string: """ + {{#sorted(.)}}{{ key }} = {{ value }}{{/.}} + """) + let object: [String: Any] = ["one": 1, "two": 2, "three": 3] + let result = template.render(object) + XCTAssertEqual(result, "one = 1three = 3two = 2") + } + }