From ccace51ede75c1ef4e7bb6558ca5ea1d3cde4b85 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Sat, 9 Mar 2024 10:08:52 +0000 Subject: [PATCH 1/3] Remove HB prefix, make Parser private --- README.md | 14 +- Sources/HummingbirdMustache/ContentType.swift | 20 +- Sources/HummingbirdMustache/Context.swift | 34 +-- .../CustomRenderable.swift | 8 +- Sources/HummingbirdMustache/Lambda.swift | 12 +- .../Library+FileSystem.swift | 12 +- Sources/HummingbirdMustache/Library.swift | 14 +- Sources/HummingbirdMustache/Parent.swift | 4 +- Sources/HummingbirdMustache/Parser.swift | 46 ++-- Sources/HummingbirdMustache/Sequence.swift | 18 +- .../HummingbirdMustache/SequenceContext.swift | 4 +- .../HummingbirdMustache/Template+Parser.swift | 40 +-- .../HummingbirdMustache/Template+Render.swift | 32 +-- Sources/HummingbirdMustache/Template.swift | 16 +- Sources/HummingbirdMustache/Transform.swift | 40 +-- .../HummingbirdMustacheTests/ErrorTests.swift | 24 +- .../LibraryTests.swift | 8 +- .../PartialTests.swift | 256 +++++++++--------- .../HummingbirdMustacheTests/SpecTests.swift | 10 +- .../TemplateParserTests.swift | 36 +-- .../TemplateRendererTests.swift | 72 ++--- .../TransformTests.swift | 26 +- documentation/Lambdas.md | 8 +- documentation/Transforms.md | 4 +- 24 files changed, 379 insertions(+), 379 deletions(-) diff --git a/README.md b/README.md index 1aec75f..0cc4e35 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ While Hummingbird Mustache has been designed to be used with the Hummingbird ser Load your templates from the filesystem ```swift -let library = HBMustacheLibrary("folder/my/templates/are/in") +let library = MustacheLibrary("folder/my/templates/are/in") ``` This will look for all the files with the extension ".mustache" in the specified folder and subfolders and attempt to load them. Each file is registed with the name of the file (with subfolder, if inside a subfolder) minus the "mustache" extension. @@ -20,23 +20,23 @@ let output = library.render(object, withTemplate: "myTemplate") ### Using with Hummingbird -HummingbirdMustache doesn't have any integration with Hummingbird as I wanted to keep the library dependency free. But if you are going to use the library with Hummingbird it is recommended you extend `HBApplication` to store an instance of your library. +HummingbirdMustache doesn't have any integration with Hummingbird as I wanted to keep the library dependency free. But if you are going to use the library with Hummingbird it is recommended you extend `Application` to store an instance of your library. ```swift -extension HBApplication { - var mustache: HBMustacheLibrary { +extension Application { + var mustache: MustacheLibrary { get { self.extensions.get(\.mustache) } set { self.extensions.set(\.mustache, value: newValue) } } } -extension HBRequest { - var mustache: HBMustacheLibrary { self.application.mustache } +extension Request { + var mustache: MustacheLibrary { self.application.mustache } } // load mustache templates from templates folder application.mustache = try .init(directory: "templates") ``` -You can now access your mustache templates via `HBRequest` eg `HBRequest.mustache.render(obj, withTemplate: "myTemplate")` +You can now access your mustache templates via `Request` eg `Request.mustache.render(obj, withTemplate: "myTemplate")` ## Support diff --git a/Sources/HummingbirdMustache/ContentType.swift b/Sources/HummingbirdMustache/ContentType.swift index 1a578a1..96a159c 100644 --- a/Sources/HummingbirdMustache/ContentType.swift +++ b/Sources/HummingbirdMustache/ContentType.swift @@ -13,20 +13,20 @@ //===----------------------------------------------------------------------===// /// Protocol for content types -public protocol HBMustacheContentType: Sendable { +public protocol MustacheContentType: Sendable { /// escape text for this content type eg for HTML replace "<" with "<" func escapeText(_ text: String) -> String } /// Text content type where no character is escaped -struct HBTextContentType: HBMustacheContentType { +struct TextContentType: MustacheContentType { func escapeText(_ text: String) -> String { return text } } /// HTML content where text is escaped for HTML output -struct HBHTMLContentType: HBMustacheContentType { +struct HTMLContentType: MustacheContentType { func escapeText(_ text: String) -> String { return text.htmlEscape() } @@ -36,9 +36,9 @@ struct HBHTMLContentType: HBMustacheContentType { /// /// The string is read from the "CONTENT_TYPE" pragma `{{% CONTENT_TYPE: type}}`. Replace type with /// the content type required. The default available types are `TEXT` and `HTML`. You can register your own -/// with `HBMustacheContentTypes.register`. -public enum HBMustacheContentTypes { - static func get(_ name: String) -> HBMustacheContentType? { +/// with `MustacheContentTypes.register`. +public enum MustacheContentTypes { + static func get(_ name: String) -> MustacheContentType? { return self.types[name] } @@ -46,12 +46,12 @@ public enum HBMustacheContentTypes { /// - Parameters: /// - contentType: Content type /// - name: String to identify it - public static func register(_ contentType: HBMustacheContentType, named name: String) { + public static func register(_ contentType: MustacheContentType, named name: String) { self.types[name] = contentType } - static var types: [String: HBMustacheContentType] = [ - "HTML": HBHTMLContentType(), - "TEXT": HBTextContentType(), + static var types: [String: MustacheContentType] = [ + "HTML": HTMLContentType(), + "TEXT": TextContentType(), ] } diff --git a/Sources/HummingbirdMustache/Context.swift b/Sources/HummingbirdMustache/Context.swift index 2eaa0d3..9aaae62 100644 --- a/Sources/HummingbirdMustache/Context.swift +++ b/Sources/HummingbirdMustache/Context.swift @@ -13,31 +13,31 @@ //===----------------------------------------------------------------------===// /// Context while rendering mustache tokens -struct HBMustacheContext { +struct MustacheContext { let stack: [Any] - let sequenceContext: HBMustacheSequenceContext? + let sequenceContext: MustacheSequenceContext? let indentation: String? - let inherited: [String: HBMustacheTemplate]? - let contentType: HBMustacheContentType - let library: HBMustacheLibrary? + let inherited: [String: MustacheTemplate]? + let contentType: MustacheContentType + let library: MustacheLibrary? /// initialize context with a single objectt - init(_ object: Any, library: HBMustacheLibrary? = nil) { + init(_ object: Any, library: MustacheLibrary? = nil) { self.stack = [object] self.sequenceContext = nil self.indentation = nil self.inherited = nil - self.contentType = HBHTMLContentType() + self.contentType = HTMLContentType() self.library = library } private init( stack: [Any], - sequenceContext: HBMustacheSequenceContext?, + sequenceContext: MustacheSequenceContext?, indentation: String?, - inherited: [String: HBMustacheTemplate]?, - contentType: HBMustacheContentType, - library: HBMustacheLibrary? = nil + inherited: [String: MustacheTemplate]?, + contentType: MustacheContentType, + library: MustacheLibrary? = nil ) { self.stack = stack self.sequenceContext = sequenceContext @@ -48,7 +48,7 @@ struct HBMustacheContext { } /// return context with object add to stack - func withObject(_ object: Any) -> HBMustacheContext { + func withObject(_ object: Any) -> MustacheContext { var stack = self.stack stack.append(object) return .init( @@ -62,13 +62,13 @@ struct HBMustacheContext { } /// return context with indent and parameter information for invoking a partial - func withPartial(indented: String?, inheriting: [String: HBMustacheTemplate]?) -> HBMustacheContext { + func withPartial(indented: String?, inheriting: [String: MustacheTemplate]?) -> MustacheContext { let indentation: String? = if let indented { (self.indentation ?? "") + indented } else { self.indentation } - let inherits: [String: HBMustacheTemplate]? = if let inheriting { + let inherits: [String: MustacheTemplate]? = if let inheriting { if let originalInherits = self.inherited { originalInherits.merging(inheriting) { value, _ in value } } else { @@ -82,13 +82,13 @@ struct HBMustacheContext { sequenceContext: nil, indentation: indentation, inherited: inherits, - contentType: HBHTMLContentType(), + contentType: HTMLContentType(), library: self.library ) } /// return context with sequence info and sequence element added to stack - func withSequence(_ object: Any, sequenceContext: HBMustacheSequenceContext) -> HBMustacheContext { + func withSequence(_ object: Any, sequenceContext: MustacheSequenceContext) -> MustacheContext { var stack = self.stack stack.append(object) return .init( @@ -102,7 +102,7 @@ struct HBMustacheContext { } /// return context with sequence info and sequence element added to stack - func withContentType(_ contentType: HBMustacheContentType) -> HBMustacheContext { + func withContentType(_ contentType: MustacheContentType) -> MustacheContext { return .init( stack: self.stack, sequenceContext: self.sequenceContext, diff --git a/Sources/HummingbirdMustache/CustomRenderable.swift b/Sources/HummingbirdMustache/CustomRenderable.swift index 307360b..003f399 100644 --- a/Sources/HummingbirdMustache/CustomRenderable.swift +++ b/Sources/HummingbirdMustache/CustomRenderable.swift @@ -16,23 +16,23 @@ import Foundation /// Allow object to override standard hummingbird type rendering which uses /// `String(describing)`. -public protocol HBMustacheCustomRenderable { +public protocol MustacheCustomRenderable { /// Custom rendered version of object var renderText: String { get } /// Whether the object is a null object. Used when scoping sections var isNull: Bool { get } } -extension HBMustacheCustomRenderable { +extension MustacheCustomRenderable { /// default version returning the standard rendering var renderText: String { String(describing: self) } /// default version returning false var isNull: Bool { false } } -/// Extend NSNull to conform to `HBMustacheCustomRenderable` to avoid outputting `` and returning +/// Extend NSNull to conform to `MustacheCustomRenderable` to avoid outputting `` and returning /// a valid response for `isNull` -extension NSNull: HBMustacheCustomRenderable { +extension NSNull: MustacheCustomRenderable { public var renderText: String { "" } public var isNull: Bool { true } } diff --git a/Sources/HummingbirdMustache/Lambda.swift b/Sources/HummingbirdMustache/Lambda.swift index d669503..7c9e64e 100644 --- a/Sources/HummingbirdMustache/Lambda.swift +++ b/Sources/HummingbirdMustache/Lambda.swift @@ -21,30 +21,30 @@ /// ``` /// struct Object { /// let name: String -/// let wrapped: HBMustacheLambda +/// let wrapped: MustacheLambda /// } /// let willy = Object(name: "Willy", wrapped: .init({ object, template in /// return "\(template.render(object))" /// })) /// let mustache = "{{#wrapped}}{{name}} is awesome.{{/wrapped}}" -/// let template = try HBMustacheTemplate(string: mustache) +/// let template = try MustacheTemplate(string: mustache) /// let output = template.render(willy) /// print(output) // Willy is awesome /// ``` /// -public struct HBMustacheLambda { +public struct MustacheLambda { /// lambda callback - public typealias Callback = (Any, HBMustacheTemplate) -> String + public typealias Callback = (Any, MustacheTemplate) -> String let callback: Callback - /// Initialize `HBMustacheLambda` + /// Initialize `MustacheLambda` /// - Parameter cb: function to be called by lambda public init(_ cb: @escaping Callback) { self.callback = cb } - internal func run(_ object: Any, _ template: HBMustacheTemplate) -> String { + internal func run(_ object: Any, _ template: MustacheTemplate) -> String { return self.callback(object, template) } } diff --git a/Sources/HummingbirdMustache/Library+FileSystem.swift b/Sources/HummingbirdMustache/Library+FileSystem.swift index 9503eed..06a95e8 100644 --- a/Sources/HummingbirdMustache/Library+FileSystem.swift +++ b/Sources/HummingbirdMustache/Library+FileSystem.swift @@ -14,9 +14,9 @@ import Foundation -extension HBMustacheLibrary { +extension MustacheLibrary { /// Load templates from a folder - static func loadTemplates(from directory: String, withExtension extension: String = "mustache") async throws -> [String: HBMustacheTemplate] { + static func loadTemplates(from directory: String, withExtension extension: String = "mustache") async throws -> [String: MustacheTemplate] { var directory = directory if !directory.hasSuffix("/") { directory += "/" @@ -24,15 +24,15 @@ extension HBMustacheLibrary { let extWithDot = ".\(`extension`)" let fs = FileManager() guard let enumerator = fs.enumerator(atPath: directory) else { return [:] } - var templates: [String: HBMustacheTemplate] = [:] + var templates: [String: MustacheTemplate] = [:] for case let path as String in enumerator { guard path.hasSuffix(extWithDot) else { continue } guard let data = fs.contents(atPath: directory + path) else { continue } let string = String(decoding: data, as: Unicode.UTF8.self) - var template: HBMustacheTemplate + var template: MustacheTemplate do { - template = try HBMustacheTemplate(string: string) - } catch let error as HBMustacheTemplate.ParserError { + template = try MustacheTemplate(string: string) + } catch let error as MustacheTemplate.ParserError { throw ParserError(filename: path, context: error.context, error: error.error) } // drop ".mustache" from path to get name diff --git a/Sources/HummingbirdMustache/Library.swift b/Sources/HummingbirdMustache/Library.swift index 515292e..6e8be10 100644 --- a/Sources/HummingbirdMustache/Library.swift +++ b/Sources/HummingbirdMustache/Library.swift @@ -18,7 +18,7 @@ /// ``` /// {{#sequence}}{{>entry}}{{/sequence}} /// ``` -public struct HBMustacheLibrary: Sendable { +public struct MustacheLibrary: Sendable { /// Initialize empty library public init() { self.templates = [:] @@ -30,7 +30,7 @@ public struct HBMustacheLibrary: Sendable { /// the folder is recursive and templates in subfolders will be registered with the name `subfolder/template`. /// - Parameter directory: Directory to look for mustache templates /// - Parameter extension: Extension of files to look for - public init(templates: [String: HBMustacheTemplate]) { + public init(templates: [String: MustacheTemplate]) { self.templates = templates } @@ -48,7 +48,7 @@ public struct HBMustacheLibrary: Sendable { /// - Parameters: /// - template: Template /// - name: Name of template - public mutating func register(_ template: HBMustacheTemplate, named name: String) { + public mutating func register(_ template: MustacheTemplate, named name: String) { self.templates[name] = template } @@ -57,14 +57,14 @@ public struct HBMustacheLibrary: Sendable { /// - mustache: Mustache text /// - name: Name of template public mutating func register(_ mustache: String, named name: String) throws { - let template = try HBMustacheTemplate(string: mustache) + let template = try MustacheTemplate(string: mustache) self.templates[name] = template } /// Return template registed with name /// - Parameter name: name to search for /// - Returns: Template - public func getTemplate(named name: String) -> HBMustacheTemplate? { + public func getTemplate(named name: String) -> MustacheTemplate? { self.templates[name] } @@ -83,10 +83,10 @@ public struct HBMustacheLibrary: Sendable { /// File error occurred in public let filename: String /// Context (line, linenumber and column number) - public let context: HBParser.Context + public let context: MustacheParserContext /// Actual error that occurred public let error: Error } - private var templates: [String: HBMustacheTemplate] + private var templates: [String: MustacheTemplate] } diff --git a/Sources/HummingbirdMustache/Parent.swift b/Sources/HummingbirdMustache/Parent.swift index 2d597a4..a542fd1 100644 --- a/Sources/HummingbirdMustache/Parent.swift +++ b/Sources/HummingbirdMustache/Parent.swift @@ -14,12 +14,12 @@ /// Protocol for object that has a custom method for accessing their children, instead /// of using Mirror -public protocol HBMustacheParent { +public protocol MustacheParent { func child(named: String) -> Any? } /// Extend dictionary where the key is a string so that it uses the key values to access /// it values -extension Dictionary: HBMustacheParent where Key == String { +extension Dictionary: MustacheParent where Key == String { public func child(named: String) -> Any? { return self[named] } } diff --git a/Sources/HummingbirdMustache/Parser.swift b/Sources/HummingbirdMustache/Parser.swift index c8bb7a9..a3581cf 100644 --- a/Sources/HummingbirdMustache/Parser.swift +++ b/Sources/HummingbirdMustache/Parser.swift @@ -15,7 +15,7 @@ import Foundation /// Reader object for parsing String buffers -public struct HBParser { +struct Parser { enum Error: Swift.Error { case overflow } @@ -42,12 +42,12 @@ public struct HBParser { private(set) var position: String.Index } -extension HBParser { +extension Parser { /// Return current character /// - Throws: .overflow /// - Returns: Current character mutating func character() throws -> Character { - guard !self.reachedEnd() else { throw HBParser.Error.overflow } + guard !self.reachedEnd() else { throw Parser.Error.overflow } let c = unsafeCurrent() unsafeAdvance() return c @@ -93,7 +93,7 @@ extension HBParser { /// - Throws: .overflow /// - Returns: The string read from the buffer mutating func read(count: Int) throws -> Substring { - guard self.buffer.distance(from: self.position, to: self.buffer.endIndex) >= count else { throw HBParser.Error.overflow } + guard self.buffer.distance(from: self.position, to: self.buffer.endIndex) >= count else { throw Parser.Error.overflow } let end = self.buffer.index(self.position, offsetBy: count) let subString = self.buffer[self.position.. Context { + func getContext() -> MustacheParserContext { var parser = self var columnNumber = 0 while !parser.atStart() { @@ -316,12 +316,12 @@ extension HBParser { let textBefore = buffer[buffer.startIndex..= amount else { throw HBParser.Error.overflow } + guard self.buffer.distance(from: self.position, to: self.buffer.endIndex) >= amount else { throw Parser.Error.overflow } return unsafeAdvance(by: amount) } @@ -356,18 +356,18 @@ extension HBParser { /// - Parameter amount: number of characters to move back /// - Throws: .overflow mutating func retreat(by amount: Int) throws { - guard self.buffer.distance(from: self.buffer.startIndex, to: self.position) >= amount else { throw HBParser.Error.overflow } + guard self.buffer.distance(from: self.buffer.startIndex, to: self.position) >= amount else { throw Parser.Error.overflow } return unsafeRetreat(by: amount) } mutating func setPosition(_ position: String.Index) throws { - guard position <= self.buffer.endIndex else { throw HBParser.Error.overflow } + guard position <= self.buffer.endIndex else { throw Parser.Error.overflow } unsafeSetPosition(position) } } // unsafe versions without checks -extension HBParser { +extension Parser { func unsafeCurrent() -> Character { return self.buffer[self.position] } diff --git a/Sources/HummingbirdMustache/Sequence.swift b/Sources/HummingbirdMustache/Sequence.swift index 2435304..5c86901 100644 --- a/Sources/HummingbirdMustache/Sequence.swift +++ b/Sources/HummingbirdMustache/Sequence.swift @@ -13,18 +13,18 @@ //===----------------------------------------------------------------------===// /// Protocol for objects that can be rendered as a sequence in Mustache -protocol HBMustacheSequence { +protocol MustacheSequence { /// Render section using template - func renderSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String + func renderSection(with template: MustacheTemplate, context: MustacheContext) -> String /// Render inverted section using template - func renderInvertedSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String + func renderInvertedSection(with template: MustacheTemplate, context: MustacheContext) -> String } extension Sequence { /// Render section using template - func renderSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String { + func renderSection(with template: MustacheTemplate, context: MustacheContext) -> String { var string = "" - var sequenceContext = HBMustacheSequenceContext(first: true) + var sequenceContext = MustacheSequenceContext(first: true) var iterator = makeIterator() guard var currentObject = iterator.next() else { return "" } @@ -43,7 +43,7 @@ extension Sequence { } /// Render inverted section using template - func renderInvertedSection(with template: HBMustacheTemplate, context: HBMustacheContext) -> String { + func renderInvertedSection(with template: MustacheTemplate, context: MustacheContext) -> String { var iterator = makeIterator() if iterator.next() == nil { return template.render(context: context.withObject(self)) @@ -52,6 +52,6 @@ extension Sequence { } } -extension Array: HBMustacheSequence {} -extension Set: HBMustacheSequence {} -extension ReversedCollection: HBMustacheSequence {} +extension Array: MustacheSequence {} +extension Set: MustacheSequence {} +extension ReversedCollection: MustacheSequence {} diff --git a/Sources/HummingbirdMustache/SequenceContext.swift b/Sources/HummingbirdMustache/SequenceContext.swift index c4d5c38..a592554 100644 --- a/Sources/HummingbirdMustache/SequenceContext.swift +++ b/Sources/HummingbirdMustache/SequenceContext.swift @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// /// Context that current object inside a sequence is being rendered in. Only relevant when rendering a sequence -struct HBMustacheSequenceContext: HBMustacheTransformable { +struct MustacheSequenceContext: MustacheTransformable { var first: Bool var last: Bool var index: Int @@ -24,7 +24,7 @@ struct HBMustacheSequenceContext: HBMustacheTransformable { self.index = 0 } - /// Transform `HBMustacheContext`. These are available when processing elements + /// Transform `MustacheContext`. These are available when processing elements /// of a sequence. /// /// Format your mustache as follows to accept them. They look like a function without any arguments diff --git a/Sources/HummingbirdMustache/Template+Parser.swift b/Sources/HummingbirdMustache/Template+Parser.swift index b8634af..2d69e5c 100644 --- a/Sources/HummingbirdMustache/Template+Parser.swift +++ b/Sources/HummingbirdMustache/Template+Parser.swift @@ -12,14 +12,14 @@ // //===----------------------------------------------------------------------===// -extension HBMustacheTemplate { - /// Error return by `HBMustacheTemplate.parse`. Includes information about where error occurred +extension MustacheTemplate { + /// Error return by `MustacheTemplate.parse`. Includes information about where error occurred public struct ParserError: Swift.Error { - public let context: HBParser.Context + public let context: MustacheParserContext public let error: Swift.Error } - /// Error generated by `HBMustacheTemplate.parse` + /// Error generated by `MustacheTemplate.parse` public enum Error: Swift.Error { /// the end section does not match the name of the start section case sectionCloseNameIncorrect @@ -72,7 +72,7 @@ extension HBMustacheTemplate { /// parse mustache text to generate a list of tokens static func parse(_ string: String) throws -> [Token] { - var parser = HBParser(string) + var parser = Parser(string) do { return try self.parse(&parser, state: .init()) } catch { @@ -81,7 +81,7 @@ extension HBMustacheTemplate { } /// parse section in mustache text - static func parse(_ parser: inout HBParser, state: ParserState) throws -> [Token] { + static func parse(_ parser: inout Parser, state: ParserState) throws -> [Token] { var tokens: [Token] = [] var state = state var whiteSpaceBefore: Substring = "" @@ -122,7 +122,7 @@ extension HBMustacheTemplate { whiteSpaceBefore = "" } let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform)) - tokens.append(.section(name: name, transform: transform, template: HBMustacheTemplate(sectionTokens))) + tokens.append(.section(name: name, transform: transform, template: MustacheTemplate(sectionTokens))) case "^": // inverted section @@ -135,7 +135,7 @@ extension HBMustacheTemplate { whiteSpaceBefore = "" } let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform)) - tokens.append(.invertedSection(name: name, transform: transform, template: HBMustacheTemplate(sectionTokens))) + tokens.append(.invertedSection(name: name, transform: transform, template: MustacheTemplate(sectionTokens))) case "$": // inherited section @@ -150,7 +150,7 @@ extension HBMustacheTemplate { whiteSpaceBefore = "" } let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform)) - tokens.append(.inheritedSection(name: name, template: HBMustacheTemplate(sectionTokens))) + tokens.append(.inheritedSection(name: name, template: MustacheTemplate(sectionTokens))) case "/": // end of section @@ -224,7 +224,7 @@ extension HBMustacheTemplate { whiteSpaceBefore = "" } let sectionTokens = try parse(&parser, state: state.withSectionName(name)) - var inherit: [String: HBMustacheTemplate] = [:] + var inherit: [String: MustacheTemplate] = [:] // parse tokens in section to extract inherited sections for token in sectionTokens { switch token { @@ -271,7 +271,7 @@ extension HBMustacheTemplate { } /// read until we hit either the start delimiter of a tag or a newline - static func readUntilDelimiterOrNewline(_ parser: inout HBParser, state: ParserState) throws -> String { + static func readUntilDelimiterOrNewline(_ parser: inout Parser, state: ParserState) throws -> String { var untilSet: Set = ["\n", "\r\n"] guard let delimiterFirstChar = state.startDelimiter.first else { return "" } var totalText = "" @@ -296,14 +296,14 @@ extension HBMustacheTemplate { } /// parse variable name - static func parseName(_ parser: inout HBParser, state: ParserState) throws -> (String, String?) { + static func parseName(_ parser: inout Parser, state: ParserState) throws -> (String, String?) { parser.read(while: \.isWhitespace) let text = String(parser.read(while: self.sectionNameChars)) parser.read(while: \.isWhitespace) guard try parser.read(string: state.endDelimiter) else { throw Error.unfinishedName } // does the name include brackets. If so this is a transform call - var nameParser = HBParser(String(text)) + var nameParser = Parser(String(text)) let string = nameParser.read(while: self.sectionNameCharsWithoutBrackets) if nameParser.reachedEnd() { return (text, nil) @@ -320,7 +320,7 @@ extension HBMustacheTemplate { } /// parse partial name - static func parsePartialName(_ parser: inout HBParser, state: ParserState) throws -> String { + static func parsePartialName(_ parser: inout Parser, state: ParserState) throws -> String { parser.read(while: \.isWhitespace) let text = String(parser.read(while: self.sectionNameChars)) parser.read(while: \.isWhitespace) @@ -328,12 +328,12 @@ extension HBMustacheTemplate { return text } - static func parseComment(_ parser: inout HBParser, state: ParserState) throws -> String { + static func parseComment(_ parser: inout Parser, state: ParserState) throws -> String { let text = try parser.read(untilString: state.endDelimiter, throwOnOverflow: true, skipToEnd: true) return String(text) } - static func parserSetDelimiter(_ parser: inout HBParser, state: ParserState) throws -> ParserState { + static func parserSetDelimiter(_ parser: inout Parser, state: ParserState) throws -> ParserState { let startDelimiter: Substring let endDelimiter: Substring @@ -352,7 +352,7 @@ extension HBMustacheTemplate { return state.withDelimiters(start: String(startDelimiter), end: String(endDelimiter)) } - static func readConfigVariable(_ parser: inout HBParser, state: ParserState) throws -> Token? { + static func readConfigVariable(_ parser: inout Parser, state: ParserState) throws -> Token? { let variable: Substring let value: Substring @@ -374,14 +374,14 @@ extension HBMustacheTemplate { switch variable { case "CONTENT_TYPE": - guard let contentType = HBMustacheContentTypes.get(String(value)) else { throw Error.unrecognisedConfigVariable } + guard let contentType = MustacheContentTypes.get(String(value)) else { throw Error.unrecognisedConfigVariable } return .contentType(contentType) default: throw Error.unrecognisedConfigVariable } } - static func hasLineFinished(_ parser: inout HBParser) -> Bool { + static func hasLineFinished(_ parser: inout Parser) -> Bool { var parser2 = parser if parser.reachedEnd() { return true } parser2.read(while: Set(" \t")) @@ -393,7 +393,7 @@ extension HBMustacheTemplate { return false } - static func isStandalone(_ parser: inout HBParser, state: ParserState) -> Bool { + static func isStandalone(_ parser: inout Parser, state: ParserState) -> Bool { return state.newLine && self.hasLineFinished(&parser) } diff --git a/Sources/HummingbirdMustache/Template+Render.swift b/Sources/HummingbirdMustache/Template+Render.swift index 12fa40b..c3f657c 100644 --- a/Sources/HummingbirdMustache/Template+Render.swift +++ b/Sources/HummingbirdMustache/Template+Render.swift @@ -14,14 +14,14 @@ import Foundation -extension HBMustacheTemplate { +extension MustacheTemplate { /// Render template using object /// - Parameters: /// - stack: Object /// - context: Context that render is occurring in. Contains information about position in sequence /// - indentation: indentation of partial /// - Returns: Rendered text - func render(context: HBMustacheContext) -> String { + func render(context: MustacheContext) -> String { var string = "" var context = context @@ -42,15 +42,15 @@ extension HBMustacheTemplate { return string } - func renderToken(_ token: Token, context: inout HBMustacheContext) -> String { + func renderToken(_ token: Token, context: inout MustacheContext) -> String { switch token { case .text(let text): return text case .variable(let variable, let transform): if let child = getChild(named: variable, transform: transform, context: context) { - if let template = child as? HBMustacheTemplate { + if let template = child as? MustacheTemplate { return template.render(context: context) - } else if let renderable = child as? HBMustacheCustomRenderable { + } else if let renderable = child as? MustacheCustomRenderable { return context.contentType.escapeText(renderable.renderText) } else { return context.contentType.escapeText(String(describing: child)) @@ -58,7 +58,7 @@ extension HBMustacheTemplate { } case .unescapedVariable(let variable, let transform): if let child = getChild(named: variable, transform: transform, context: context) { - if let renderable = child as? HBMustacheCustomRenderable { + if let renderable = child as? MustacheCustomRenderable { return renderable.renderText } else { return String(describing: child) @@ -96,15 +96,15 @@ extension HBMustacheTemplate { /// - parent: Current object being rendered /// - template: Template to render with /// - Returns: Rendered text - func renderSection(_ child: Any?, with template: HBMustacheTemplate, context: HBMustacheContext) -> String { + func renderSection(_ child: Any?, with template: MustacheTemplate, context: MustacheContext) -> String { switch child { - case let array as HBMustacheSequence: + case let array as MustacheSequence: return array.renderSection(with: template, context: context) case let bool as Bool: return bool ? template.render(context: context) : "" - case let lambda as HBMustacheLambda: + case let lambda as MustacheLambda: return lambda.run(context.stack.last!, template) - case let null as HBMustacheCustomRenderable where null.isNull == true: + case let null as MustacheCustomRenderable where null.isNull == true: return "" case .some(let value): return template.render(context: context.withObject(value)) @@ -119,13 +119,13 @@ extension HBMustacheTemplate { /// - parent: Current object being rendered /// - template: Template to render with /// - Returns: Rendered text - func renderInvertedSection(_ child: Any?, with template: HBMustacheTemplate, context: HBMustacheContext) -> String { + func renderInvertedSection(_ child: Any?, with template: MustacheTemplate, context: MustacheContext) -> String { switch child { - case let array as HBMustacheSequence: + case let array as MustacheSequence: return array.renderInvertedSection(with: template, context: context) case let bool as Bool: return bool ? "" : template.render(context: context) - case let null as HBMustacheCustomRenderable where null.isNull == true: + case let null as MustacheCustomRenderable where null.isNull == true: return template.render(context: context) case .some: return "" @@ -135,9 +135,9 @@ extension HBMustacheTemplate { } /// Get child object from variable name - func getChild(named name: String, transform: String?, context: HBMustacheContext) -> Any? { + func getChild(named name: String, transform: String?, context: MustacheContext) -> Any? { func _getImmediateChild(named name: String, from object: Any) -> Any? { - if let customBox = object as? HBMustacheParent { + if let customBox = object as? MustacheParent { return customBox.child(named: name) } else { let mirror = Mirror(reflecting: object) @@ -183,7 +183,7 @@ extension HBMustacheTemplate { // if we want to run a transform and the current child can have transforms applied to it then // run transform on the current child if let transform { - if let runnable = child as? HBMustacheTransformable { + if let runnable = child as? MustacheTransformable { return runnable.transform(transform) } return nil diff --git a/Sources/HummingbirdMustache/Template.swift b/Sources/HummingbirdMustache/Template.swift index a82d8c1..2d608c6 100644 --- a/Sources/HummingbirdMustache/Template.swift +++ b/Sources/HummingbirdMustache/Template.swift @@ -13,10 +13,10 @@ //===----------------------------------------------------------------------===// /// Class holding Mustache template -public struct HBMustacheTemplate: Sendable { +public struct MustacheTemplate: Sendable { /// Initialize template /// - Parameter string: Template text - /// - Throws: HBMustacheTemplate.Error + /// - Throws: MustacheTemplate.Error public init(string: String) throws { self.tokens = try Self.parse(string) } @@ -24,7 +24,7 @@ public struct HBMustacheTemplate: Sendable { /// Render object using this template /// - Parameter object: Object to render /// - Returns: Rendered text - public func render(_ object: Any, library: HBMustacheLibrary? = nil) -> String { + public func render(_ object: Any, library: MustacheLibrary? = nil) -> String { self.render(context: .init(object, library: library)) } @@ -36,11 +36,11 @@ public struct HBMustacheTemplate: Sendable { case text(String) case variable(name: String, transform: String? = nil) case unescapedVariable(name: String, transform: String? = nil) - case section(name: String, transform: String? = nil, template: HBMustacheTemplate) - case invertedSection(name: String, transform: String? = nil, template: HBMustacheTemplate) - case inheritedSection(name: String, template: HBMustacheTemplate) - case partial(String, indentation: String?, inherits: [String: HBMustacheTemplate]?) - case contentType(HBMustacheContentType) + case section(name: String, transform: String? = nil, template: MustacheTemplate) + case invertedSection(name: String, transform: String? = nil, template: MustacheTemplate) + case inheritedSection(name: String, template: MustacheTemplate) + case partial(String, indentation: String?, inherits: [String: MustacheTemplate]?) + case contentType(MustacheContentType) } var tokens: [Token] diff --git a/Sources/HummingbirdMustache/Transform.swift b/Sources/HummingbirdMustache/Transform.swift index 63c68fe..f0947af 100644 --- a/Sources/HummingbirdMustache/Transform.swift +++ b/Sources/HummingbirdMustache/Transform.swift @@ -27,7 +27,7 @@ /// ``` /// {{#reversed(sequence)}}{{.}}{{\reversed(sequence)}} /// ``` -public protocol HBMustacheTransformable { +public protocol MustacheTransformable { func transform(_ name: String) -> Any? } @@ -55,15 +55,15 @@ public extension StringProtocol { } } -extension String: HBMustacheTransformable {} -extension Substring: HBMustacheTransformable {} +extension String: MustacheTransformable {} +extension Substring: MustacheTransformable {} /// Protocol for sequence that can be sorted -private protocol HBComparableSequence { +private protocol ComparableSequence { func comparableTransform(_ name: String) -> Any? } -extension Array: HBMustacheTransformable { +extension Array: MustacheTransformable { /// Transform Array. /// /// Transforms available are `first`, `last`, `reversed`, `count` and for arrays @@ -83,7 +83,7 @@ extension Array: HBMustacheTransformable { case "empty": return isEmpty default: - if let comparableSeq = self as? HBComparableSequence { + if let comparableSeq = self as? ComparableSequence { return comparableSeq.comparableTransform(name) } return nil @@ -91,7 +91,7 @@ extension Array: HBMustacheTransformable { } } -extension Array: HBComparableSequence where Element: Comparable { +extension Array: ComparableSequence where Element: Comparable { func comparableTransform(_ name: String) -> Any? { switch name { case "sorted": @@ -102,7 +102,7 @@ extension Array: HBComparableSequence where Element: Comparable { } } -extension Dictionary: HBMustacheTransformable { +extension Dictionary: MustacheTransformable { /// Transform Dictionary /// /// Transforms available are `count`, `enumerated` and for dictionaries @@ -118,7 +118,7 @@ extension Dictionary: HBMustacheTransformable { case "enumerated": return map { (key: $0.key, value: $0.value) } default: - if let comparableSeq = self as? HBComparableSequence { + if let comparableSeq = self as? ComparableSequence { return comparableSeq.comparableTransform(name) } return nil @@ -126,7 +126,7 @@ extension Dictionary: HBMustacheTransformable { } } -extension Dictionary: HBComparableSequence where Key: Comparable { +extension Dictionary: ComparableSequence where Key: Comparable { func comparableTransform(_ name: String) -> Any? { switch name { case "sorted": @@ -161,13 +161,13 @@ public extension FixedWidthInteger { } } -extension Int: HBMustacheTransformable {} -extension Int8: HBMustacheTransformable {} -extension Int16: HBMustacheTransformable {} -extension Int32: HBMustacheTransformable {} -extension Int64: HBMustacheTransformable {} -extension UInt: HBMustacheTransformable {} -extension UInt8: HBMustacheTransformable {} -extension UInt16: HBMustacheTransformable {} -extension UInt32: HBMustacheTransformable {} -extension UInt64: HBMustacheTransformable {} +extension Int: MustacheTransformable {} +extension Int8: MustacheTransformable {} +extension Int16: MustacheTransformable {} +extension Int32: MustacheTransformable {} +extension Int64: MustacheTransformable {} +extension UInt: MustacheTransformable {} +extension UInt8: MustacheTransformable {} +extension UInt16: MustacheTransformable {} +extension UInt32: MustacheTransformable {} +extension UInt64: MustacheTransformable {} diff --git a/Tests/HummingbirdMustacheTests/ErrorTests.swift b/Tests/HummingbirdMustacheTests/ErrorTests.swift index 9330c62..daaeafe 100644 --- a/Tests/HummingbirdMustacheTests/ErrorTests.swift +++ b/Tests/HummingbirdMustacheTests/ErrorTests.swift @@ -17,14 +17,14 @@ import XCTest final class ErrorTests: XCTestCase { func testSectionCloseNameIncorrect() { - XCTAssertThrowsError(try HBMustacheTemplate(string: """ + XCTAssertThrowsError(try MustacheTemplate(string: """ {{#test}} {{.}} {{/test2}} """)) { error in switch error { - case let error as HBMustacheTemplate.ParserError: - XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .sectionCloseNameIncorrect) + case let error as MustacheTemplate.ParserError: + XCTAssertEqual(error.error as? MustacheTemplate.Error, .sectionCloseNameIncorrect) XCTAssertEqual(error.context.line, "{{/test2}}") XCTAssertEqual(error.context.lineNumber, 3) XCTAssertEqual(error.context.columnNumber, 4) @@ -36,14 +36,14 @@ final class ErrorTests: XCTestCase { } func testUnfinishedName() { - XCTAssertThrowsError(try HBMustacheTemplate(string: """ + XCTAssertThrowsError(try MustacheTemplate(string: """ {{#test}} {{name} {{/test2}} """)) { error in switch error { - case let error as HBMustacheTemplate.ParserError: - XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .unfinishedName) + case let error as MustacheTemplate.ParserError: + XCTAssertEqual(error.error as? MustacheTemplate.Error, .unfinishedName) XCTAssertEqual(error.context.line, "{{name}") XCTAssertEqual(error.context.lineNumber, 2) XCTAssertEqual(error.context.columnNumber, 7) @@ -55,13 +55,13 @@ final class ErrorTests: XCTestCase { } func testExpectedSectionEnd() { - XCTAssertThrowsError(try HBMustacheTemplate(string: """ + XCTAssertThrowsError(try MustacheTemplate(string: """ {{#test}} {{.}} """)) { error in switch error { - case let error as HBMustacheTemplate.ParserError: - XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .expectedSectionEnd) + case let error as MustacheTemplate.ParserError: + XCTAssertEqual(error.error as? MustacheTemplate.Error, .expectedSectionEnd) XCTAssertEqual(error.context.line, "{{.}}") XCTAssertEqual(error.context.lineNumber, 2) XCTAssertEqual(error.context.columnNumber, 6) @@ -73,14 +73,14 @@ final class ErrorTests: XCTestCase { } func testInvalidSetDelimiter() { - XCTAssertThrowsError(try HBMustacheTemplate(string: """ + XCTAssertThrowsError(try MustacheTemplate(string: """ {{=<% %>=}} <%.%> <%={{}}=%> """)) { error in switch error { - case let error as HBMustacheTemplate.ParserError: - XCTAssertEqual(error.error as? HBMustacheTemplate.Error, .invalidSetDelimiter) + case let error as MustacheTemplate.ParserError: + XCTAssertEqual(error.error as? MustacheTemplate.Error, .invalidSetDelimiter) XCTAssertEqual(error.context.line, "<%={{}}=%>") XCTAssertEqual(error.context.lineNumber, 3) XCTAssertEqual(error.context.columnNumber, 4) diff --git a/Tests/HummingbirdMustacheTests/LibraryTests.swift b/Tests/HummingbirdMustacheTests/LibraryTests.swift index 5a92bcf..d195b62 100644 --- a/Tests/HummingbirdMustacheTests/LibraryTests.swift +++ b/Tests/HummingbirdMustacheTests/LibraryTests.swift @@ -24,7 +24,7 @@ final class LibraryTests: XCTestCase { try mustache.write(to: URL(fileURLWithPath: "templates/test.mustache")) defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/test.mustache")) } - let library = try await HBMustacheLibrary(directory: "./templates") + let library = try await MustacheLibrary(directory: "./templates") let object = ["value": ["value1", "value2"]] XCTAssertEqual(library.render(object, withTemplate: "test"), "value1value2") } @@ -42,7 +42,7 @@ final class LibraryTests: XCTestCase { XCTAssertNoThrow(try fs.removeItem(atPath: "templates")) } - let library = try await HBMustacheLibrary(directory: "./templates") + let library = try await MustacheLibrary(directory: "./templates") let object = ["value": ["value1", "value2"]] XCTAssertEqual(library.render(object, withTemplate: "test"), "value1value2") } @@ -63,8 +63,8 @@ final class LibraryTests: XCTestCase { defer { XCTAssertNoThrow(try fs.removeItem(atPath: "templates/error.mustache")) } do { - _ = try await HBMustacheLibrary(directory: "./templates") - } catch let parserError as HBMustacheLibrary.ParserError { + _ = try await MustacheLibrary(directory: "./templates") + } catch let parserError as MustacheLibrary.ParserError { XCTAssertEqual(parserError.filename, "error.mustache") XCTAssertEqual(parserError.context.line, "{{{name}}") XCTAssertEqual(parserError.context.lineNumber, 2) diff --git a/Tests/HummingbirdMustacheTests/PartialTests.swift b/Tests/HummingbirdMustacheTests/PartialTests.swift index c489c9f..f8ecc97 100644 --- a/Tests/HummingbirdMustacheTests/PartialTests.swift +++ b/Tests/HummingbirdMustacheTests/PartialTests.swift @@ -16,132 +16,132 @@ import XCTest final class PartialTests: XCTestCase { - /// Testing partials - func testMustacheManualExample9() throws { - let template = try HBMustacheTemplate(string: """ -

