diff --git a/Stencil/Node.swift b/Stencil/Node.swift index 9f29332..8345989 100644 --- a/Stencil/Node.swift +++ b/Stencil/Node.swift @@ -157,7 +157,7 @@ public class ForNode : NodeType { public func render(context: Context) throws -> String { let values = try variable.resolve(context) - if let values = values as? NSArray where values.count > 0 { + if let values = values as? [Any] where values.count > 0 { return try values.map { item in try context.push([loopVariable: item]) { try renderNodes(nodes, context) @@ -232,10 +232,10 @@ public class IfNode : NodeType { let result = try variable.resolve(context) var truthy = false - if let result = result as? NSArray { - if result.count > 0 { - truthy = true - } + if let result = result as? [Any] { + truthy = !result.isEmpty + } else if let result = result as? [String:Any] { + truthy = !result.isEmpty } else if result != nil { truthy = true } diff --git a/Stencil/Variable.swift b/Stencil/Variable.swift index 061059b..aa544f3 100644 --- a/Stencil/Variable.swift +++ b/Stencil/Variable.swift @@ -58,11 +58,9 @@ public struct Variable : Equatable, Resolvable { for bit in lookup() { if let context = current as? Context { current = context[bit] - } else if let dictionary = current as? [String: Any] { + } else if let dictionary = resolveDictionary(current) { current = dictionary[bit] - } else if let dictionary = current as? [String: AnyObject] { - current = dictionary[bit] - } else if let array = current as? [Any] { + } else if let array = resolveArray(current) { if let index = Int(bit) { current = array[index] } else if bit == "first" { @@ -72,27 +70,72 @@ public struct Variable : Equatable, Resolvable { } else if bit == "count" { current = array.count } - } else if let array = current as? NSArray { - if let index = Int(bit) { - current = array[index] - } else if bit == "first" { - current = array.firstObject - } else if bit == "last" { - current = array.lastObject - } else if bit == "count" { - current = array.count - } - } else if let object = current as? NSObject { + } else if let object = current as? NSObject { // NSKeyValueCoding current = object.valueForKey(bit) } else { return nil } } - return current + return normalize(current) } } public func ==(lhs: Variable, rhs: Variable) -> Bool { return lhs.variable == rhs.variable } + + +func resolveDictionary(current: Any?) -> [String: Any]? { + if let dictionary = current as? [String: Any] { + return dictionary + } + + if let dictionary = current as? [String: AnyObject] { + var result: [String: Any] = [:] + for (k, v) in dictionary { + result[k] = v as Any + } + return result + } + + if let dictionary = current as? NSDictionary { + var result: [String: Any] = [:] + for (k, v) in dictionary { + if let k = k as? String { + result[k] = v as Any + } + } + return result + } + + return nil +} + +func resolveArray(current: Any?) -> [Any]? { + if let current = current as? [Any] { + return current + } + + if let current = current as? [AnyObject] { + return current.map { $0 as Any } + } + + if let current = current as? NSArray { + return current.map { $0 as Any } + } + + return nil +} + +func normalize(current: Any?) -> Any? { + if let array = resolveArray(current) { + return array + } + + if let dictionary = resolveDictionary(current) { + return dictionary + } + + return current +} diff --git a/StencilSpecs/Nodes/IfNodeSpec.swift b/StencilSpecs/Nodes/IfNodeSpec.swift index c46edc6..03fb04a 100644 --- a/StencilSpecs/Nodes/IfNodeSpec.swift +++ b/StencilSpecs/Nodes/IfNodeSpec.swift @@ -96,5 +96,12 @@ describe("IfNode") { 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 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" + } } }