diff --git a/.travis.yml b/.travis.yml index 0d109c3..df312b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,11 @@ os: -- osx + - osx + - linux +language: generic +sudo: required +dist: trusty osx_image: xcode7.2 install: -- curl -sL https://gist.github.com/kylef/5c0475ff02b7c7671d2a/raw/621ef9b29bbb852fdfd2e10ed147b321d792c1e4/swiftenv-install.sh | bash + - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/02090c7ede5a637b76e6df1710e83cd0bbe7dcdf/swiftenv-install.sh)" script: -- . ~/.swiftenv/init - make test diff --git a/Sources/Namespace.swift b/Sources/Namespace.swift index becad8f..52fca61 100644 --- a/Sources/Namespace.swift +++ b/Sources/Namespace.swift @@ -13,7 +13,9 @@ public class Namespace { registerTag("for", parser: ForNode.parse) registerTag("if", parser: IfNode.parse) registerTag("ifnot", parser: IfNode.parse_ifnot) +#if !os(Linux) registerTag("now", parser: NowNode.parse) +#endif registerTag("include", parser: IncludeNode.parse) registerTag("extends", parser: ExtendsNode.parse) registerTag("block", parser: BlockNode.parse) diff --git a/Sources/Node.swift b/Sources/Node.swift index 8110352..f752910 100644 --- a/Sources/Node.swift +++ b/Sources/Node.swift @@ -76,6 +76,8 @@ public class VariableNode : NodeType { } } + +#if !os(Linux) public class NowNode : NodeType { public let format:Variable @@ -114,6 +116,8 @@ public class NowNode : NodeType { return formatter!.stringFromDate(date) } } +#endif + public class ForNode : NodeType { let variable:Variable diff --git a/Sources/Variable.swift b/Sources/Variable.swift index 70b8d65..291b529 100644 --- a/Sources/Variable.swift +++ b/Sources/Variable.swift @@ -56,11 +56,13 @@ public struct Variable : Equatable, Resolvable { } for bit in lookup() { + current = normalize(current) + if let context = current as? Context { current = context[bit] - } else if let dictionary = resolveDictionary(current) { + } else if let dictionary = current as? [String: Any] { current = dictionary[bit] - } else if let array = resolveArray(current) { + } else if let array = current as? [Any] { if let index = Int(bit) { current = array[index] } else if bit == "first" { @@ -90,50 +92,42 @@ public func ==(lhs: Variable, rhs: Variable) -> Bool { } -func resolveDictionary(current: Any?) -> [String: Any]? { - switch current { - case let dictionary as [String: Any]: - return dictionary - case let dictionary as [String: AnyObject]: - var result: [String: Any] = [:] - for (k, v) in dictionary { - result[k] = v as Any - } - return result - case let dictionary as NSDictionary: - var result: [String: Any] = [:] - for (k, v) in dictionary { - if let k = k as? String { - result[k] = v as Any - } - } - return result - default: - return nil - } -} - -func resolveArray(current: Any?) -> [Any]? { - switch current { - case let array as [Any]: - return array - case let array as [AnyObject]: - return array.map { $0 as Any } - case let array as NSArray: - return array.map { $0 as Any } - default: - return nil - } -} - func normalize(current: Any?) -> Any? { - if let array = resolveArray(current) { - return array - } - - if let dictionary = resolveDictionary(current) { - return dictionary + if let current = current as? Normalizable { + return current.normalize() } return current } + +protocol Normalizable { + func normalize() -> Any? +} + +extension Array : Normalizable { + func normalize() -> Any? { + return map { $0 as Any } + } +} + +extension NSArray : Normalizable { + func normalize() -> Any? { + return map { $0 as Any } + } +} + +extension Dictionary : Normalizable { + func normalize() -> Any? { + var dictionary: [String: Any] = [:] + + for (key, value) in self { + if let key = key as? String { + dictionary[key] = Stencil.normalize(value) + } else if let key = key as? CustomStringConvertible { + dictionary[key.description] = Stencil.normalize(value) + } + } + + return dictionary + } +} diff --git a/Tests/Nodes/ForNodeSpec.swift b/Tests/Nodes/ForNodeSpec.swift index 856035a..15b3f6c 100644 --- a/Tests/Nodes/ForNodeSpec.swift +++ b/Tests/Nodes/ForNodeSpec.swift @@ -33,6 +33,7 @@ func testForNode() { try expect(try node.render(any_context)) == "123" } +#if os(OSX) $0.it("renders a context variable of type NSArray") { let nsarray_context = Context(dictionary: [ "items": NSArray(array: [1, 2, 3]) @@ -40,8 +41,9 @@ func testForNode() { let nodes: [NodeType] = [VariableNode(variable: "item")] let node = ForNode(variable: "items", loopVariable: "item", nodes: nodes, emptyNodes: []) - try expect(try node.render(nsarray_context)) == "123" + try expect(try node.render(nsarray_context)) == "123" } +#endif $0.it("renders the given nodes while providing if the item is first in the context") { let nodes: [NodeType] = [VariableNode(variable: "item"), VariableNode(variable: "forloop.first")] diff --git a/Tests/Nodes/IfNodeSpec.swift b/Tests/Nodes/IfNodeSpec.swift index 49f563a..156031d 100644 --- a/Tests/Nodes/IfNodeSpec.swift +++ b/Tests/Nodes/IfNodeSpec.swift @@ -86,21 +86,21 @@ func testIfNode() { } $0.it("renders the truth when array expression is not empty") { - let items: Array<[String:AnyObject]> = [["key":"key1","value":42],["key":"key2","value":1337]] + let items: [[String: Any]] = [["key":"key1","value":42],["key":"key2","value":1337]] let arrayContext = Context(dictionary: ["items": [items]]) let node = IfNode(variable: "items", trueNodes: [TextNode(text: "true")], falseNodes: [TextNode(text: "false")]) try expect(try node.render(arrayContext)) == "true" } $0.it("renders the false when array expression is empty") { - let emptyItems = Array<[String:AnyObject]>() + let emptyItems = [[String: Any]]() let arrayContext = Context(dictionary: ["items": emptyItems]) let node = IfNode(variable: "items", trueNodes: [TextNode(text: "true")], falseNodes: [TextNode(text: "false")]) try expect(try node.render(arrayContext)) == "false" } $0.it("renders the false when dictionary expression is empty") { - let emptyItems = [String:AnyObject]() + let emptyItems = [String:Any]() let arrayContext = Context(dictionary: ["items": emptyItems]) let node = IfNode(variable: "items", trueNodes: [TextNode(text: "true")], falseNodes: [TextNode(text: "false")]) try expect(try node.render(arrayContext)) == "false" diff --git a/Tests/Nodes/NowNodeSpec.swift b/Tests/Nodes/NowNodeSpec.swift index e0d9451..912ad75 100644 --- a/Tests/Nodes/NowNodeSpec.swift +++ b/Tests/Nodes/NowNodeSpec.swift @@ -4,6 +4,7 @@ import Stencil func testNowNode() { +#if !os(Linux) describe("NowNode") { $0.describe("parsing") { $0.it("parses default format without any now arguments") { @@ -38,4 +39,5 @@ func testNowNode() { } } } +#endif } diff --git a/Tests/ParserSpec.swift b/Tests/ParserSpec.swift index 5e4495c..fdac74d 100644 --- a/Tests/ParserSpec.swift +++ b/Tests/ParserSpec.swift @@ -38,9 +38,14 @@ func testTokenParser() { } $0.it("can parse a tag token") { + let namespace = Namespace() + namespace.registerSimpleTag("known") { _ in + return "" + } + let parser = TokenParser(tokens: [ - Token.Block(value: "now"), - ], namespace: Namespace()) + Token.Block(value: "known"), + ], namespace: namespace) let nodes = try parser.parse() try expect(nodes.count) == 1 diff --git a/Tests/VariableSpec.swift b/Tests/VariableSpec.swift index 1b1c36c..0b4b7f3 100644 --- a/Tests/VariableSpec.swift +++ b/Tests/VariableSpec.swift @@ -3,9 +3,11 @@ import Spectre import Stencil +#if os(OSX) @objc class Object : NSObject { let title = "Hello World" } +#endif func testVariable() { @@ -16,9 +18,12 @@ func testVariable() { "profiles": [ "github": "kylef", ], - "object": Object(), ]) +#if os(OSX) + context.push(["object": Object()]) +#endif + $0.it("can resolve a string literal with double quotes") { let variable = Variable("\"name\"") let result = try variable.resolve(context) as? String @@ -61,10 +66,12 @@ func testVariable() { try expect(result) == "Carlton" } +#if os(OSX) $0.it("can resolve a value via KVO") { let variable = Variable("object.title") let result = try variable.resolve(context) as? String try expect(result) == "Hello World" } +#endif } }