chore: Lock down APIs

This commit is contained in:
Kyle Fuller
2016-11-27 02:20:46 +00:00
parent 60b378d482
commit a13401b046
17 changed files with 67 additions and 60 deletions

View File

@@ -2,6 +2,13 @@
## Master ## Master
### Breaking
- 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
private.
### Enhancements ### Enhancements
- You may now register custom template filters which make use of arguments. - You may now register custom template filters which make use of arguments.

View File

@@ -14,7 +14,7 @@ public class Context {
self.namespace = namespace self.namespace = namespace
} }
open subscript(key: String) -> Any? { public subscript(key: String) -> Any? {
/// Retrieves a variable's value, starting at the current context and going upwards /// Retrieves a variable's value, starting at the current context and going upwards
get { get {
for dictionary in Array(dictionaries.reversed()) { for dictionary in Array(dictionaries.reversed()) {
@@ -47,7 +47,7 @@ public class Context {
} }
/// Push a new level onto the context for the duration of the execution of the given closure /// Push a new level onto the context for the duration of the execution of the given closure
open func push<Result>(dictionary: [String: Any]? = nil, closure: (() throws -> Result)) rethrows -> Result { public func push<Result>(dictionary: [String: Any]? = nil, closure: (() throws -> Result)) rethrows -> Result {
push(dictionary) push(dictionary)
defer { _ = pop() } defer { _ = pop() }
return try closure() return try closure()

View File

@@ -1,10 +1,10 @@
open class ForNode : NodeType { class ForNode : NodeType {
let variable:Variable let variable:Variable
let loopVariable:String let loopVariable:String
let nodes:[NodeType] let nodes:[NodeType]
let emptyNodes: [NodeType] let emptyNodes: [NodeType]
open class func parse(_ parser:TokenParser, token:Token) throws -> NodeType { class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
let components = token.components() let components = token.components()
guard components.count == 4 && components[2] == "in" else { guard components.count == 4 && components[2] == "in" else {
@@ -30,14 +30,14 @@ open class ForNode : NodeType {
return ForNode(variable: variable, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes) return ForNode(variable: variable, loopVariable: loopVariable, nodes: forNodes, emptyNodes:emptyNodes)
} }
public init(variable:String, loopVariable:String, nodes:[NodeType], emptyNodes:[NodeType]) { init(variable:String, loopVariable:String, nodes:[NodeType], emptyNodes:[NodeType]) {
self.variable = Variable(variable) self.variable = Variable(variable)
self.loopVariable = loopVariable self.loopVariable = loopVariable
self.nodes = nodes self.nodes = nodes
self.emptyNodes = emptyNodes self.emptyNodes = emptyNodes
} }
open func render(_ context: Context) throws -> String { func render(_ context: Context) throws -> String {
let values = try variable.resolve(context) let values = try variable.resolve(context)
if let values = values as? [Any] , values.count > 0 { if let values = values as? [Any] , values.count > 0 {

View File

@@ -1,9 +1,9 @@
open class IfNode : NodeType { class IfNode : NodeType {
open let variable:Variable let variable:Variable
open let trueNodes:[NodeType] let trueNodes:[NodeType]
open let falseNodes:[NodeType] let falseNodes:[NodeType]
open class func parse(_ parser:TokenParser, token:Token) throws -> NodeType { class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
let components = token.components() let components = token.components()
guard components.count == 2 else { guard components.count == 2 else {
throw TemplateSyntaxError("'if' statements should use the following 'if condition' `\(token.contents)`.") throw TemplateSyntaxError("'if' statements should use the following 'if condition' `\(token.contents)`.")
@@ -26,7 +26,7 @@ open class IfNode : NodeType {
return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes) return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes)
} }
open class func parse_ifnot(_ parser:TokenParser, token:Token) throws -> NodeType { class func parse_ifnot(_ parser:TokenParser, token:Token) throws -> NodeType {
let components = token.components() let components = token.components()
guard components.count == 2 else { guard components.count == 2 else {
throw TemplateSyntaxError("'ifnot' statements should use the following 'ifnot condition' `\(token.contents)`.") throw TemplateSyntaxError("'ifnot' statements should use the following 'ifnot condition' `\(token.contents)`.")
@@ -49,13 +49,13 @@ open class IfNode : NodeType {
return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes) return IfNode(variable: variable, trueNodes: trueNodes, falseNodes: falseNodes)
} }
public init(variable:String, trueNodes:[NodeType], falseNodes:[NodeType]) { init(variable:String, trueNodes:[NodeType], falseNodes:[NodeType]) {
self.variable = Variable(variable) self.variable = Variable(variable)
self.trueNodes = trueNodes self.trueNodes = trueNodes
self.falseNodes = falseNodes self.falseNodes = falseNodes
} }
open func render(_ context: Context) throws -> String { func render(_ context: Context) throws -> String {
let result = try variable.resolve(context) let result = try variable.resolve(context)
var truthy = false var truthy = false

View File

@@ -1,10 +1,10 @@
import PathKit import PathKit
open class IncludeNode : NodeType { class IncludeNode : NodeType {
open let templateName: Variable let templateName: Variable
open class func parse(_ parser: TokenParser, token: Token) throws -> NodeType { class func parse(_ parser: TokenParser, token: Token) throws -> NodeType {
let bits = token.components() let bits = token.components()
guard bits.count == 2 else { guard bits.count == 2 else {
@@ -14,11 +14,11 @@ open class IncludeNode : NodeType {
return IncludeNode(templateName: Variable(bits[1])) return IncludeNode(templateName: Variable(bits[1]))
} }
public init(templateName: Variable) { init(templateName: Variable) {
self.templateName = templateName self.templateName = templateName
} }
open func render(_ context: Context) throws -> String { func render(_ context: Context) throws -> String {
guard let loader = context["loader"] as? TemplateLoader else { guard let loader = context["loader"] as? TemplateLoader else {
throw TemplateSyntaxError("Template loader not in context") throw TemplateSyntaxError("Template loader not in context")
} }

View File

@@ -1,7 +1,7 @@
public struct Lexer { struct Lexer {
public let templateString: String let templateString: String
public init(templateString: String) { init(templateString: String) {
self.templateString = templateString self.templateString = templateString
} }
@@ -24,7 +24,7 @@ public struct Lexer {
} }
/// Returns an array of tokens from a given template string. /// Returns an array of tokens from a given template string.
public func tokenize() -> [Token] { func tokenize() -> [Token] {
var tokens: [Token] = [] var tokens: [Token] = []
let scanner = Scanner(templateString) let scanner = Scanner(templateString)

View File

@@ -21,7 +21,7 @@ enum Filter: FilterType {
} }
open class Namespace { public class Namespace {
public typealias TagParser = (TokenParser, Token) throws -> NodeType public typealias TagParser = (TokenParser, Token) throws -> NodeType
var tags = [String: TagParser]() var tags = [String: TagParser]()
@@ -51,24 +51,24 @@ open class Namespace {
} }
/// Registers a new template tag /// Registers a new template tag
open func registerTag(_ name: String, parser: @escaping TagParser) { public func registerTag(_ name: String, parser: @escaping TagParser) {
tags[name] = parser tags[name] = parser
} }
/// Registers a simple template tag with a name and a handler /// Registers a simple template tag with a name and a handler
open func registerSimpleTag(_ name: String, handler: @escaping (Context) throws -> String) { public func registerSimpleTag(_ name: String, handler: @escaping (Context) throws -> String) {
registerTag(name, parser: { parser, token in registerTag(name, parser: { parser, token in
return SimpleNode(handler: handler) return SimpleNode(handler: handler)
}) })
} }
/// Registers a template filter with the given name /// Registers a template filter with the given name
open func registerFilter(_ name: String, filter: @escaping (Any?) throws -> Any?) { public func registerFilter(_ name: String, filter: @escaping (Any?) throws -> Any?) {
filters[name] = .simple(filter) filters[name] = .simple(filter)
} }
/// Registers a template filter with the given name /// Registers a template filter with the given name
open func registerFilter(_ name: String, filter: @escaping (Any?, [Any?]) throws -> Any?) { public func registerFilter(_ name: String, filter: @escaping (Any?, [Any?]) throws -> Any?) {
filters[name] = .arguments(filter) filters[name] = .arguments(filter)
} }
} }

View File

@@ -26,27 +26,27 @@ public func renderNodes(_ nodes:[NodeType], _ context:Context) throws -> String
return try nodes.map { try $0.render(context) }.joined(separator: "") return try nodes.map { try $0.render(context) }.joined(separator: "")
} }
open class SimpleNode : NodeType { public class SimpleNode : NodeType {
let handler:(Context) throws -> String public let handler:(Context) throws -> String
public init(handler: @escaping (Context) throws -> String) { public init(handler: @escaping (Context) throws -> String) {
self.handler = handler self.handler = handler
} }
open func render(_ context: Context) throws -> String { public func render(_ context: Context) throws -> String {
return try handler(context) return try handler(context)
} }
} }
open class TextNode : NodeType { public class TextNode : NodeType {
open let text:String public let text:String
public init(text:String) { public init(text:String) {
self.text = text self.text = text
} }
open func render(_ context:Context) throws -> String { public func render(_ context:Context) throws -> String {
return self.text return self.text
} }
} }
@@ -57,8 +57,8 @@ public protocol Resolvable {
} }
open class VariableNode : NodeType { public class VariableNode : NodeType {
open let variable: Resolvable public let variable: Resolvable
public init(variable: Resolvable) { public init(variable: Resolvable) {
self.variable = variable self.variable = variable
@@ -68,7 +68,7 @@ open class VariableNode : NodeType {
self.variable = Variable(variable) self.variable = Variable(variable)
} }
open func render(_ context: Context) throws -> String { public func render(_ context: Context) throws -> String {
let result = try variable.resolve(context) let result = try variable.resolve(context)
if let result = result as? String { if let result = result as? String {

View File

@@ -2,10 +2,10 @@
import Foundation import Foundation
open class NowNode : NodeType { class NowNode : NodeType {
open let format:Variable let format:Variable
open class func parse(_ parser:TokenParser, token:Token) throws -> NodeType { class func parse(_ parser:TokenParser, token:Token) throws -> NodeType {
var format:Variable? var format:Variable?
let components = token.components() let components = token.components()
@@ -19,11 +19,11 @@ open class NowNode : NodeType {
return NowNode(format:format) return NowNode(format:format)
} }
public init(format:Variable?) { init(format:Variable?) {
self.format = format ?? Variable("\"yyyy-MM-dd 'at' HH:mm\"") self.format = format ?? Variable("\"yyyy-MM-dd 'at' HH:mm\"")
} }
open func render(_ context: Context) throws -> String { func render(_ context: Context) throws -> String {
let date = Date() let date = Date()
let format = try self.format.resolve(context) let format = try self.format.resolve(context)
var formatter:DateFormatter? var formatter:DateFormatter?

View File

@@ -14,7 +14,7 @@ public func until(_ tags: [String]) -> ((TokenParser, Token) -> Bool) {
/// A class for parsing an array of tokens and converts them into a collection of Node's /// A class for parsing an array of tokens and converts them into a collection of Node's
open class TokenParser { public class TokenParser {
public typealias TagParser = (TokenParser, Token) throws -> NodeType public typealias TagParser = (TokenParser, Token) throws -> NodeType
fileprivate var tokens: [Token] fileprivate var tokens: [Token]
@@ -26,11 +26,11 @@ open class TokenParser {
} }
/// Parse the given tokens into nodes /// Parse the given tokens into nodes
open func parse() throws -> [NodeType] { public func parse() throws -> [NodeType] {
return try parse(nil) return try parse(nil)
} }
open func parse(_ parse_until:((_ parser:TokenParser, _ token:Token) -> (Bool))?) throws -> [NodeType] { public func parse(_ parse_until:((_ parser:TokenParser, _ token:Token) -> (Bool))?) throws -> [NodeType] {
var nodes = [NodeType]() var nodes = [NodeType]()
while tokens.count > 0 { while tokens.count > 0 {
@@ -64,7 +64,7 @@ open class TokenParser {
return nodes return nodes
} }
open func nextToken() -> Token? { public func nextToken() -> Token? {
if tokens.count > 0 { if tokens.count > 0 {
return tokens.remove(at: 0) return tokens.remove(at: 0)
} }
@@ -72,11 +72,11 @@ open class TokenParser {
return nil return nil
} }
open func prependToken(_ token:Token) { public func prependToken(_ token:Token) {
tokens.insert(token, at: 0) tokens.insert(token, at: 0)
} }
open func findFilter(_ name: String) throws -> FilterType { public func findFilter(_ name: String) throws -> FilterType {
if let filter = namespace.filters[name] { if let filter = namespace.filters[name] {
return filter return filter
} }

View File

@@ -6,7 +6,7 @@ let NSFileNoSuchFileError = 4
#endif #endif
/// A class representing a template /// A class representing a template
open class Template: ExpressibleByStringLiteral { public class Template: ExpressibleByStringLiteral {
let tokens: [Token] let tokens: [Token]
/// Create a template with the given name inside the given bundle /// Create a template with the given name inside the given bundle
@@ -51,7 +51,7 @@ open class Template: ExpressibleByStringLiteral {
} }
/// Render the given template /// Render the given template
open func render(_ context: Context? = nil) throws -> String { public func render(_ context: Context? = nil) throws -> String {
let context = context ?? Context() let context = context ?? Context()
let parser = TokenParser(tokens: tokens, namespace: context.namespace) let parser = TokenParser(tokens: tokens, namespace: context.namespace)
let nodes = try parser.parse() let nodes = try parser.parse()

View File

@@ -3,8 +3,8 @@ import PathKit
// A class for loading a template from disk // A class for loading a template from disk
open class TemplateLoader { public class TemplateLoader {
open let paths: [Path] public let paths: [Path]
public init(paths: [Path]) { public init(paths: [Path]) {
self.paths = paths self.paths = paths
@@ -16,11 +16,11 @@ open class TemplateLoader {
} }
} }
open func loadTemplate(_ templateName: String) -> Template? { public func loadTemplate(_ templateName: String) -> Template? {
return loadTemplate([templateName]) return loadTemplate([templateName])
} }
open func loadTemplate(_ templateNames: [String]) -> Template? { public func loadTemplate(_ templateNames: [String]) -> Template? {
for path in paths { for path in paths {
for templateName in templateNames { for templateName in templateNames {
let templatePath = path + Path(templateName) let templatePath = path + Path(templateName)

View File

@@ -1,5 +1,5 @@
import Spectre import Spectre
import Stencil @testable import Stencil
import Foundation import Foundation

View File

@@ -1,5 +1,5 @@
import Spectre import Spectre
import Stencil @testable import Stencil
func testIfNode() { func testIfNode() {

View File

@@ -1,5 +1,5 @@
import Spectre import Spectre
import Stencil @testable import Stencil
import PathKit import PathKit

View File

@@ -1,5 +1,5 @@
import Spectre import Spectre
import Stencil @testable import Stencil
func testLexer() { func testLexer() {

View File

@@ -1,6 +1,6 @@
import Foundation import Foundation
import Spectre import Spectre
import Stencil @testable import Stencil
func testNowNode() { func testNowNode() {