diff --git a/Package.swift b/Package.swift index e8a5d84..58b51f5 100644 --- a/Package.swift +++ b/Package.swift @@ -1,34 +1,17 @@ // swift-tools-version:4.0 -// -// Package.swift -// PerfectMustache -// -// Created by Kyle Jessup on 2016-05-02. -// Copyright (C) 2016 PerfectlySoft, Inc. -// -//===----------------------------------------------------------------------===// -// -// This source file is part of the Perfect.org open source project -// -// Copyright (c) 2015 - 2018 PerfectlySoft Inc. and the Perfect project authors -// Licensed under Apache License v2.0 -// -// See http://perfect.org/licensing.html for license information -// -//===----------------------------------------------------------------------===// -// - +// Generated automatically by Perfect Assistant +// Date: 2018-05-31 18:31:13 +0000 import PackageDescription -let package = Package(name: "PerfectMustache", - products: [.library(name: "PerfectMustache",targets: ["PerfectMustache"]),], - dependencies: [ - .package(url: "https://github.com/PerfectlySoft/Perfect-HTTP.git", from: "3.0.0"), + +let package = Package( + name: "PerfectMustache", + products: [ + .library(name: "PerfectMustache", targets: ["PerfectMustache"]) ], - targets: [ - .target( - name: "PerfectMustache", - dependencies: ["PerfectHTTP"]), - .testTarget( - name: "PerfectMustacheTests", - dependencies: ["PerfectMustache"]), - ]) \ No newline at end of file + dependencies: [ + ], + targets: [ + .target(name: "PerfectMustache", dependencies: []), + .testTarget(name: "PerfectMustacheTests", dependencies: ["PerfectMustache"]) + ] +) diff --git a/Sources/PerfectMustache/HTTPResponseExtension.swift b/Sources/PerfectMustache/HTTPResponseExtension.swift deleted file mode 100644 index e56a325..0000000 --- a/Sources/PerfectMustache/HTTPResponseExtension.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// HTTPResponseExtension.swift -// PerfectMustache -// -// Created by Jonathan Guthrie on 2017-08-01. -// Copyright (C) 2017 PerfectlySoft, Inc. -// -//===----------------------------------------------------------------------===// -// -// This source file is part of the Perfect.org open source project -// -// Copyright (c) 2015 - 2016 PerfectlySoft Inc. and the Perfect project authors -// Licensed under Apache License v2.0 -// -// See http://perfect.org/licensing.html for license information -// -//===----------------------------------------------------------------------===// -// - -import PerfectHTTP - -import Foundation -extension HTTPResponse { - public func renderMustache(template: String, context values: [String: Any] = [String: Any]()) { - let context = MustacheEvaluationContext(templatePath: template) - let collector = MustacheEvaluationOutputCollector() - context.extendValues(with: values) - do { - let d = try context.formulateResponse(withCollector: collector) - self.setBody(string: d) - .completed() - } catch { - self.setBody(string: "\(error)") - .completed(status: .internalServerError) - } - } -} diff --git a/Sources/PerfectMustache/Mustache.swift b/Sources/PerfectMustache/Mustache.swift index ce0d617..d60d13c 100644 --- a/Sources/PerfectMustache/Mustache.swift +++ b/Sources/PerfectMustache/Mustache.swift @@ -19,8 +19,6 @@ import PerfectThread import PerfectLib -import PerfectHTTP - import Foundation let mustacheExtension = "mustache" @@ -89,57 +87,25 @@ public enum MustacheError : Error { case evaluationError(String) } -/// A mustache handler, which should be passed to `mustacheRequest`, generates values to fill a mustache template. -/// Call `context.extendValues(with: values)` one or more times and then -/// `context.requestCompleted(withCollector collector)` to complete the request and output the resulting content to the client. -public protocol MustachePageHandler { - /// Called by the system when the handler needs to add values for the template. - func extendValuesForResponse(context contxt: MustacheWebEvaluationContext, collector: MustacheEvaluationOutputCollector) -} - -/** Convenience function to begin a mustache template request - -```swift -routes.add(method: .get, uri: "/", handler: { - request, response in - mustacheRequest(request: request, response: response, handler: UploadHandler(), path: webRoot + "/index.mustache") -}) -``` - -*/ -public func mustacheRequest(request req: HTTPRequest, response: HTTPResponse, handler: MustachePageHandler, templatePath: String) { - - let context = MustacheWebEvaluationContext(webResponse: response) - context.templatePath = templatePath - let collector = MustacheEvaluationOutputCollector() - - handler.extendValuesForResponse(context: context, collector: collector) -} - /// This class represents an individual scope for mustache template values. /// A mustache template handler will return a `MustacheEvaluationContext.MapType` object as a result from its `PageHandler.valuesForResponse` function. public class MustacheEvaluationContext { + var mapValues: MapType public typealias MapType = [String:Any] public typealias SequenceType = [MapType] - /// The parent of this context public var parent: MustacheEvaluationContext? = nil - /// Complete path to the file being processed public var templatePath: String? - /// Mustache content for dynamic generation public var templateContent: String? - /// Returns the name of the current template file. public var templateName: String? { let nam = templatePath?.lastFilePathComponent return nam } - var mapValues: MapType - public init(templatePath: String, map: MapType = MapType()) { self.templatePath = templatePath self.mapValues = map @@ -196,7 +162,6 @@ public class MustacheEvaluationContext { /// - returns: The value, if found, or nil public func getValue(named nam: String) -> MapType.Value? { let values = nam.components(separatedBy: ".") - var cntxt: MapType.Value? = mapValues for val in values { guard let prev = cntxt as? MapType else { @@ -204,7 +169,6 @@ public class MustacheEvaluationContext { } cntxt = prev[val] } - let v = cntxt if v == nil && parent != nil { return parent?.getValue(named: nam) @@ -231,48 +195,6 @@ public class MustacheEvaluationContext { } } -/// This class represents an individual scope for mustache template values. -/// A mustache template handler will return a `MustacheWebEvaluationContext.MapType` object as a result from its `PageHandler.valuesForResponse` function. -public class MustacheWebEvaluationContext: MustacheEvaluationContext { - - /// Provides access to the current HTTPResponse object. - public var webResponse: HTTPResponse - - /// Provides access to the current HTTPRequest object. - public var webRequest: HTTPRequest { - return webResponse.request - } - - init(webResponse: HTTPResponse, templatePath: String, map: MapType = MapType()) { - self.webResponse = webResponse - super.init(templatePath: templatePath, map: map) - } - - init(webResponse: HTTPResponse, map: MapType = MapType()) { - self.webResponse = webResponse - super.init(map: map) - } - - override func newChildContext() -> MustacheEvaluationContext { - let cc = MustacheWebEvaluationContext(webResponse: webResponse) - cc.parent = self - return cc - } - - override func newChildContext(withMap with: MapType) -> MustacheEvaluationContext { - let cc = MustacheWebEvaluationContext(webResponse: webResponse, map: with) - cc.parent = self - return cc - } - - /// All the template values have been completed and resulting content should be - /// formulated and returned to the client. - public func requestCompleted(withCollector collector: MustacheEvaluationOutputCollector) throws { - self.webResponse.appendBody(string: try self.formulateResponse(withCollector: collector)) - self.webResponse.completed() - } -} - /// An instance of this class will collect all output data generated by mustache tags during evaluation. /// Call the `asString()` function to retreive the resulting data. public class MustacheEvaluationOutputCollector { @@ -368,11 +290,9 @@ public class MustacheTag { /// Reconstitutes the tag into its original source string form. /// - returns: The resulting string, including the original delimiters and tag-type marker. public func description() -> String { - guard type != .plain else { return tag } - var s = delimOpen() switch type { case .name: @@ -406,7 +326,6 @@ public class MustacheTag { /// A sub-class of MustacheTag which represents a mustache "partial" tag. public class MustachePartialTag : MustacheTag { - override func clone() -> MustacheTag { let s = MustachePartialTag() self.populateClone(s) @@ -415,7 +334,6 @@ public class MustachePartialTag : MustacheTag { /// Override for evaluating the partial tag. public override func evaluate(context contxt: MustacheEvaluationContext, collector: MustacheEvaluationOutputCollector) { - guard let page = contxt.getCurrentFilePath(), !page.isEmpty else { print("Exception while executing partial \(tag): unable to find template root directory") return @@ -673,21 +591,17 @@ public class MustacheParser { /// - throws: `MustacheError.SyntaxError` /// - returns: A `MustacheTemplate` object which can be evaluated. public func parse(string strng: String) throws -> MustacheTemplate { - let t = MustacheTemplate() self.activeList = t self.g = strng.unicodeScalars.makeIterator() - try consumeLoop() - t.pragmas = pragmas - return t } func next() -> UnicodeScalar? { offset += 1 - return g!.next() + return g?.next() } func consumeLoop() throws { @@ -712,24 +626,19 @@ public class MustacheParser { func addChild(_ t: MustacheTag) { self.activeList!.children.append(t) t.parent = self.activeList! - t.openD = openDelimiters t.closeD = closeDelimiters } // Read until delimiters are encountered func consumePlain() -> MustacheTagType { - let currTag = MustacheTag() currTag.type = .plain - addChild(currTag) - while true { guard let e = next() else { return .none } - if e == openDelimiters[0] { testingPutback = String(e) if consumePossibleOpenDelimiter(index: 1) { @@ -770,12 +679,10 @@ public class MustacheParser { // Read until delimiters are encountered func consumeTag() throws -> MustacheTagType { - if let e = skipWhiteSpace() { // e is first non-white character // # ^ ! > switch e { - case "%": // pragma let tagName = consumeTagName(firstChar: skipWhiteSpace()) let newTag = MustachePragmaTag() @@ -862,11 +769,9 @@ public class MustacheParser { // reads until closing delimiters // firstChar was read as part of previous step and should be added to the result func consumeTagName(firstChar first: UnicodeScalar?) -> String { - guard let f = first else { return "" } - var s = String(f) return consumeTagName(into: &s) } @@ -970,4 +875,3 @@ public class MustacheParser { closeDelimiters = close } } - diff --git a/Tests/PerfectMustacheTests/PerfectMustacheTests.swift b/Tests/PerfectMustacheTests/PerfectMustacheTests.swift index 23bff2c..b466d75 100644 --- a/Tests/PerfectMustacheTests/PerfectMustacheTests.swift +++ b/Tests/PerfectMustacheTests/PerfectMustacheTests.swift @@ -1,51 +1,7 @@ import XCTest -import PerfectHTTP -import PerfectNet import PerfectLib @testable import PerfectMustache -class ShimHTTPRequest: HTTPRequest { - var pathComponents: [String] = [] - - var method = HTTPMethod.get - var path = "/" - var queryParams = [(String, String)]() - var protocolVersion = (1, 1) - var remoteAddress = (host: "127.0.0.1", port: 8000 as UInt16) - var serverAddress = (host: "127.0.0.1", port: 8282 as UInt16) - var serverName = "my_server" - var documentRoot = "./webroot" - var connection = NetTCP() - var urlVariables = [String:String]() - func header(_ named: HTTPRequestHeader.Name) -> String? { return nil } - func addHeader(_ named: HTTPRequestHeader.Name, value: String) {} - func setHeader(_ named: HTTPRequestHeader.Name, value: String) {} - var headers = AnyIterator<(HTTPRequestHeader.Name, String)> { return nil } - var postParams = [(String, String)]() - var postBodyBytes: [UInt8]? = nil - var postBodyString: String? = nil - var postFileUploads: [MimeReader.BodySpec]? = nil - var scratchPad = [String:Any]() -} - -class ShimHTTPResponse: HTTPResponse { - func next() {} - var request: HTTPRequest = ShimHTTPRequest() - var status: HTTPResponseStatus = .ok - var isStreaming = false - var bodyBytes = [UInt8]() - func header(_ named: HTTPResponseHeader.Name) -> String? { return nil } - func addHeader(_ named: HTTPResponseHeader.Name, value: String) -> Self { return self } - func setHeader(_ named: HTTPResponseHeader.Name, value: String) -> Self { return self } - var headers = AnyIterator<(HTTPResponseHeader.Name, String)> { return nil } - func addCookie(_: PerfectHTTP.HTTPCookie) {} - func appendBody(bytes: [UInt8]) {} - func appendBody(string: String) {} - func setBody(json: [String:Any]) throws {} - func push(callback: @escaping (Bool) -> ()) {} - func completed() {} -} - class PerfectMustacheTests: XCTestCase { func testMustacheParser1() { @@ -54,9 +10,7 @@ class PerfectMustacheTests: XCTestCase { let template = try MustacheParser().parse(string: usingTemplate) let d = ["name":"The name"] as [String:Any] - let response = ShimHTTPResponse() - - let context = MustacheWebEvaluationContext(webResponse: response, map: d) + let context = MustacheEvaluationContext(map: d) let collector = MustacheEvaluationOutputCollector() template.evaluate(context: context, collector: collector) @@ -73,9 +27,7 @@ class PerfectMustacheTests: XCTestCase { let template = try MustacheParser().parse(string: usingTemplate) let d = ["name":{ (tag:String, context:MustacheEvaluationContext) -> String in return nameVal }] as [String:Any] - let response = ShimHTTPResponse() - - let context = MustacheWebEvaluationContext(webResponse: response, map: d) + let context = MustacheEvaluationContext(map: d) let collector = MustacheEvaluationOutputCollector() template.evaluate(context: context, collector: collector) @@ -174,9 +126,7 @@ class PerfectMustacheTests: XCTestCase { let template = try MustacheParser().parse(string: usingTemplate) let d = ["name": ["first": "The", "last": "name"]] as [String:Any] - let response = ShimHTTPResponse() - - let context = MustacheWebEvaluationContext(webResponse: response, map: d) + let context = MustacheEvaluationContext(map: d) let collector = MustacheEvaluationOutputCollector() template.evaluate(context: context, collector: collector) @@ -192,9 +142,7 @@ class PerfectMustacheTests: XCTestCase { let template = try MustacheParser().parse(string: usingTemplate) let d = ["foo": ["data": ["name": ["first": "The", "last": "name"]]]] as [String:Any] - let response = ShimHTTPResponse() - - let context = MustacheWebEvaluationContext(webResponse: response, map: d) + let context = MustacheEvaluationContext(map: d) let collector = MustacheEvaluationOutputCollector() template.evaluate(context: context, collector: collector)