refactor: Introducing Environments
This commit is contained in:
@@ -1,17 +1,19 @@
|
||||
/// A container for template variables.
|
||||
public class Context {
|
||||
var dictionaries: [[String: Any?]]
|
||||
|
||||
public let environment: Environment
|
||||
let namespace: Namespace
|
||||
|
||||
/// Initialise a Context with an optional dictionary and optional namespace
|
||||
public init(dictionary: [String: Any]? = nil, namespace: Namespace = Namespace()) {
|
||||
init(dictionary: [String: Any]? = nil, namespace: Namespace? = nil, environment: Environment? = nil) {
|
||||
if let dictionary = dictionary {
|
||||
dictionaries = [dictionary]
|
||||
} else {
|
||||
dictionaries = []
|
||||
}
|
||||
|
||||
self.namespace = namespace
|
||||
self.namespace = namespace ?? environment?.namespace ?? Namespace()
|
||||
self.environment = environment ?? Environment()
|
||||
}
|
||||
|
||||
public subscript(key: String) -> Any? {
|
||||
|
||||
36
Sources/Environment.swift
Normal file
36
Sources/Environment.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
public struct Environment {
|
||||
var namespace: Namespace
|
||||
|
||||
public var loader: Loader?
|
||||
|
||||
public init(loader: Loader? = nil, namespace: Namespace? = nil) {
|
||||
self.loader = loader
|
||||
self.namespace = namespace ?? Namespace()
|
||||
}
|
||||
|
||||
public func loadTemplate(name: String) throws -> Template {
|
||||
if let loader = loader {
|
||||
return try loader.loadTemplate(name: name, environment: self)
|
||||
} else {
|
||||
throw TemplateDoesNotExist(templateNames: [name], loader: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func loadTemplate(names: [String]) throws -> Template {
|
||||
if let loader = loader {
|
||||
return try loader.loadTemplate(names: names, environment: self)
|
||||
} else {
|
||||
throw TemplateDoesNotExist(templateNames: names, loader: nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func renderTemplate(name: String, context: [String: Any]? = nil) throws -> String {
|
||||
let template = try loadTemplate(name: name)
|
||||
return try template.render(context)
|
||||
}
|
||||
|
||||
public func renderTemplate(string: String, context: [String: Any]? = nil) throws -> String {
|
||||
let template = Template(templateString: string, environment: self)
|
||||
return try template.render(context)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,19 @@
|
||||
public class TemplateDoesNotExist: Error, CustomStringConvertible {
|
||||
let templateNames: [String]
|
||||
let loader: Loader
|
||||
let loader: Loader?
|
||||
|
||||
public init(templateNames: [String], loader: Loader) {
|
||||
public init(templateNames: [String], loader: Loader? = nil) {
|
||||
self.templateNames = templateNames
|
||||
self.loader = loader
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
let templates = templateNames.joined(separator: ", ")
|
||||
return "Template named `\(templates)` does not exist in loader \(loader)"
|
||||
|
||||
if let loader = loader {
|
||||
return "Template named `\(templates)` does not exist in loader \(loader)"
|
||||
}
|
||||
|
||||
return "Template named `\(templates)` does not exist. No loaders found"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,15 @@ class IncludeNode : NodeType {
|
||||
}
|
||||
|
||||
func render(_ context: Context) throws -> String {
|
||||
guard let loader = context["loader"] as? Loader else {
|
||||
throw TemplateSyntaxError("Template loader not in context")
|
||||
}
|
||||
|
||||
guard let templateName = try self.templateName.resolve(context) as? String else {
|
||||
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
||||
}
|
||||
|
||||
let template = try loader.loadTemplate(name: templateName)
|
||||
return try template.render(context)
|
||||
let template = try context.environment.loadTemplate(name: templateName)
|
||||
|
||||
return try context.push {
|
||||
return try template.render(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,15 +59,11 @@ class ExtendsNode : NodeType {
|
||||
}
|
||||
|
||||
func render(_ context: Context) throws -> String {
|
||||
guard let loader = context["loader"] as? Loader else {
|
||||
throw TemplateSyntaxError("Template loader not in context")
|
||||
}
|
||||
|
||||
guard let templateName = try self.templateName.resolve(context) as? String else {
|
||||
throw TemplateSyntaxError("'\(self.templateName)' could not be resolved as a string")
|
||||
}
|
||||
|
||||
let template = try loader.loadTemplate(name: templateName)
|
||||
let template = try context.environment.loadTemplate(name: templateName)
|
||||
|
||||
let blockContext: BlockContext
|
||||
if let context = context[BlockContext.contextKey] as? BlockContext {
|
||||
|
||||
@@ -3,16 +3,16 @@ import PathKit
|
||||
|
||||
|
||||
public protocol Loader {
|
||||
func loadTemplate(name: String) throws -> Template
|
||||
func loadTemplate(names: [String]) throws -> Template
|
||||
func loadTemplate(name: String, environment: Environment) throws -> Template
|
||||
func loadTemplate(names: [String], environment: Environment) throws -> Template
|
||||
}
|
||||
|
||||
|
||||
extension Loader {
|
||||
func loadTemplate(names: [String]) throws -> Template {
|
||||
public func loadTemplate(names: [String], environment: Environment) throws -> Template {
|
||||
for name in names {
|
||||
do {
|
||||
return try loadTemplate(name: name)
|
||||
return try loadTemplate(name: name, environment: environment)
|
||||
} catch is TemplateDoesNotExist {
|
||||
continue
|
||||
} catch {
|
||||
@@ -43,7 +43,7 @@ public class FileSystemLoader: Loader, CustomStringConvertible {
|
||||
return "FileSystemLoader(\(paths))"
|
||||
}
|
||||
|
||||
public func loadTemplate(name: String) throws -> Template {
|
||||
public func loadTemplate(name: String, environment: Environment) throws -> Template {
|
||||
for path in paths {
|
||||
let templatePath = try path.safeJoin(path: Path(name))
|
||||
|
||||
@@ -51,19 +51,19 @@ public class FileSystemLoader: Loader, CustomStringConvertible {
|
||||
continue
|
||||
}
|
||||
|
||||
return try Template(path: templatePath)
|
||||
return try Template(path: templatePath, environment: environment, name: name)
|
||||
}
|
||||
|
||||
throw TemplateDoesNotExist(templateNames: [name], loader: self)
|
||||
}
|
||||
|
||||
public func loadTemplate(names: [String]) throws -> Template {
|
||||
public func loadTemplate(names: [String], environment: Environment) throws -> Template {
|
||||
for path in paths {
|
||||
for templateName in names {
|
||||
let templatePath = try path.safeJoin(path: Path(templateName))
|
||||
|
||||
if templatePath.exists {
|
||||
return try Template(path: templatePath)
|
||||
return try Template(path: templatePath, environment: environment, name: templateName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,17 @@ let NSFileNoSuchFileError = 4
|
||||
|
||||
/// A class representing a template
|
||||
public class Template: ExpressibleByStringLiteral {
|
||||
let environment: Environment
|
||||
let tokens: [Token]
|
||||
|
||||
/// The name of the loaded Template if the Template was loaded from a Loader
|
||||
public let name: String?
|
||||
|
||||
/// Create a template with a template string
|
||||
public init(templateString: String) {
|
||||
public init(templateString: String, environment: Environment? = nil, name: String? = nil) {
|
||||
self.environment = environment ?? Environment()
|
||||
self.name = name
|
||||
|
||||
let lexer = Lexer(templateString: templateString)
|
||||
tokens = lexer.tokenize()
|
||||
}
|
||||
@@ -31,11 +38,13 @@ public class Template: ExpressibleByStringLiteral {
|
||||
}
|
||||
|
||||
/// Create a template with a file found at the given path
|
||||
public convenience init(path: Path) throws {
|
||||
self.init(templateString: try path.read())
|
||||
public convenience init(path: Path, environment: Environment? = nil, name: String? = nil) throws {
|
||||
self.init(templateString: try path.read(), environment: environment, name: name)
|
||||
}
|
||||
|
||||
// Create a template with a template string literal
|
||||
// MARK: ExpressibleByStringLiteral
|
||||
|
||||
// Create a templaVte with a template string literal
|
||||
public convenience required init(stringLiteral value: String) {
|
||||
self.init(templateString: value)
|
||||
}
|
||||
@@ -50,11 +59,16 @@ public class Template: ExpressibleByStringLiteral {
|
||||
self.init(stringLiteral: value)
|
||||
}
|
||||
|
||||
/// Render the given template
|
||||
public func render(_ context: Context? = nil) throws -> String {
|
||||
let context = context ?? Context()
|
||||
/// Render the given template with a context
|
||||
func render(_ context: Context) throws -> String {
|
||||
let context = context ?? Context(environment: environment)
|
||||
let parser = TokenParser(tokens: tokens, namespace: context.namespace)
|
||||
let nodes = try parser.parse()
|
||||
return try renderNodes(nodes, context)
|
||||
}
|
||||
|
||||
/// Render the given template
|
||||
public func render(_ dictionary: [String: Any]? = nil) throws -> String {
|
||||
return try render(Context(dictionary: dictionary, environment: environment))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user