diff --git a/Package.swift b/Package.swift index 1924bc8..89e2189 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,7 @@ let package = Package( .library(name: "Leaf", targets: ["Leaf"]), ], dependencies: [ - .package(url: "https://github.com/vapor/leaf-kit.git", from: "1.0.0-rc.1"), + .package(url: "https://github.com/vapor/leaf-kit.git", from: "1.0.0-rc.1.2"), .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0-rc.1"), ], targets: [ diff --git a/Sources/Leaf/LeafProvider.swift b/Sources/Leaf/Application+Leaf.swift similarity index 54% rename from Sources/Leaf/LeafProvider.swift rename to Sources/Leaf/Application+Leaf.swift index 8f8006f..c2f4e05 100644 --- a/Sources/Leaf/LeafProvider.swift +++ b/Sources/Leaf/Application+Leaf.swift @@ -1,32 +1,62 @@ import Vapor +extension Application.Views.Provider { + public static var leaf: Self { + .init { + $0.views.use { + $0.leaf.renderer + } + } + } +} + extension Application { public var leaf: Leaf { .init(application: self) } public struct Leaf { - final class Storage { - var cache: LeafCache + public let application: Application - init() { - self.cache = DefaultLeafCache() + public var renderer: LeafRenderer { + .init( + configuration: self.configuration, + cache: self.cache, + files: self.files, + eventLoop: self.application.eventLoopGroup.next(), + userInfo: [ + "application": self + ] + ) + } + + public var configuration: LeafConfiguration { + get { + self.storage.configuration ?? LeafConfiguration( + rootDirectory: self.application.directory.viewsDirectory + ) + } + nonmutating set { + self.storage.configuration = newValue } } - struct Key: StorageKey { - typealias Value = Storage + public var tags: [String: LeafTag] { + get { + self.storage.tags + } + nonmutating set { + self.storage.tags = newValue + } } - public var renderer: LeafRenderer { - .init( - configuration: .init( - rootDirectory: self.application.directory.viewsDirectory - ), - cache: self.cache, - fileio: self.application.fileio, - eventLoop: self.application.eventLoopGroup.next() - ) + public var files: LeafFiles { + get { + self.storage.files ?? NIOLeafFiles(fileio: self.application.fileio) + } + nonmutating set { + self.storage.files = newValue + } } public var cache: LeafCache { @@ -48,53 +78,27 @@ extension Application { } } - public let application: Application - } -} - + struct Key: StorageKey { + typealias Value = Storage + } -extension Request { - var leaf: LeafRenderer { - .init( - configuration: .init(rootDirectory: self.application.directory.viewsDirectory), - cache: self.application.leaf.cache, - fileio: self.application.fileio, - eventLoop: self.eventLoop - ) - } -} + final class Storage { + var cache: LeafCache + var configuration: LeafConfiguration? + var files: LeafFiles? + var tags: [String: LeafTag] -extension LeafRenderer: ViewRenderer { - public func `for`(_ request: Request) -> ViewRenderer { - LeafRenderer( - configuration: self.configuration, - cache: self.cache, - fileio: self.fileio, - eventLoop: request.eventLoop - ) - } - - public func render(_ name: String, _ context: E) -> EventLoopFuture - where E: Encodable - { - let data: [String: LeafData] - do { - data = try LeafEncoder().encode(context) - } catch { - return self.eventLoop.makeFailedFuture(error) - } - return self.render(path: name, context: data).map { buffer in - return View(data: buffer) + init() { + self.cache = DefaultLeafCache() + self.tags = LeafKit.defaultTags + } } } } -extension Application.Views.Provider { - public static var leaf: Self { - .init { - $0.views.use { - $0.leaf.renderer - } - } + +extension LeafContext { + public var application: Application? { + self.userInfo["application"] as? Application } } diff --git a/Sources/Leaf/LeafRenderer+ViewRenderer.swift b/Sources/Leaf/LeafRenderer+ViewRenderer.swift new file mode 100644 index 0000000..651bea5 --- /dev/null +++ b/Sources/Leaf/LeafRenderer+ViewRenderer.swift @@ -0,0 +1,21 @@ +import Vapor + +extension LeafRenderer: ViewRenderer { + public func `for`(_ request: Request) -> ViewRenderer { + request.leaf + } + + public func render(_ name: String, _ context: E) -> EventLoopFuture + where E: Encodable + { + let data: [String: LeafData] + do { + data = try LeafEncoder().encode(context) + } catch { + return self.eventLoop.makeFailedFuture(error) + } + return self.render(path: name, context: data).map { buffer in + return View(data: buffer) + } + } +} diff --git a/Sources/Leaf/Request+Leaf.swift b/Sources/Leaf/Request+Leaf.swift new file mode 100644 index 0000000..48940ef --- /dev/null +++ b/Sources/Leaf/Request+Leaf.swift @@ -0,0 +1,23 @@ +import Vapor + +extension Request { + var leaf: LeafRenderer { + .init( + configuration: self.application.leaf.configuration, + tags: self.application.leaf.tags, + cache: self.application.leaf.cache, + files: self.application.leaf.files, + eventLoop: self.eventLoop, + userInfo: [ + "request": self, + "application": self.application + ] + ) + } +} + +extension LeafContext { + public var request: Request? { + self.userInfo["request"] as? Request + } +} diff --git a/Tests/LeafTests/LeafTests.swift b/Tests/LeafTests/LeafTests.swift index 764b44a..b34245e 100644 --- a/Tests/LeafTests/LeafTests.swift +++ b/Tests/LeafTests/LeafTests.swift @@ -20,4 +20,56 @@ class LeafTests: XCTestCase { XCTAssertContains(res.body.string, "test: bar") } } + + func testContextRequest() throws { + var test = TestFiles() + test.files["/foo.leaf"] = """ + Hello #(name) @ #path() + """ + + struct RequestPathTag: LeafTag { + func render(_ ctx: LeafContext) throws -> LeafData { + .string(ctx.request?.url.path ?? "") + } + } + + let app = Application(.testing) + defer { app.shutdown() } + + app.views.use(.leaf) + app.leaf.configuration.rootDirectory = "/" + app.leaf.cache.isEnabled = false + app.leaf.tags["path"] = RequestPathTag() + app.leaf.files = test + + app.get("test-file") { req in + req.view.render("foo", [ + "name": "vapor" + ]) + } + + try app.test(.GET, "test-file") { res in + XCTAssertEqual(res.status, .ok) + XCTAssertEqual(res.headers.contentType, .html) + XCTAssertEqual(res.body.string, "Hello vapor @ /test-file") + } + } +} + +struct TestFiles: LeafFiles { + var files: [String: String] + + init() { + files = [:] + } + + func file(path: String, on eventLoop: EventLoop) -> EventLoopFuture { + if let file = self.files[path] { + var buffer = ByteBufferAllocator().buffer(capacity: 0) + buffer.writeString(file) + return eventLoop.makeSucceededFuture(buffer) + } else { + return eventLoop.makeFailedFuture("no test file: \(path)") + } + } }