refactor: TemplateLoader to protocol, follow Swift API guidelines
This commit is contained in:
@@ -4,6 +4,12 @@
|
|||||||
|
|
||||||
### Breaking
|
### Breaking
|
||||||
|
|
||||||
|
- `TemplateLoader` is now a protocol with the file system based loader now
|
||||||
|
called `FileSystemLoader`. You will need to use `FileSystemLoader` instead.
|
||||||
|
|
||||||
|
- `TemplateLoader` `loadTemplate` methods are now throwing and now take labels
|
||||||
|
for the `name` and `names` arguments.
|
||||||
|
|
||||||
- Many internal classes are no longer private. Some APIs were previously
|
- Many internal classes are no longer private. Some APIs were previously
|
||||||
accessible due to earlier versions of Swift requiring the types to be public
|
accessible due to earlier versions of Swift requiring the types to be public
|
||||||
to be able to test. Now we have access to `@testable` these can correctly be
|
to be able to test. Now we have access to `@testable` these can correctly be
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ class IncludeNode : NodeType {
|
|||||||
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let template = loader.loadTemplate(templateName) else {
|
guard let template = try loader.loadTemplate(name: templateName) else {
|
||||||
let paths = loader.paths.map { $0.description }.joined(separator: ", ")
|
throw TemplateSyntaxError("'\(templateName)' template not found")
|
||||||
throw TemplateSyntaxError("'\(templateName)' template not found in \(paths)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return try template.render(context)
|
return try template.render(context)
|
||||||
|
|||||||
@@ -67,9 +67,8 @@ class ExtendsNode : NodeType {
|
|||||||
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let template = loader.loadTemplate(templateName) else {
|
guard let template = try loader.loadTemplate(name: templateName) else {
|
||||||
let paths: String = loader.paths.map { $0.description }.joined(separator: ", ")
|
throw TemplateSyntaxError("'\(templateName)' template not found")
|
||||||
throw TemplateSyntaxError("'\(templateName)' template not found in \(paths)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let blockContext: BlockContext
|
let blockContext: BlockContext
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ let NSFileNoSuchFileError = 4
|
|||||||
public class Template: ExpressibleByStringLiteral {
|
public class Template: ExpressibleByStringLiteral {
|
||||||
let tokens: [Token]
|
let tokens: [Token]
|
||||||
|
|
||||||
|
/// Create a template with a template string
|
||||||
|
public init(templateString: String) {
|
||||||
|
let lexer = Lexer(templateString: templateString)
|
||||||
|
tokens = lexer.tokenize()
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a template with the given name inside the given bundle
|
/// Create a template with the given name inside the given bundle
|
||||||
public convenience init(named:String, inBundle bundle:Bundle? = nil) throws {
|
public convenience init(named:String, inBundle bundle:Bundle? = nil) throws {
|
||||||
let useBundle = bundle ?? Bundle.main
|
let useBundle = bundle ?? Bundle.main
|
||||||
@@ -25,28 +31,22 @@ public class Template: ExpressibleByStringLiteral {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a template with a file found at the given path
|
/// Create a template with a file found at the given path
|
||||||
public convenience init(path:Path) throws {
|
public convenience init(path: Path) throws {
|
||||||
self.init(templateString: try path.read())
|
self.init(templateString: try path.read())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a template with a template string
|
|
||||||
public init(templateString:String) {
|
|
||||||
let lexer = Lexer(templateString: templateString)
|
|
||||||
tokens = lexer.tokenize()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a template with a template string literal
|
// Create a template with a template string literal
|
||||||
public convenience required init(stringLiteral value:String) {
|
public convenience required init(stringLiteral value: String) {
|
||||||
self.init(templateString: value)
|
self.init(templateString: value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a template with a template string literal
|
// Create a template with a template string literal
|
||||||
public convenience required init(extendedGraphemeClusterLiteral value:StringLiteralType) {
|
public convenience required init(extendedGraphemeClusterLiteral value: StringLiteralType) {
|
||||||
self.init(stringLiteral: value)
|
self.init(stringLiteral: value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a template with a template string literal
|
// Create a template with a template string literal
|
||||||
public convenience required init(unicodeScalarLiteral value:StringLiteralType) {
|
public convenience required init(unicodeScalarLiteral value: StringLiteralType) {
|
||||||
self.init(stringLiteral: value)
|
self.init(stringLiteral: value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,29 @@ import Foundation
|
|||||||
import PathKit
|
import PathKit
|
||||||
|
|
||||||
|
|
||||||
|
public protocol TemplateLoader {
|
||||||
|
func loadTemplate(name: String) throws -> Template?
|
||||||
|
func loadTemplate(names: [String]) throws -> Template?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension TemplateLoader {
|
||||||
|
func loadTemplate(names: [String]) throws -> Template? {
|
||||||
|
for name in names {
|
||||||
|
let template = try loadTemplate(name: name)
|
||||||
|
|
||||||
|
if template != nil {
|
||||||
|
return template
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// A class for loading a template from disk
|
// A class for loading a template from disk
|
||||||
public class TemplateLoader {
|
public class FileSystemLoader: TemplateLoader {
|
||||||
public let paths: [Path]
|
public let paths: [Path]
|
||||||
|
|
||||||
public init(paths: [Path]) {
|
public init(paths: [Path]) {
|
||||||
@@ -16,19 +37,25 @@ public class TemplateLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadTemplate(_ templateName: String) -> Template? {
|
public func loadTemplate(name: String) throws -> Template? {
|
||||||
return loadTemplate([templateName])
|
for path in paths {
|
||||||
|
let templatePath = path + Path(name)
|
||||||
|
|
||||||
|
if templatePath.exists {
|
||||||
|
return try Template(path: templatePath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadTemplate(_ templateNames: [String]) -> Template? {
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public func loadTemplate(names: [String]) throws -> Template? {
|
||||||
for path in paths {
|
for path in paths {
|
||||||
for templateName in templateNames {
|
for templateName in names {
|
||||||
let templatePath = path + Path(templateName)
|
let templatePath = path + Path(templateName)
|
||||||
|
|
||||||
if templatePath.exists {
|
if templatePath.exists {
|
||||||
if let template = try? Template(path: templatePath) {
|
return try Template(path: templatePath)
|
||||||
return template
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import PathKit
|
|||||||
func testInclude() {
|
func testInclude() {
|
||||||
describe("Include") {
|
describe("Include") {
|
||||||
let path = Path(#file) + ".." + "fixtures"
|
let path = Path(#file) + ".." + "fixtures"
|
||||||
let loader = TemplateLoader(paths: [path])
|
let loader = FileSystemLoader(paths: [path])
|
||||||
|
|
||||||
$0.describe("parsing") {
|
$0.describe("parsing") {
|
||||||
$0.it("throws an error when no template is given") {
|
$0.it("throws an error when no template is given") {
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ import PathKit
|
|||||||
func testInheritence() {
|
func testInheritence() {
|
||||||
describe("Inheritence") {
|
describe("Inheritence") {
|
||||||
let path = Path(#file) + ".." + "fixtures"
|
let path = Path(#file) + ".." + "fixtures"
|
||||||
let loader = TemplateLoader(paths: [path])
|
let loader = FileSystemLoader(paths: [path])
|
||||||
|
|
||||||
$0.it("can inherit from another template") {
|
$0.it("can inherit from another template") {
|
||||||
let context = Context(dictionary: ["loader": loader])
|
let context = Context(dictionary: ["loader": loader])
|
||||||
let template = loader.loadTemplate("child.html")
|
let template = try loader.loadTemplate(name: "child.html")
|
||||||
try expect(try template?.render(context)) == "Header\nChild"
|
try expect(try template?.render(context)) == "Header\nChild"
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can inherit from another template inheriting from another template") {
|
$0.it("can inherit from another template inheriting from another template") {
|
||||||
let context = Context(dictionary: ["loader": loader])
|
let context = Context(dictionary: ["loader": loader])
|
||||||
let template = loader.loadTemplate("child-child.html")
|
let template = try loader.loadTemplate(name: "child-child.html")
|
||||||
try expect(try template?.render(context)) == "Child Child Header\nChild"
|
try expect(try template?.render(context)) == "Child Child Header\nChild"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,18 @@ import PathKit
|
|||||||
func testTemplateLoader() {
|
func testTemplateLoader() {
|
||||||
describe("TemplateLoader") {
|
describe("TemplateLoader") {
|
||||||
let path = Path(#file) + ".." + "fixtures"
|
let path = Path(#file) + ".." + "fixtures"
|
||||||
let loader = TemplateLoader(paths: [path])
|
let loader = FileSystemLoader(paths: [path])
|
||||||
|
|
||||||
$0.it("returns nil when a template cannot be found") {
|
$0.it("returns nil when a template cannot be found") {
|
||||||
try expect(loader.loadTemplate("unknown.html")).to.beNil()
|
try expect(try loader.loadTemplate(name: "unknown.html")).to.beNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("returns nil when an array of templates cannot be found") {
|
$0.it("returns nil when an array of templates cannot be found") {
|
||||||
try expect(loader.loadTemplate(["unknown.html", "unknown2.html"])).to.beNil()
|
try expect(try loader.loadTemplate(names: ["unknown.html", "unknown2.html"])).to.beNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("can load a template from a file") {
|
$0.it("can load a template from a file") {
|
||||||
if loader.loadTemplate("test.html") == nil {
|
if try loader.loadTemplate(name: "test.html") == nil {
|
||||||
throw failure("didn't find the template")
|
throw failure("didn't find the template")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,12 +117,12 @@ You can include another template using the `include` tag.
|
|||||||
|
|
||||||
{% include "comment.html" %}
|
{% include "comment.html" %}
|
||||||
|
|
||||||
The `include` tag requires a TemplateLoader to be found inside your context with the paths, or bundles used to lookup the template.
|
The `include` tag requires a FileSystemLoader to be found inside your context with the paths, or bundles used to lookup the template.
|
||||||
|
|
||||||
.. code-block:: swift
|
.. code-block:: swift
|
||||||
|
|
||||||
let context = Context(dictionary: [
|
let context = Context(dictionary: [
|
||||||
"loader": TemplateLoader(bundle:[NSBundle.mainBundle()])
|
"loader": FileSystemLoader(bundle: [NSBundle.mainBundle()])
|
||||||
])
|
])
|
||||||
|
|
||||||
``extends``
|
``extends``
|
||||||
|
|||||||
Reference in New Issue
Block a user