HBTemplate -> HBMustacheTemplate, escape characters
Add tests for mustache examples
This commit is contained in:
@@ -13,12 +13,12 @@ extension Dictionary: HBMustacheParent where Key == String {
|
||||
}
|
||||
|
||||
protocol HBSequence {
|
||||
func renderSection(with template: HBTemplate) -> String
|
||||
func renderInvertedSection(with template: HBTemplate) -> String
|
||||
func renderSection(with template: HBMustacheTemplate) -> String
|
||||
func renderInvertedSection(with template: HBMustacheTemplate) -> String
|
||||
}
|
||||
|
||||
extension Array: HBSequence {
|
||||
func renderSection(with template: HBTemplate) -> String {
|
||||
func renderSection(with template: HBMustacheTemplate) -> String {
|
||||
var string = ""
|
||||
for obj in self {
|
||||
string += template.render(obj)
|
||||
@@ -26,7 +26,7 @@ extension Array: HBSequence {
|
||||
return string
|
||||
}
|
||||
|
||||
func renderInvertedSection(with template: HBTemplate) -> String {
|
||||
func renderInvertedSection(with template: HBMustacheTemplate) -> String {
|
||||
if count == 0 {
|
||||
return template.render(self)
|
||||
}
|
||||
@@ -35,7 +35,7 @@ extension Array: HBSequence {
|
||||
}
|
||||
|
||||
extension Dictionary: HBSequence {
|
||||
func renderSection(with template: HBTemplate) -> String {
|
||||
func renderSection(with template: HBMustacheTemplate) -> String {
|
||||
var string = ""
|
||||
for obj in self {
|
||||
string += template.render(obj)
|
||||
@@ -43,7 +43,7 @@ extension Dictionary: HBSequence {
|
||||
return string
|
||||
}
|
||||
|
||||
func renderInvertedSection(with template: HBTemplate) -> String {
|
||||
func renderInvertedSection(with template: HBMustacheTemplate) -> String {
|
||||
if count == 0 {
|
||||
return template.render(self)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
extension HBTemplate {
|
||||
extension HBMustacheTemplate {
|
||||
static func parse(_ string: String) throws -> [Token] {
|
||||
var parser = HBParser(string)
|
||||
return try parse(&parser, sectionName: nil)
|
||||
@@ -17,14 +17,20 @@ extension HBTemplate {
|
||||
case "#":
|
||||
parser.unsafeAdvance()
|
||||
let name = try parseSectionName(&parser)
|
||||
if parser.current() == "\n" {
|
||||
parser.unsafeAdvance()
|
||||
}
|
||||
let sectionTokens = try parse(&parser, sectionName: name)
|
||||
tokens.append(.section(name, HBTemplate(sectionTokens)))
|
||||
tokens.append(.section(name, HBMustacheTemplate(sectionTokens)))
|
||||
|
||||
case "^":
|
||||
parser.unsafeAdvance()
|
||||
let name = try parseSectionName(&parser)
|
||||
if parser.current() == "\n" {
|
||||
parser.unsafeAdvance()
|
||||
}
|
||||
let sectionTokens = try parse(&parser, sectionName: name)
|
||||
tokens.append(.invertedSection(name, HBTemplate(sectionTokens)))
|
||||
tokens.append(.invertedSection(name, HBMustacheTemplate(sectionTokens)))
|
||||
|
||||
case "/":
|
||||
parser.unsafeAdvance()
|
||||
@@ -32,13 +38,16 @@ extension HBTemplate {
|
||||
guard name == sectionName else {
|
||||
throw HBMustacheError.sectionCloseNameIncorrect
|
||||
}
|
||||
if parser.current() == "\n" {
|
||||
parser.unsafeAdvance()
|
||||
}
|
||||
return tokens
|
||||
|
||||
case "{":
|
||||
parser.unsafeAdvance()
|
||||
let name = try parseSectionName(&parser)
|
||||
guard try parser.read("}") else { throw HBMustacheError.unfinishedSectionName }
|
||||
tokens.append(.variable(name))
|
||||
tokens.append(.unescapedVariable(name))
|
||||
|
||||
case "!":
|
||||
parser.unsafeAdvance()
|
||||
@@ -67,5 +76,5 @@ extension HBTemplate {
|
||||
return text.string
|
||||
}
|
||||
|
||||
private static let sectionNameChars = Set<Unicode.Scalar>("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.")
|
||||
private static let sectionNameChars = Set<Unicode.Scalar>("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._?")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
extension HBTemplate {
|
||||
extension HBMustacheTemplate {
|
||||
public func render(_ object: Any) -> String {
|
||||
var string = ""
|
||||
for token in tokens {
|
||||
@@ -7,48 +7,32 @@ extension HBTemplate {
|
||||
case .text(let text):
|
||||
string += text
|
||||
case .variable(let variable):
|
||||
if let child = getChild(named: variable, from: object) {
|
||||
string += encodedEscapedCharacters(String(describing: child))
|
||||
}
|
||||
case .unescapedVariable(let variable):
|
||||
if let child = getChild(named: variable, from: object) {
|
||||
string += String(describing: child)
|
||||
}
|
||||
case .section(let variable, let template):
|
||||
let child = getChild(named: variable, from: object)
|
||||
string += renderSection(child, with: template)
|
||||
string += renderSection(child, parent: object, with: template)
|
||||
|
||||
case .invertedSection(let variable, let template):
|
||||
let child = getChild(named: variable, from: object)
|
||||
string += renderInvertedSection(child, with: template)
|
||||
string += renderInvertedSection(child, parent: object, with: template)
|
||||
|
||||
}
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
func renderSection(_ object: Any?, with template: HBTemplate) -> String {
|
||||
switch object {
|
||||
func renderSection(_ child: Any?, parent: Any, with template: HBMustacheTemplate) -> String {
|
||||
switch child {
|
||||
case let array as HBSequence:
|
||||
return array.renderSection(with: template)
|
||||
case let bool as Bool:
|
||||
return bool ? template.render(true) : ""
|
||||
case let int as Int:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as Int8:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as Int16:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as Int32:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as Int64:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as UInt:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as UInt8:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as UInt16:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as UInt32:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
case let int as UInt64:
|
||||
return int != 0 ? template.render(int) : ""
|
||||
return bool ? template.render(parent) : ""
|
||||
case .some(let value):
|
||||
return template.render(value)
|
||||
case .none:
|
||||
@@ -56,36 +40,16 @@ extension HBTemplate {
|
||||
}
|
||||
}
|
||||
|
||||
func renderInvertedSection(_ object: Any?, with template: HBTemplate) -> String {
|
||||
switch object {
|
||||
func renderInvertedSection(_ child: Any?, parent: Any, with template: HBMustacheTemplate) -> String {
|
||||
switch child {
|
||||
case let array as HBSequence:
|
||||
return array.renderInvertedSection(with: template)
|
||||
case let bool as Bool:
|
||||
return bool ? "" : template.render(true)
|
||||
case let int as Int:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as Int8:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as Int16:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as Int32:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as Int64:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as UInt:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as UInt8:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as UInt16:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as UInt32:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
case let int as UInt64:
|
||||
return int == 0 ? template.render(int) : ""
|
||||
return bool ? "" : template.render(parent)
|
||||
case .some:
|
||||
return ""
|
||||
case .none:
|
||||
return template.render(Void())
|
||||
return template.render(parent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +72,24 @@ extension HBTemplate {
|
||||
let nameSplit = name.split(separator: ".").map { String($0) }
|
||||
return _getChild(named: nameSplit[...], from: object)
|
||||
}
|
||||
|
||||
private static let escapedCharacters: [Character: String] = [
|
||||
"<": "<",
|
||||
">": ">",
|
||||
"&": "&",
|
||||
]
|
||||
func encodedEscapedCharacters(_ string: String) -> String {
|
||||
var newString = ""
|
||||
newString.reserveCapacity(string.count)
|
||||
for c in string {
|
||||
if let replacement = Self.escapedCharacters[c] {
|
||||
newString += replacement
|
||||
} else {
|
||||
newString.append(c)
|
||||
}
|
||||
}
|
||||
return newString
|
||||
}
|
||||
}
|
||||
|
||||
func unwrap(_ any: Any) -> Any? {
|
||||
|
||||
@@ -5,8 +5,8 @@ enum HBMustacheError: Error {
|
||||
case expectedSectionEnd
|
||||
}
|
||||
|
||||
public class HBTemplate {
|
||||
public init(_ string: String) throws {
|
||||
public class HBMustacheTemplate {
|
||||
public init(string: String) throws {
|
||||
self.tokens = try Self.parse(string)
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@ public class HBTemplate {
|
||||
enum Token {
|
||||
case text(String)
|
||||
case variable(String)
|
||||
case section(String, HBTemplate)
|
||||
case invertedSection(String, HBTemplate)
|
||||
case unescapedVariable(String)
|
||||
case section(String, HBMustacheTemplate)
|
||||
case invertedSection(String, HBMustacheTemplate)
|
||||
}
|
||||
|
||||
let tokens: [Token]
|
||||
|
||||
Reference in New Issue
Block a user