diff --git a/CHANGELOG.md b/CHANGELOG.md index 29e5716..2994156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ ### 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 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 diff --git a/Sources/Include.swift b/Sources/Include.swift index b5601d4..7de0df8 100644 --- a/Sources/Include.swift +++ b/Sources/Include.swift @@ -27,9 +27,8 @@ class IncludeNode : NodeType { throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string") } - guard let template = loader.loadTemplate(templateName) else { - let paths = loader.paths.map { $0.description }.joined(separator: ", ") - throw TemplateSyntaxError("'\(templateName)' template not found in \(paths)") + guard let template = try loader.loadTemplate(name: templateName) else { + throw TemplateSyntaxError("'\(templateName)' template not found") } return try template.render(context) diff --git a/Sources/Inheritence.swift b/Sources/Inheritence.swift index d2c1299..75f728b 100644 --- a/Sources/Inheritence.swift +++ b/Sources/Inheritence.swift @@ -67,9 +67,8 @@ class ExtendsNode : NodeType { throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string") } - guard let template = loader.loadTemplate(templateName) else { - let paths: String = loader.paths.map { $0.description }.joined(separator: ", ") - throw TemplateSyntaxError("'\(templateName)' template not found in \(paths)") + guard let template = try loader.loadTemplate(name: templateName) else { + throw TemplateSyntaxError("'\(templateName)' template not found") } let blockContext: BlockContext diff --git a/Sources/Template.swift b/Sources/Template.swift index 7867b49..305b32b 100644 --- a/Sources/Template.swift +++ b/Sources/Template.swift @@ -9,6 +9,12 @@ let NSFileNoSuchFileError = 4 public class Template: ExpressibleByStringLiteral { 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 public convenience init(named:String, inBundle bundle:Bundle? = nil) throws { let useBundle = bundle ?? Bundle.main @@ -25,28 +31,22 @@ public class Template: ExpressibleByStringLiteral { } /// 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()) } - /// 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 - public convenience required init(stringLiteral value:String) { + public convenience required init(stringLiteral value: String) { self.init(templateString: value) } // 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) } // 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) } diff --git a/Sources/TemplateLoader.swift b/Sources/TemplateLoader.swift index db8d298..8decb00 100644 --- a/Sources/TemplateLoader.swift +++ b/Sources/TemplateLoader.swift @@ -2,8 +2,29 @@ import Foundation 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 -public class TemplateLoader { +public class FileSystemLoader: TemplateLoader { public let paths: [Path] public init(paths: [Path]) { @@ -16,19 +37,25 @@ public class TemplateLoader { } } - public func loadTemplate(_ templateName: String) -> Template? { - return loadTemplate([templateName]) + public func loadTemplate(name: String) throws -> Template? { + for path in paths { + let templatePath = path + Path(name) + + if templatePath.exists { + return try Template(path: templatePath) + } + } + + return nil } - public func loadTemplate(_ templateNames: [String]) -> Template? { + public func loadTemplate(names: [String]) throws -> Template? { for path in paths { - for templateName in templateNames { + for templateName in names { let templatePath = path + Path(templateName) if templatePath.exists { - if let template = try? Template(path: templatePath) { - return template - } + return try Template(path: templatePath) } } } diff --git a/Tests/StencilTests/IncludeSpec.swift b/Tests/StencilTests/IncludeSpec.swift index fc65913..7e2cbf5 100644 --- a/Tests/StencilTests/IncludeSpec.swift +++ b/Tests/StencilTests/IncludeSpec.swift @@ -6,7 +6,7 @@ import PathKit func testInclude() { describe("Include") { let path = Path(#file) + ".." + "fixtures" - let loader = TemplateLoader(paths: [path]) + let loader = FileSystemLoader(paths: [path]) $0.describe("parsing") { $0.it("throws an error when no template is given") { diff --git a/Tests/StencilTests/InheritenceSpec.swift b/Tests/StencilTests/InheritenceSpec.swift index 663161d..5267bf8 100644 --- a/Tests/StencilTests/InheritenceSpec.swift +++ b/Tests/StencilTests/InheritenceSpec.swift @@ -6,17 +6,17 @@ import PathKit func testInheritence() { describe("Inheritence") { let path = Path(#file) + ".." + "fixtures" - let loader = TemplateLoader(paths: [path]) + let loader = FileSystemLoader(paths: [path]) $0.it("can inherit from another template") { 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" } $0.it("can inherit from another template inheriting from another template") { 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" } } diff --git a/Tests/StencilTests/TemplateLoaderSpec.swift b/Tests/StencilTests/TemplateLoaderSpec.swift index ae4eeb6..db099b5 100644 --- a/Tests/StencilTests/TemplateLoaderSpec.swift +++ b/Tests/StencilTests/TemplateLoaderSpec.swift @@ -6,18 +6,18 @@ import PathKit func testTemplateLoader() { describe("TemplateLoader") { 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") { - 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") { - 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") { - if loader.loadTemplate("test.html") == nil { + if try loader.loadTemplate(name: "test.html") == nil { throw failure("didn't find the template") } } diff --git a/docs/builtins.rst b/docs/builtins.rst index f2afb3b..f354bc9 100644 --- a/docs/builtins.rst +++ b/docs/builtins.rst @@ -117,12 +117,12 @@ You can include another template using the `include` tag. {% 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 let context = Context(dictionary: [ - "loader": TemplateLoader(bundle:[NSBundle.mainBundle()]) + "loader": FileSystemLoader(bundle: [NSBundle.mainBundle()]) ]) ``extends``