Add support for Set Delimiters (#5)
* Added ParserState * Add support for setting delimiters * Add spec tests for setting delimiters * swift format
This commit is contained in:
@@ -4,52 +4,73 @@ extension HBMustacheTemplate {
|
|||||||
case sectionCloseNameIncorrect
|
case sectionCloseNameIncorrect
|
||||||
case unfinishedName
|
case unfinishedName
|
||||||
case expectedSectionEnd
|
case expectedSectionEnd
|
||||||
|
case invalidSetDelimiter
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParserState {
|
||||||
|
var sectionName: String?
|
||||||
|
var newLine: Bool
|
||||||
|
var startDelimiter: String
|
||||||
|
var endDelimiter: String
|
||||||
|
|
||||||
|
init() {
|
||||||
|
sectionName = nil
|
||||||
|
newLine = true
|
||||||
|
startDelimiter = "{{"
|
||||||
|
endDelimiter = "}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
func withSectionName(_ name: String) -> ParserState {
|
||||||
|
var newValue = self
|
||||||
|
newValue.sectionName = name
|
||||||
|
return newValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func withDelimiters(start: String, end: String) -> ParserState {
|
||||||
|
var newValue = self
|
||||||
|
newValue.startDelimiter = start
|
||||||
|
newValue.endDelimiter = end
|
||||||
|
return newValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func withDefaultDelimiters(start _: String, end _: String) -> ParserState {
|
||||||
|
var newValue = self
|
||||||
|
newValue.startDelimiter = "{{"
|
||||||
|
newValue.endDelimiter = "}}"
|
||||||
|
return newValue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parse mustache text to generate a list of tokens
|
/// parse mustache text to generate a list of tokens
|
||||||
static func parse(_ string: String) throws -> [Token] {
|
static func parse(_ string: String) throws -> [Token] {
|
||||||
var parser = HBParser(string)
|
var parser = HBParser(string)
|
||||||
return try parse(&parser, sectionName: nil)
|
return try parse(&parser, state: .init())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parse section in mustache text
|
/// parse section in mustache text
|
||||||
static func parse(_ parser: inout HBParser, sectionName: String?, newLine: Bool = true) throws -> [Token] {
|
static func parse(_ parser: inout HBParser, state: ParserState) throws -> [Token] {
|
||||||
var tokens: [Token] = []
|
var tokens: [Token] = []
|
||||||
var newLine = newLine
|
var state = state
|
||||||
var whiteSpaceBefore: String = ""
|
var whiteSpaceBefore: String = ""
|
||||||
while !parser.reachedEnd() {
|
while !parser.reachedEnd() {
|
||||||
// if new line read whitespace
|
// if new line read whitespace
|
||||||
if newLine {
|
if state.newLine {
|
||||||
whiteSpaceBefore = parser.read(while: Set(" \t")).string
|
whiteSpaceBefore = parser.read(while: Set(" \t")).string
|
||||||
}
|
}
|
||||||
// read until we hit either a newline or "{"
|
let text = try readUntilDelimiterOrNewline(&parser, state: state)
|
||||||
let text = try parser.read(until: Set("{\n"), throwOnOverflow: false)
|
// if we hit a newline add text
|
||||||
// if new line append all text read plus newline
|
|
||||||
if parser.current() == "\n" {
|
if parser.current() == "\n" {
|
||||||
tokens.append(.text(whiteSpaceBefore + text.string + "\n"))
|
tokens.append(.text(whiteSpaceBefore + text + "\n"))
|
||||||
newLine = true
|
state.newLine = true
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
continue
|
continue
|
||||||
} else if parser.current() == "{" {
|
}
|
||||||
parser.unsafeAdvance()
|
// we have found a tag
|
||||||
// if next character is not "{" then is normal text
|
// whatever text we found before the tag should be added as a token
|
||||||
if parser.current() != "{" {
|
|
||||||
if text.count > 0 {
|
if text.count > 0 {
|
||||||
tokens.append(.text(whiteSpaceBefore + text.string + "{"))
|
tokens.append(.text(whiteSpaceBefore + text))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
newLine = false
|
state.newLine = false
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
parser.unsafeAdvance()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// whatever text we found before the "{{" should be added
|
|
||||||
if text.count > 0 {
|
|
||||||
tokens.append(.text(whiteSpaceBefore + text.string))
|
|
||||||
whiteSpaceBefore = ""
|
|
||||||
newLine = false
|
|
||||||
}
|
}
|
||||||
// have we reached the end of the text
|
// have we reached the end of the text
|
||||||
if parser.reachedEnd() {
|
if parser.reachedEnd() {
|
||||||
@@ -60,8 +81,8 @@ extension HBMustacheTemplate {
|
|||||||
case "#":
|
case "#":
|
||||||
// section
|
// section
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser)
|
let (name, method) = try parseName(&parser, state: state)
|
||||||
if newLine, hasLineFinished(&parser) {
|
if state.newLine, hasLineFinished(&parser) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
if parser.current() == "\n" {
|
if parser.current() == "\n" {
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
@@ -70,14 +91,14 @@ extension HBMustacheTemplate {
|
|||||||
tokens.append(.text(whiteSpaceBefore))
|
tokens.append(.text(whiteSpaceBefore))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, sectionName: name, newLine: newLine)
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name))
|
||||||
tokens.append(.section(name: name, method: method, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.section(name: name, method: method, template: HBMustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "^":
|
case "^":
|
||||||
// inverted section
|
// inverted section
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser)
|
let (name, method) = try parseName(&parser, state: state)
|
||||||
if newLine, hasLineFinished(&parser) {
|
if state.newLine, hasLineFinished(&parser) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
if parser.current() == "\n" {
|
if parser.current() == "\n" {
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
@@ -86,17 +107,17 @@ extension HBMustacheTemplate {
|
|||||||
tokens.append(.text(whiteSpaceBefore))
|
tokens.append(.text(whiteSpaceBefore))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, sectionName: name, newLine: newLine)
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name))
|
||||||
tokens.append(.invertedSection(name: name, method: method, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.invertedSection(name: name, method: method, template: HBMustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "/":
|
case "/":
|
||||||
// end of section
|
// end of section
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, _) = try parseName(&parser)
|
let (name, _) = try parseName(&parser, state: state)
|
||||||
guard name == sectionName else {
|
guard name == state.sectionName else {
|
||||||
throw Error.sectionCloseNameIncorrect
|
throw Error.sectionCloseNameIncorrect
|
||||||
}
|
}
|
||||||
if newLine, hasLineFinished(&parser) {
|
if state.newLine, hasLineFinished(&parser) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
if parser.current() == "\n" {
|
if parser.current() == "\n" {
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
@@ -110,8 +131,8 @@ extension HBMustacheTemplate {
|
|||||||
case "!":
|
case "!":
|
||||||
// comment
|
// comment
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
_ = try parseComment(&parser)
|
_ = try parseComment(&parser, state: state)
|
||||||
if newLine, hasLineFinished(&parser) {
|
if state.newLine, hasLineFinished(&parser) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
if !parser.reachedEnd() {
|
if !parser.reachedEnd() {
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
@@ -125,7 +146,7 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser)
|
let (name, method) = try parseName(&parser, state: state)
|
||||||
guard try parser.read("}") else { throw Error.unfinishedName }
|
guard try parser.read("}") else { throw Error.unfinishedName }
|
||||||
tokens.append(.unescapedVariable(name: name, method: method))
|
tokens.append(.unescapedVariable(name: name, method: method))
|
||||||
|
|
||||||
@@ -136,17 +157,17 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser)
|
let (name, method) = try parseName(&parser, state: state)
|
||||||
tokens.append(.unescapedVariable(name: name, method: method))
|
tokens.append(.unescapedVariable(name: name, method: method))
|
||||||
|
|
||||||
case ">":
|
case ">":
|
||||||
// partial
|
// partial
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, _) = try parseName(&parser)
|
let (name, _) = try parseName(&parser, state: state)
|
||||||
if whiteSpaceBefore.count > 0 {
|
if whiteSpaceBefore.count > 0 {
|
||||||
tokens.append(.text(whiteSpaceBefore))
|
tokens.append(.text(whiteSpaceBefore))
|
||||||
}
|
}
|
||||||
if newLine, hasLineFinished(&parser) {
|
if state.newLine, hasLineFinished(&parser) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
if parser.current() == "\n" {
|
if parser.current() == "\n" {
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
@@ -157,30 +178,68 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
|
|
||||||
|
case "=":
|
||||||
|
// set delimiter
|
||||||
|
parser.unsafeAdvance()
|
||||||
|
state = try parserSetDelimiter(&parser, state: state)
|
||||||
|
if state.newLine, hasLineFinished(&parser) {
|
||||||
|
setNewLine = true
|
||||||
|
if !parser.reachedEnd() {
|
||||||
|
parser.unsafeAdvance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// variable
|
// variable
|
||||||
if whiteSpaceBefore.count > 0 {
|
if whiteSpaceBefore.count > 0 {
|
||||||
tokens.append(.text(whiteSpaceBefore))
|
tokens.append(.text(whiteSpaceBefore))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let (name, method) = try parseName(&parser)
|
let (name, method) = try parseName(&parser, state: state)
|
||||||
tokens.append(.variable(name: name, method: method))
|
tokens.append(.variable(name: name, method: method))
|
||||||
}
|
}
|
||||||
newLine = setNewLine
|
state.newLine = setNewLine
|
||||||
}
|
}
|
||||||
// should never get here if reading section
|
// should never get here if reading section
|
||||||
guard sectionName == nil else {
|
guard state.sectionName == nil else {
|
||||||
throw Error.expectedSectionEnd
|
throw Error.expectedSectionEnd
|
||||||
}
|
}
|
||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// read until we hit either the start delimiter of a tag or a newline
|
||||||
|
static func readUntilDelimiterOrNewline(_ parser: inout HBParser, state: ParserState) throws -> String {
|
||||||
|
var untilSet = Set("\n")
|
||||||
|
guard let delimiterFirstChar = state.startDelimiter.first,
|
||||||
|
let delimiterFirstScalar = delimiterFirstChar.unicodeScalars.first else { return "" }
|
||||||
|
var totalText = ""
|
||||||
|
untilSet.insert(delimiterFirstScalar)
|
||||||
|
|
||||||
|
while !parser.reachedEnd() {
|
||||||
|
// read until we hit either a newline or "{"
|
||||||
|
let text = try parser.read(until: untilSet, throwOnOverflow: false).string
|
||||||
|
totalText += text
|
||||||
|
// if new line append all text read plus newline
|
||||||
|
if parser.current() == "\n" {
|
||||||
|
break
|
||||||
|
} else if parser.current() == delimiterFirstScalar {
|
||||||
|
if try parser.read(state.startDelimiter) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
totalText += String(delimiterFirstScalar)
|
||||||
|
parser.unsafeAdvance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalText
|
||||||
|
}
|
||||||
|
|
||||||
/// parse variable name
|
/// parse variable name
|
||||||
static func parseName(_ parser: inout HBParser) throws -> (String, String?) {
|
static func parseName(_ parser: inout HBParser, state: ParserState) throws -> (String, String?) {
|
||||||
parser.read(while: \.isWhitespace)
|
parser.read(while: \.isWhitespace)
|
||||||
var text = parser.read(while: sectionNameChars)
|
var text = parser.read(while: sectionNameChars)
|
||||||
parser.read(while: \.isWhitespace)
|
parser.read(while: \.isWhitespace)
|
||||||
guard try parser.read("}"), try parser.read("}") else { throw Error.unfinishedName }
|
guard try parser.read(state.endDelimiter) else { throw Error.unfinishedName }
|
||||||
|
|
||||||
// does the name include brackets. If so this is a method call
|
// does the name include brackets. If so this is a method call
|
||||||
let string = text.read(while: sectionNameCharsWithoutBrackets)
|
let string = text.read(while: sectionNameCharsWithoutBrackets)
|
||||||
if text.reachedEnd() {
|
if text.reachedEnd() {
|
||||||
@@ -197,11 +256,23 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func parseComment(_ parser: inout HBParser) throws -> String {
|
static func parseComment(_ parser: inout HBParser, state: ParserState) throws -> String {
|
||||||
let text = try parser.read(untilString: "}}", throwOnOverflow: true, skipToEnd: true)
|
let text = try parser.read(untilString: state.endDelimiter, throwOnOverflow: true, skipToEnd: true)
|
||||||
return text.string
|
return text.string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func parserSetDelimiter(_ parser: inout HBParser, state: ParserState) throws -> ParserState {
|
||||||
|
parser.read(while: \.isWhitespace)
|
||||||
|
let startDelimiter = try parser.read(until: \.isWhitespace).string
|
||||||
|
parser.read(while: \.isWhitespace)
|
||||||
|
let endDelimiter = try parser.read(until: { $0 == "=" || $0.isWhitespace }).string
|
||||||
|
parser.read(while: \.isWhitespace)
|
||||||
|
guard try parser.read("=") else { throw Error.invalidSetDelimiter }
|
||||||
|
guard try parser.read(state.endDelimiter) else { throw Error.invalidSetDelimiter }
|
||||||
|
guard startDelimiter.count > 0, endDelimiter.count > 0 else { throw Error.invalidSetDelimiter }
|
||||||
|
return state.withDelimiters(start: startDelimiter, end: endDelimiter)
|
||||||
|
}
|
||||||
|
|
||||||
static func hasLineFinished(_ parser: inout HBParser) -> Bool {
|
static func hasLineFinished(_ parser: inout HBParser) -> Bool {
|
||||||
var parser2 = parser
|
var parser2 = parser
|
||||||
if parser.reachedEnd() { return true }
|
if parser.reachedEnd() { return true }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import XCTest
|
|||||||
final class LibraryTests: XCTestCase {
|
final class LibraryTests: XCTestCase {
|
||||||
func testDirectoryLoad() throws {
|
func testDirectoryLoad() throws {
|
||||||
let fs = FileManager()
|
let fs = FileManager()
|
||||||
try fs.createDirectory(atPath: "templates", withIntermediateDirectories: false)
|
try? fs.createDirectory(atPath: "templates", withIntermediateDirectories: false)
|
||||||
let mustache = "<test>{{#value}}<value>{{.}}</value>{{/value}}</test>"
|
let mustache = "<test>{{#value}}<value>{{.}}</value>{{/value}}</test>"
|
||||||
let data = Data(mustache.utf8)
|
let data = Data(mustache.utf8)
|
||||||
defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates")) }
|
defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates")) }
|
||||||
|
|||||||
@@ -10,6 +10,18 @@ func test(_ object: Any, _ template: String, _ expected: String) throws {
|
|||||||
XCTAssertEqual(result, expected)
|
XCTAssertEqual(result, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testPartial(_ object: Any, _ template: String, _ partials: [String: String], _ expected: String) throws {
|
||||||
|
let library = HBMustacheLibrary()
|
||||||
|
let template = try HBMustacheTemplate(string: template)
|
||||||
|
library.register(template, named: "template")
|
||||||
|
for (key, value) in partials {
|
||||||
|
let template = try HBMustacheTemplate(string: value)
|
||||||
|
library.register(template, named: key)
|
||||||
|
}
|
||||||
|
let result = library.render(object, withTemplate: "template")
|
||||||
|
XCTAssertEqual(result, expected)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Comments
|
// MARK: Comments
|
||||||
|
|
||||||
final class SpecCommentsTests: XCTestCase {
|
final class SpecCommentsTests: XCTestCase {
|
||||||
@@ -112,6 +124,179 @@ final class SpecCommentsTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Delimiters
|
||||||
|
|
||||||
|
final class SpecDelimiterTests: XCTestCase {
|
||||||
|
func testPairBehaviour() throws {
|
||||||
|
let object = ["text": "Hey!"]
|
||||||
|
let template = "{{=<% %>=}}(<%text%>)"
|
||||||
|
let expected = "(Hey!)"
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSpecialCharacter() throws {
|
||||||
|
let object = ["text": "It worked!"]
|
||||||
|
let template = "({{=[ ]=}}[text])"
|
||||||
|
let expected = "(It worked!)"
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSections() throws {
|
||||||
|
let object: [String: Any] = ["section": true, "data": "I got interpolated."]
|
||||||
|
let template = """
|
||||||
|
[
|
||||||
|
{{#section}}
|
||||||
|
{{data}}
|
||||||
|
|data|
|
||||||
|
{{/section}}
|
||||||
|
|
||||||
|
{{= | | =}}
|
||||||
|
|#section|
|
||||||
|
{{data}}
|
||||||
|
|data|
|
||||||
|
|/section|
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
let expected = """
|
||||||
|
[
|
||||||
|
I got interpolated.
|
||||||
|
|data|
|
||||||
|
|
||||||
|
{{data}}
|
||||||
|
I got interpolated.
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInvertedSections() throws {
|
||||||
|
let object: [String: Any] = ["section": false, "data": "I got interpolated."]
|
||||||
|
let template = """
|
||||||
|
[
|
||||||
|
{{^section}}
|
||||||
|
{{data}}
|
||||||
|
|data|
|
||||||
|
{{/section}}
|
||||||
|
|
||||||
|
{{= | | =}}
|
||||||
|
|^section|
|
||||||
|
{{data}}
|
||||||
|
|data|
|
||||||
|
|/section|
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
let expected = """
|
||||||
|
[
|
||||||
|
I got interpolated.
|
||||||
|
|data|
|
||||||
|
|
||||||
|
{{data}}
|
||||||
|
I got interpolated.
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPartialInheritance() throws {
|
||||||
|
let object = ["value": "yes"]
|
||||||
|
let template = """
|
||||||
|
[ {{>include}} ]
|
||||||
|
{{= | | =}}
|
||||||
|
[ |>include| ]
|
||||||
|
"""
|
||||||
|
let partial = ".{{value}}."
|
||||||
|
let expected = """
|
||||||
|
[ .yes. ]
|
||||||
|
[ .yes. ]
|
||||||
|
"""
|
||||||
|
try testPartial(object, template, ["include": partial], expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPostPartialBehaviour() throws {
|
||||||
|
let object = ["value": "yes"]
|
||||||
|
let template = """
|
||||||
|
[ {{>include}} ]
|
||||||
|
[ .{{value}}. .|value|. ]
|
||||||
|
"""
|
||||||
|
let partial = ".{{value}}. {{= | | =}} .|value|."
|
||||||
|
let expected = """
|
||||||
|
[ .yes. .yes. ]
|
||||||
|
[ .yes. .|value|. ]
|
||||||
|
"""
|
||||||
|
try testPartial(object, template, ["include": partial], expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSurroundingWhitespace() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = "| {{=@ @=}} |"
|
||||||
|
let expected = "| |"
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOutlyingWhitespace() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = " | {{=@ @=}}\n"
|
||||||
|
let expected = " | \n"
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStandalone() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = """
|
||||||
|
Begin.
|
||||||
|
{{=@ @=}}
|
||||||
|
End.
|
||||||
|
"""
|
||||||
|
let expected = """
|
||||||
|
Begin.
|
||||||
|
End.
|
||||||
|
"""
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testIndentedStandalone() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = """
|
||||||
|
Begin.
|
||||||
|
{{=@ @=}}
|
||||||
|
End.
|
||||||
|
"""
|
||||||
|
let expected = """
|
||||||
|
Begin.
|
||||||
|
End.
|
||||||
|
"""
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStandaloneLineEndings() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = "|\r\n{{= @ @ =}}\r\n|"
|
||||||
|
let expected = "|\r\n|"
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStandaloneWithoutPreviousLine() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = " {{=@ @=}}\n="
|
||||||
|
let expected = "="
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testStandaloneWithoutNewLine() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = "=\n {{=@ @=}}"
|
||||||
|
let expected = "=\n"
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPairWithPadding() throws {
|
||||||
|
let object = {}
|
||||||
|
let template = "|{{= @ @ =}}|"
|
||||||
|
let expected = "||"
|
||||||
|
try test(object, template, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Interpolation
|
// MARK: Interpolation
|
||||||
|
|
||||||
final class SpecInterpolationTests: XCTestCase {
|
final class SpecInterpolationTests: XCTestCase {
|
||||||
@@ -512,18 +697,6 @@ final class SpecInvertedTests: XCTestCase {
|
|||||||
// MARK: Partials
|
// MARK: Partials
|
||||||
|
|
||||||
final class SpecPartialsTests: XCTestCase {
|
final class SpecPartialsTests: XCTestCase {
|
||||||
func testPartial(_ object: Any, _ template: String, _ partials: [String: String], _ expected: String) throws {
|
|
||||||
let library = HBMustacheLibrary()
|
|
||||||
let template = try HBMustacheTemplate(string: template)
|
|
||||||
library.register(template, named: "template")
|
|
||||||
for (key, value) in partials {
|
|
||||||
let template = try HBMustacheTemplate(string: value)
|
|
||||||
library.register(template, named: key)
|
|
||||||
}
|
|
||||||
let result = library.render(object, withTemplate: "template")
|
|
||||||
XCTAssertEqual(result, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testBasic() throws {
|
func testBasic() throws {
|
||||||
let object = {}
|
let object = {}
|
||||||
let template = #""{{>text}}""#
|
let template = #""{{>text}}""#
|
||||||
|
|||||||
Reference in New Issue
Block a user