Add 'Namespace' a container for tags and filters

This commit is contained in:
Kyle Fuller
2015-11-18 16:08:18 +03:00
parent 226becb258
commit dc774fe43b
11 changed files with 115 additions and 86 deletions

44
Stencil/Namespace.swift Normal file
View File

@@ -0,0 +1,44 @@
public class Namespace {
public typealias TagParser = (TokenParser, Token) throws -> NodeType
var tags = [String: TagParser]()
var filters = [String: Filter]()
public init() {
registerDefaultTags()
registerDefaultFilters()
}
private func registerDefaultTags() {
registerTag("for", parser: ForNode.parse)
registerTag("if", parser: IfNode.parse)
registerTag("ifnot", parser: IfNode.parse_ifnot)
registerTag("now", parser: NowNode.parse)
registerTag("include", parser: IncludeNode.parse)
registerTag("extends", parser: ExtendsNode.parse)
registerTag("block", parser: BlockNode.parse)
}
private func registerDefaultFilters() {
registerFilter("capitalize", filter: capitalise)
registerFilter("uppercase", filter: uppercase)
registerFilter("lowercase", filter: lowercase)
}
/// Registers a new template tag
public func registerTag(name: String, parser: TagParser) {
tags[name] = parser
}
/// Registers a simple template tag with a name and a handler
public func registerSimpleTag(name: String, handler: Context throws -> String) {
registerTag(name, parser: { parser, token in
return SimpleNode(handler: handler)
})
}
/// Registers a template filter with the given name
public func registerFilter(name: String, filter: Filter) {
filters[name] = filter
}
}

View File

@@ -16,38 +16,12 @@ public typealias Filter = Any? throws -> Any?
public class TokenParser {
public typealias TagParser = (TokenParser, Token) throws -> NodeType
private var tokens:[Token]
private var tags = [String:TagParser]()
private var filters = [String: Filter]()
private var tokens: [Token]
private let namespace: Namespace
public init(tokens:[Token]) {
public init(tokens: [Token], namespace: Namespace) {
self.tokens = tokens
registerTag("for", parser: ForNode.parse)
registerTag("if", parser: IfNode.parse)
registerTag("ifnot", parser: IfNode.parse_ifnot)
registerTag("now", parser: NowNode.parse)
registerTag("include", parser: IncludeNode.parse)
registerTag("extends", parser: ExtendsNode.parse)
registerTag("block", parser: BlockNode.parse)
registerFilter("capitalize", filter: capitalise)
registerFilter("uppercase", filter: uppercase)
registerFilter("lowercase", filter: lowercase)
}
/// Registers a new template tag
public func registerTag(name:String, parser:TagParser) {
tags[name] = parser
}
/// Registers a simple template tag with a name and a handler
public func registerSimpleTag(name:String, handler:(Context throws -> String)) {
registerTag(name, parser: { parser, token in
return SimpleNode(handler: handler)
})
}
public func registerFilter(name: String, filter: Filter) {
filters[name] = filter
self.namespace = namespace
}
/// Parse the given tokens into nodes
@@ -75,7 +49,7 @@ public class TokenParser {
}
if let tag = tag {
if let parser = self.tags[tag] {
if let parser = namespace.tags[tag] {
nodes.append(try parser(self, token))
} else {
throw TemplateSyntaxError("Unknown template tag '\(tag)'")
@@ -102,7 +76,7 @@ public class TokenParser {
}
public func findFilter(name: String) throws -> Filter {
if let filter = filters[name] {
if let filter = namespace.filters[name] {
return filter
}

View File

@@ -3,8 +3,7 @@ import PathKit
/// A class representing a template
public class Template {
public let parser:TokenParser
private var nodes:[NodeType]? = nil
let tokens: [Token]
/// Create a template with the given name inside the given bundle
public convenience init(named:String, inBundle bundle:NSBundle? = nil) throws {
@@ -29,16 +28,13 @@ public class Template {
/// Create a template with a template string
public init(templateString:String) {
let lexer = Lexer(templateString: templateString)
let tokens = lexer.tokenize()
parser = TokenParser(tokens: tokens)
tokens = lexer.tokenize()
}
/// Render the given template
public func render(context:Context? = nil) throws -> String {
if nodes == nil {
nodes = try parser.parse()
}
return try renderNodes(nodes!, context ?? Context())
public func render(context: Context? = nil, namespace: Namespace? = nil) throws -> String {
let parser = TokenParser(tokens: tokens, namespace: namespace ?? Namespace())
let nodes = try parser.parse()
return try renderNodes(nodes, context ?? Context())
}
}