Names

- {{#names}} - {{> user}} - {{/names}} - """) - let template2 = try HBMustacheTemplate(string: """ - {{.}} - - """) - let library = HBMustacheLibrary(templates: ["base": template, "user": template2]) - - let object: [String: Any] = ["names": ["john", "adam", "claire"]] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire - - """) - } - - /// Test where last line of partial generates no content. It should not add a - /// tab either - func testPartialEmptyLineTabbing() throws { - let template = try HBMustacheTemplate(string: """ -

Names

- {{#names}} - {{> user}} - {{/names}} - Text after - - """) - let template2 = try HBMustacheTemplate(string: """ - {{^empty(.)}} - {{.}} - {{/empty(.)}} - {{#empty(.)}} - empty - {{/empty(.)}} - - """) - var library = HBMustacheLibrary() - library.register(template, named: "base") - library.register(template2, named: "user") // , withTemplate: String)// = HBMustacheLibrary(templates: ["base": template, "user": template2]) - - let object: [String: Any] = ["names": ["john", "adam", "claire"]] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire - Text after - - """) - } - - /// Testing dynamic partials - func testDynamicPartials() throws { - let template = try HBMustacheTemplate(string: """ -

Names

- {{partial}} - """) - let template2 = try HBMustacheTemplate(string: """ - {{#names}} - {{.}} - {{/names}} - """) - let library = HBMustacheLibrary(templates: ["base": template]) - - let object: [String: Any] = ["names": ["john", "adam", "claire"], "partial": template2] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire - - """) - } - - /// test inheritance - func testInheritance() throws { - var library = HBMustacheLibrary() - try library.register( - """ - - {{$title}}Default title{{/title}} - - - """, - named: "header" - ) - try library.register( - """ - - {{$header}}{{/header}} - {{$content}}{{/content}} - - - """, - named: "base" - ) - try library.register( - """ - {{Hello world{{/content}} - {{/base}} - - """, - named: "mypage" - ) - XCTAssertEqual(library.render({}, withTemplate: "mypage")!, """ - - - My page title - -

Hello world

- - - """) - } + /// Testing partials + func testMustacheManualExample9() throws { + let template = try MustacheTemplate(string: """ +

Names

+ {{#names}} + {{> user}} + {{/names}} + """) + let template2 = try MustacheTemplate(string: """ + {{.}} + + """) + let library = MustacheLibrary(templates: ["base": template, "user": template2]) + + let object: [String: Any] = ["names": ["john", "adam", "claire"]] + XCTAssertEqual(library.render(object, withTemplate: "base"), """ +

Names

+ john + adam + claire + + """) + } + + /// Test where last line of partial generates no content. It should not add a + /// tab either + func testPartialEmptyLineTabbing() throws { + let template = try MustacheTemplate(string: """ +

Names

+ {{#names}} + {{> user}} + {{/names}} + Text after + + """) + let template2 = try MustacheTemplate(string: """ + {{^empty(.)}} + {{.}} + {{/empty(.)}} + {{#empty(.)}} + empty + {{/empty(.)}} + + """) + var library = MustacheLibrary() + library.register(template, named: "base") + library.register(template2, named: "user") // , withTemplate: String)// = MustacheLibrary(templates: ["base": template, "user": template2]) + + let object: [String: Any] = ["names": ["john", "adam", "claire"]] + XCTAssertEqual(library.render(object, withTemplate: "base"), """ +

Names

+ john + adam + claire + Text after + + """) + } + + /// Testing dynamic partials + func testDynamicPartials() throws { + let template = try MustacheTemplate(string: """ +

Names

+ {{partial}} + """) + let template2 = try MustacheTemplate(string: """ + {{#names}} + {{.}} + {{/names}} + """) + let library = MustacheLibrary(templates: ["base": template]) + + let object: [String: Any] = ["names": ["john", "adam", "claire"], "partial": template2] + XCTAssertEqual(library.render(object, withTemplate: "base"), """ +

Names

+ john + adam + claire + + """) + } + + /// test inheritance + func testInheritance() throws { + var library = MustacheLibrary() + try library.register( + """ + + {{$title}}Default title{{/title}} + + + """, + named: "header" + ) + try library.register( + """ + + {{$header}}{{/header}} + {{$content}}{{/content}} + + + """, + named: "base" + ) + try library.register( + """ + {{Hello world{{/content}} + {{/base}} + + """, + named: "mypage" + ) + XCTAssertEqual(library.render({}, withTemplate: "mypage")!, """ + + + My page title + +

Hello world

+ + + """) + } } diff --git a/Tests/HummingbirdMustacheTests/SpecTests.swift b/Tests/HummingbirdMustacheTests/SpecTests.swift index 593d1df..e563ddc 100644 --- a/Tests/HummingbirdMustacheTests/SpecTests.swift +++ b/Tests/HummingbirdMustacheTests/SpecTests.swift @@ -68,17 +68,17 @@ final class MustacheSpecTests: XCTestCase { func run() throws { // print("Test: \(self.name)") if let partials = self.partials { - let template = try HBMustacheTemplate(string: self.template) - var templates: [String: HBMustacheTemplate] = ["__test__": template] + let template = try MustacheTemplate(string: self.template) + var templates: [String: MustacheTemplate] = ["__test__": template] for (key, value) in partials { - let template = try HBMustacheTemplate(string: value) + let template = try MustacheTemplate(string: value) templates[key] = template } - let library = HBMustacheLibrary(templates: templates) + let library = MustacheLibrary(templates: templates) let result = library.render(self.data.value, withTemplate: "__test__") self.XCTAssertSpecEqual(result, self) } else { - let template = try HBMustacheTemplate(string: self.template) + let template = try MustacheTemplate(string: self.template) let result = template.render(self.data.value) self.XCTAssertSpecEqual(result, self) } diff --git a/Tests/HummingbirdMustacheTests/TemplateParserTests.swift b/Tests/HummingbirdMustacheTests/TemplateParserTests.swift index c5deca6..6c53ffe 100644 --- a/Tests/HummingbirdMustacheTests/TemplateParserTests.swift +++ b/Tests/HummingbirdMustacheTests/TemplateParserTests.swift @@ -17,55 +17,55 @@ import XCTest final class TemplateParserTests: XCTestCase { func testText() throws { - let template = try HBMustacheTemplate(string: "test template") + let template = try MustacheTemplate(string: "test template") XCTAssertEqual(template.tokens, [.text("test template")]) } func testVariable() throws { - let template = try HBMustacheTemplate(string: "test {{variable}}") + let template = try MustacheTemplate(string: "test {{variable}}") XCTAssertEqual(template.tokens, [.text("test "), .variable(name: "variable")]) } func testSection() throws { - let template = try HBMustacheTemplate(string: "test {{#section}}text{{/section}}") + let template = try MustacheTemplate(string: "test {{#section}}text{{/section}}") XCTAssertEqual(template.tokens, [.text("test "), .section(name: "section", template: .init([.text("text")]))]) } func testInvertedSection() throws { - let template = try HBMustacheTemplate(string: "test {{^section}}text{{/section}}") + let template = try MustacheTemplate(string: "test {{^section}}text{{/section}}") XCTAssertEqual(template.tokens, [.text("test "), .invertedSection(name: "section", template: .init([.text("text")]))]) } func testComment() throws { - let template = try HBMustacheTemplate(string: "test {{!section}}") + let template = try MustacheTemplate(string: "test {{!section}}") XCTAssertEqual(template.tokens, [.text("test ")]) } func testWhitespace() throws { - let template = try HBMustacheTemplate(string: "{{ section }}") + let template = try MustacheTemplate(string: "{{ section }}") XCTAssertEqual(template.tokens, [.variable(name: "section")]) } func testContentType() throws { - let template = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}") - let template1 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:TEXT }}") - let template2 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE: TEXT}}") - let template3 = try HBMustacheTemplate(string: "{{%CONTENT_TYPE:TEXT}}") - XCTAssertEqual(template.tokens, [.contentType(HBTextContentType())]) - XCTAssertEqual(template1.tokens, [.contentType(HBTextContentType())]) - XCTAssertEqual(template2.tokens, [.contentType(HBTextContentType())]) - XCTAssertEqual(template3.tokens, [.contentType(HBTextContentType())]) + let template = try MustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}") + let template1 = try MustacheTemplate(string: "{{% CONTENT_TYPE:TEXT }}") + let template2 = try MustacheTemplate(string: "{{% CONTENT_TYPE: TEXT}}") + let template3 = try MustacheTemplate(string: "{{%CONTENT_TYPE:TEXT}}") + XCTAssertEqual(template.tokens, [.contentType(TextContentType())]) + XCTAssertEqual(template1.tokens, [.contentType(TextContentType())]) + XCTAssertEqual(template2.tokens, [.contentType(TextContentType())]) + XCTAssertEqual(template3.tokens, [.contentType(TextContentType())]) } } -extension HBMustacheTemplate: Equatable { - public static func == (lhs: HBMustacheTemplate, rhs: HBMustacheTemplate) -> Bool { +extension MustacheTemplate: Equatable { + public static func == (lhs: MustacheTemplate, rhs: MustacheTemplate) -> Bool { lhs.tokens == rhs.tokens } } -extension HBMustacheTemplate.Token: Equatable { - public static func == (lhs: HBMustacheTemplate.Token, rhs: HBMustacheTemplate.Token) -> Bool { +extension MustacheTemplate.Token: Equatable { + public static func == (lhs: MustacheTemplate.Token, rhs: MustacheTemplate.Token) -> Bool { switch (lhs, rhs) { case (.text(let lhs), .text(let rhs)): return lhs == rhs diff --git a/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift b/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift index c22f3e4..0c6a29a 100644 --- a/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift +++ b/Tests/HummingbirdMustacheTests/TemplateRendererTests.swift @@ -17,50 +17,50 @@ import XCTest final class TemplateRendererTests: XCTestCase { func testText() throws { - let template = try HBMustacheTemplate(string: "test text") + let template = try MustacheTemplate(string: "test text") XCTAssertEqual(template.render("test"), "test text") } func testStringVariable() throws { - let template = try HBMustacheTemplate(string: "test {{.}}") + let template = try MustacheTemplate(string: "test {{.}}") XCTAssertEqual(template.render("text"), "test text") } func testIntegerVariable() throws { - let template = try HBMustacheTemplate(string: "test {{.}}") + let template = try MustacheTemplate(string: "test {{.}}") XCTAssertEqual(template.render(101), "test 101") } func testDictionary() throws { - let template = try HBMustacheTemplate(string: "test {{value}} {{bool}}") + let template = try MustacheTemplate(string: "test {{value}} {{bool}}") XCTAssertEqual(template.render(["value": "test2", "bool": true]), "test test2 true") } func testArraySection() throws { - let template = try HBMustacheTemplate(string: "test {{#value}}*{{.}}{{/value}}") + let template = try MustacheTemplate(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 ") } func testBooleanSection() throws { - let template = try HBMustacheTemplate(string: "test {{#.}}Yep{{/.}}") + let template = try MustacheTemplate(string: "test {{#.}}Yep{{/.}}") XCTAssertEqual(template.render(true), "test Yep") XCTAssertEqual(template.render(false), "test ") } func testIntegerSection() throws { - let template = try HBMustacheTemplate(string: "test {{#.}}{{.}}{{/.}}") + let template = try MustacheTemplate(string: "test {{#.}}{{.}}{{/.}}") XCTAssertEqual(template.render(23), "test 23") } func testStringSection() throws { - let template = try HBMustacheTemplate(string: "test {{#.}}{{.}}{{/.}}") + let template = try MustacheTemplate(string: "test {{#.}}{{.}}{{/.}}") XCTAssertEqual(template.render("Hello"), "test Hello") } func testInvertedSection() throws { - let template = try HBMustacheTemplate(string: "test {{^.}}Inverted{{/.}}") + let template = try MustacheTemplate(string: "test {{^.}}Inverted{{/.}}") XCTAssertEqual(template.render(true), "test ") XCTAssertEqual(template.render(false), "test Inverted") } @@ -69,7 +69,7 @@ final class TemplateRendererTests: XCTestCase { struct Test { let string: String } - let template = try HBMustacheTemplate(string: "test {{string}}") + let template = try MustacheTemplate(string: "test {{string}}") XCTAssertEqual(template.render(Test(string: "string")), "test string") } @@ -77,7 +77,7 @@ final class TemplateRendererTests: XCTestCase { struct Test { let string: String? } - let template = try HBMustacheTemplate(string: "test {{string}}") + let template = try MustacheTemplate(string: "test {{string}}") XCTAssertEqual(template.render(Test(string: "string")), "test string") XCTAssertEqual(template.render(Test(string: nil)), "test ") } @@ -86,10 +86,10 @@ final class TemplateRendererTests: XCTestCase { struct Test { let string: String? } - let template = try HBMustacheTemplate(string: "test {{#string}}*{{.}}{{/string}}") + let template = try MustacheTemplate(string: "test {{#string}}*{{.}}{{/string}}") XCTAssertEqual(template.render(Test(string: "string")), "test *string") XCTAssertEqual(template.render(Test(string: nil)), "test ") - let template2 = try HBMustacheTemplate(string: "test {{^string}}*{{/string}}") + let template2 = try MustacheTemplate(string: "test {{^string}}*{{/string}}") XCTAssertEqual(template2.render(Test(string: "string")), "test ") XCTAssertEqual(template2.render(Test(string: nil)), "test *") } @@ -98,7 +98,7 @@ final class TemplateRendererTests: XCTestCase { struct Test { let string: String? } - let template = try HBMustacheTemplate(string: "test {{#.}}{{string}}{{/.}}") + let template = try MustacheTemplate(string: "test {{#.}}{{string}}{{/.}}") XCTAssertEqual(template.render([Test(string: "string")]), "test string") } @@ -106,7 +106,7 @@ final class TemplateRendererTests: XCTestCase { struct Test { let string: String? } - let template = try HBMustacheTemplate(string: "test {{#.}}{{#string}}*{{.}}{{/string}}{{/.}}") + let template = try MustacheTemplate(string: "test {{#.}}{{#string}}*{{.}}{{/string}}{{/.}}") XCTAssertEqual(template.render([Test(string: "string")]), "test *string") } @@ -118,20 +118,20 @@ final class TemplateRendererTests: XCTestCase { let test: SubTest } - let template = try HBMustacheTemplate(string: "test {{test.string}}") + let template = try MustacheTemplate(string: "test {{test.string}}") XCTAssertEqual(template.render(Test(test: .init(string: "sub"))), "test sub") } func testTextEscaping() throws { - let template1 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}{{.}}") + let template1 = try MustacheTemplate(string: "{{% CONTENT_TYPE:TEXT}}{{.}}") XCTAssertEqual(template1.render("<>"), "<>") - let template2 = try HBMustacheTemplate(string: "{{% CONTENT_TYPE:HTML}}{{.}}") + let template2 = try MustacheTemplate(string: "{{% CONTENT_TYPE:HTML}}{{.}}") XCTAssertEqual(template2.render("<>"), "<>") } func testStopClimbingStack() throws { - let template1 = try HBMustacheTemplate(string: "{{#test}}{{name}}{{/test}}") - let template2 = try HBMustacheTemplate(string: "{{#test}}{{.name}}{{/test}}") + let template1 = try MustacheTemplate(string: "{{#test}}{{name}}{{/test}}") + let template2 = try MustacheTemplate(string: "{{#test}}{{.name}}{{/test}}") let object: [String: Any] = ["test": [:], "name": "John"] let object2: [String: Any] = ["test": ["name": "Jane"], "name": "John"] XCTAssertEqual(template1.render(object), "John") @@ -141,7 +141,7 @@ final class TemplateRendererTests: XCTestCase { /// variables func testMustacheManualExample1() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ Hello {{name}} You have just won {{value}} dollars! {{#in_ca}} @@ -159,7 +159,7 @@ final class TemplateRendererTests: XCTestCase { /// test esacped and unescaped text func testMustacheManualExample2() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ *{{name}} *{{age}} *{{company}} @@ -176,7 +176,7 @@ final class TemplateRendererTests: XCTestCase { /// test boolean func testMustacheManualExample3() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ Shown. {{#person}} Never shown! @@ -191,7 +191,7 @@ final class TemplateRendererTests: XCTestCase { /// test non-empty lists func testMustacheManualExample4() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{name}} {{/repo}} @@ -207,13 +207,13 @@ final class TemplateRendererTests: XCTestCase { /// test lambdas func testMustacheManualExample5() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#wrapped}}{{name}} is awesome.{{/wrapped}} """) - func wrapped(object: Any, template: HBMustacheTemplate) -> String { + func wrapped(object: Any, template: MustacheTemplate) -> String { return "\(template.render(object))" } - let object: [String: Any] = ["name": "Willy", "wrapped": HBMustacheLambda(wrapped)] + let object: [String: Any] = ["name": "Willy", "wrapped": MustacheLambda(wrapped)] XCTAssertEqual(template.render(object), """ Willy is awesome. """) @@ -221,7 +221,7 @@ final class TemplateRendererTests: XCTestCase { /// test setting context object func testMustacheManualExample6() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#person?}} Hi {{name}}! {{/person?}} @@ -235,7 +235,7 @@ final class TemplateRendererTests: XCTestCase { /// test inverted sections func testMustacheManualExample7() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{name}} {{/repo}} @@ -252,7 +252,7 @@ final class TemplateRendererTests: XCTestCase { /// test comments func testMustacheManualExample8() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """

Today{{! ignore me }}.

""") let object: [String: Any] = ["repo": []] @@ -261,12 +261,12 @@ final class TemplateRendererTests: XCTestCase { """) } - /// test HBMustacheCustomRenderable + /// test MustacheCustomRenderable func testCustomRenderable() throws { - let template = try HBMustacheTemplate(string: "{{.}}") - let template1 = try HBMustacheTemplate(string: "{{#.}}not null{{/.}}") - let template2 = try HBMustacheTemplate(string: "{{^.}}null{{/.}}") - struct Object: HBMustacheCustomRenderable { + let template = try MustacheTemplate(string: "{{.}}") + let template1 = try MustacheTemplate(string: "{{#.}}not null{{/.}}") + let template2 = try MustacheTemplate(string: "{{^.}}null{{/.}}") + struct Object: MustacheCustomRenderable { let value: String var renderText: String { self.value.uppercased() } @@ -282,7 +282,7 @@ final class TemplateRendererTests: XCTestCase { } func testPerformance() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{name}} {{/repo}} diff --git a/Tests/HummingbirdMustacheTests/TransformTests.swift b/Tests/HummingbirdMustacheTests/TransformTests.swift index 1a938c8..14d0e7c 100644 --- a/Tests/HummingbirdMustacheTests/TransformTests.swift +++ b/Tests/HummingbirdMustacheTests/TransformTests.swift @@ -17,7 +17,7 @@ import XCTest final class TransformTests: XCTestCase { func testLowercased() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{ lowercased(name) }} """) let object: [String: Any] = ["name": "Test"] @@ -25,7 +25,7 @@ final class TransformTests: XCTestCase { } func testUppercased() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{ uppercased(name) }} """) let object: [String: Any] = ["name": "Test"] @@ -33,7 +33,7 @@ final class TransformTests: XCTestCase { } func testNewline() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{name}} {{/repo}} @@ -49,7 +49,7 @@ final class TransformTests: XCTestCase { } func testFirstLast() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{#first()}}first: {{/first()}}{{#last()}}last: {{/last()}}{{ name }} {{/repo}} @@ -65,7 +65,7 @@ final class TransformTests: XCTestCase { } func testIndex() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{#index()}}{{plusone(.)}}{{/index()}}) {{ name }} {{/repo}} @@ -81,7 +81,7 @@ final class TransformTests: XCTestCase { } func testEvenOdd() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{index()}}) {{#even()}}even {{/even()}}{{#odd()}}odd {{/odd()}}{{ name }} {{/repo}} @@ -97,7 +97,7 @@ final class TransformTests: XCTestCase { } func testReversed() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#reversed(repo)}} {{ name }} {{/reversed(repo)}} @@ -113,7 +113,7 @@ final class TransformTests: XCTestCase { } func testArrayIndex() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#repo}} {{ index() }}) {{ name }} {{/repo}} @@ -128,7 +128,7 @@ final class TransformTests: XCTestCase { } func testArraySorted() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#sorted(repo)}} {{ index() }}) {{ . }} {{/sorted(repo)}} @@ -143,7 +143,7 @@ final class TransformTests: XCTestCase { } func testDictionaryEmpty() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#empty(array)}}Array{{/empty(array)}}{{#empty(dictionary)}}Dictionary{{/empty(dictionary)}} """) let object: [String: Any] = ["array": [], "dictionary": [:]] @@ -152,12 +152,12 @@ final class TransformTests: XCTestCase { func testListOutput() throws { let object = [1, 2, 3, 4] - let template = try HBMustacheTemplate(string: "{{#.}}{{.}}{{^last()}}, {{/last()}}{{/.}}") + let template = try MustacheTemplate(string: "{{#.}}{{.}}{{^last()}}, {{/last()}}{{/.}}") XCTAssertEqual(template.render(object), "1, 2, 3, 4") } func testDictionaryEnumerated() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#enumerated(.)}}{{ key }} = {{ value }}{{/enumerated(.)}} """) let object: [String: Any] = ["one": 1, "two": 2] @@ -166,7 +166,7 @@ final class TransformTests: XCTestCase { } func testDictionarySortedByKey() throws { - let template = try HBMustacheTemplate(string: """ + let template = try MustacheTemplate(string: """ {{#sorted(.)}}{{ key }} = {{ value }}{{/sorted(.)}} """) let object: [String: Any] = ["one": 1, "two": 2, "three": 3] diff --git a/documentation/Lambdas.md b/documentation/Lambdas.md index f09f178..ccd9f3e 100644 --- a/documentation/Lambdas.md +++ b/documentation/Lambdas.md @@ -2,17 +2,17 @@ The library doesn't provide a lambda implementation but it does provide something akin to the lambda feature. -Add a `HBMustacheLambda` to the object you want to be rendered and it can be used in a similar way to lambdas are used in Mustache. When you create a section referencing the lambda the contents of the section are passed as a template along with the current object to the lamdba function. This is slightly different from the standard implementation where the unprocessed text is passed to the lambda. +Add a `MustacheLambda` to the object you want to be rendered and it can be used in a similar way to lambdas are used in Mustache. When you create a section referencing the lambda the contents of the section are passed as a template along with the current object to the lamdba function. This is slightly different from the standard implementation where the unprocessed text is passed to the lambda. Given the object `person` defined below ```swift struct Person { let name: String - let wrapped: HBMustacheLambda + let wrapped: MustacheLambda } let person = Person( name: "John", - wrapped: HBMustacheLambda { object, template in + wrapped: MustacheLambda { object, template in return "\(template.render(object))" } ) @@ -21,7 +21,7 @@ let person = Person( and the following mustache template ```swift let mustache = "{{#wrapped}}{{name}} is awesome.{{/wrapped}}" -let template = try HBMustacheTemplate(string: mustache) +let template = try MustacheTemplate(string: mustache) ``` Then `template.render(person)` will output ``` diff --git a/documentation/Transforms.md b/documentation/Transforms.md index 06858cf..4dd4d28 100644 --- a/documentation/Transforms.md +++ b/documentation/Transforms.md @@ -52,9 +52,9 @@ The following sequence context transforms are available ## Custom transforms -You can add transforms to your own objects. Conform the object to `HBMustacheTransformable` and provide an implementation of the function `transform`. eg +You can add transforms to your own objects. Conform the object to `MustacheTransformable` and provide an implementation of the function `transform`. eg ```swift -struct Object: HBMustacheTransformable { +struct Object: MustacheTransformable { let either: Bool let or: Bool From ec458b4c32310c3d25dbdc15c61aba6b46804928 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Sun, 10 Mar 2024 11:48:31 +0000 Subject: [PATCH 2/3] Add deprecations --- .../HummingbirdMustache/Deprecations.swift | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Sources/HummingbirdMustache/Deprecations.swift diff --git a/Sources/HummingbirdMustache/Deprecations.swift b/Sources/HummingbirdMustache/Deprecations.swift new file mode 100644 index 0000000..58952aa --- /dev/null +++ b/Sources/HummingbirdMustache/Deprecations.swift @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Hummingbird server framework project +// +// Copyright (c) 2024 the Hummingbird authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +// Below is a list of deprecated symbols with the "HB" prefix. These are available +// temporarily to ease transition from the old symbols that included the "HB" +// prefix to the new ones. +// +// This file will be removed before we do a 2.0 release + +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheContentType") +public typealias HBMustacheContentType = MustacheContentType +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheContentTypes") +public typealias HBMustacheContentTypes = MustacheContentTypes +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheCustomRenderable") +public typealias HBMustacheCustomRenderable = MustacheCustomRenderable +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheLambda") +public typealias HBMustacheLambda = MustacheLambda +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheLibrary") +public typealias HBMustacheLibrary = MustacheLibrary +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheParent") +public typealias HBMustacheParent = MustacheParent +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheParserContext") +public typealias HBMustacheParserContext = MustacheParserContext +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheTemplate") +public typealias HBMustacheTemplate = MustacheTemplate +@_documentation(visibility: internal) @available(*, deprecated, renamed: "MustacheTransformable") +public typealias HBMustacheTransformable = MustacheTransformable From 1de4c1c3a5e064f9dda48f8dac5e1e18d8518fb2 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Mon, 11 Mar 2024 21:59:18 +0000 Subject: [PATCH 3/3] swift-format --- .../PartialTests.swift | 256 +++++++++--------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/Tests/HummingbirdMustacheTests/PartialTests.swift b/Tests/HummingbirdMustacheTests/PartialTests.swift index f8ecc97..b296331 100644 --- a/Tests/HummingbirdMustacheTests/PartialTests.swift +++ b/Tests/HummingbirdMustacheTests/PartialTests.swift @@ -16,132 +16,132 @@ import XCTest final class PartialTests: XCTestCase { - /// Testing partials - func testMustacheManualExample9() throws { - let template = try MustacheTemplate(string: """ -

Names

- {{#names}} - {{> user}} - {{/names}} - """) - let template2 = try MustacheTemplate(string: """ - {{.}} - - """) - let library = MustacheLibrary(templates: ["base": template, "user": template2]) - - let object: [String: Any] = ["names": ["john", "adam", "claire"]] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire - - """) - } - - /// Test where last line of partial generates no content. It should not add a - /// tab either - func testPartialEmptyLineTabbing() throws { - let template = try MustacheTemplate(string: """ -

Names

- {{#names}} - {{> user}} - {{/names}} - Text after - - """) - let template2 = try MustacheTemplate(string: """ - {{^empty(.)}} - {{.}} - {{/empty(.)}} - {{#empty(.)}} - empty - {{/empty(.)}} - - """) - var library = MustacheLibrary() - library.register(template, named: "base") - library.register(template2, named: "user") // , withTemplate: String)// = MustacheLibrary(templates: ["base": template, "user": template2]) - - let object: [String: Any] = ["names": ["john", "adam", "claire"]] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire - Text after - - """) - } - - /// Testing dynamic partials - func testDynamicPartials() throws { - let template = try MustacheTemplate(string: """ -

Names

- {{partial}} - """) - let template2 = try MustacheTemplate(string: """ - {{#names}} - {{.}} - {{/names}} - """) - let library = MustacheLibrary(templates: ["base": template]) - - let object: [String: Any] = ["names": ["john", "adam", "claire"], "partial": template2] - XCTAssertEqual(library.render(object, withTemplate: "base"), """ -

Names

- john - adam - claire - - """) - } - - /// test inheritance - func testInheritance() throws { - var library = MustacheLibrary() - try library.register( - """ - - {{$title}}Default title{{/title}} - - - """, - named: "header" - ) - try library.register( - """ - - {{$header}}{{/header}} - {{$content}}{{/content}} - - - """, - named: "base" - ) - try library.register( - """ - {{Hello world{{/content}} - {{/base}} - - """, - named: "mypage" - ) - XCTAssertEqual(library.render({}, withTemplate: "mypage")!, """ - - - My page title - -

Hello world

- - - """) - } + /// Testing partials + func testMustacheManualExample9() throws { + let template = try MustacheTemplate(string: """ +

Names

+ {{#names}} + {{> user}} + {{/names}} + """) + let template2 = try MustacheTemplate(string: """ + {{.}} + + """) + let library = MustacheLibrary(templates: ["base": template, "user": template2]) + + let object: [String: Any] = ["names": ["john", "adam", "claire"]] + XCTAssertEqual(library.render(object, withTemplate: "base"), """ +

Names

+ john + adam + claire + + """) + } + + /// Test where last line of partial generates no content. It should not add a + /// tab either + func testPartialEmptyLineTabbing() throws { + let template = try MustacheTemplate(string: """ +

Names

+ {{#names}} + {{> user}} + {{/names}} + Text after + + """) + let template2 = try MustacheTemplate(string: """ + {{^empty(.)}} + {{.}} + {{/empty(.)}} + {{#empty(.)}} + empty + {{/empty(.)}} + + """) + var library = MustacheLibrary() + library.register(template, named: "base") + library.register(template2, named: "user") // , withTemplate: String)// = MustacheLibrary(templates: ["base": template, "user": template2]) + + let object: [String: Any] = ["names": ["john", "adam", "claire"]] + XCTAssertEqual(library.render(object, withTemplate: "base"), """ +

Names

+ john + adam + claire + Text after + + """) + } + + /// Testing dynamic partials + func testDynamicPartials() throws { + let template = try MustacheTemplate(string: """ +

Names

+ {{partial}} + """) + let template2 = try MustacheTemplate(string: """ + {{#names}} + {{.}} + {{/names}} + """) + let library = MustacheLibrary(templates: ["base": template]) + + let object: [String: Any] = ["names": ["john", "adam", "claire"], "partial": template2] + XCTAssertEqual(library.render(object, withTemplate: "base"), """ +

Names

+ john + adam + claire + + """) + } + + /// test inheritance + func testInheritance() throws { + var library = MustacheLibrary() + try library.register( + """ + + {{$title}}Default title{{/title}} + + + """, + named: "header" + ) + try library.register( + """ + + {{$header}}{{/header}} + {{$content}}{{/content}} + + + """, + named: "base" + ) + try library.register( + """ + {{Hello world{{/content}} + {{/base}} + + """, + named: "mypage" + ) + XCTAssertEqual(library.render({}, withTemplate: "mypage")!, """ + + + My page title + +

Hello world

+ + + """) + } }