diff --git a/CHANGELOG.md b/CHANGELOG.md index 2994156..1e578a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ ### Enhancements +- Variable lookup now supports introspection of Swift types. You can now lookup + values of Swift structures and classes inside a Context. + - If tags can now use prefix and infix operators such as `not`, `and` and `or`. ```html+django diff --git a/README.md b/README.md index d33858f..1a40c72 100644 --- a/README.md +++ b/README.md @@ -11,21 +11,28 @@ feel right at home with Stencil. ```html+django There are {{ articles.count }} articles. -{% for article in articles %} - - {{ article.title }} by {{ article.author }}. -{% endfor %} + ``` ```swift +struct Article { + let title: String + let author: String +} + let context = Context(dictionary: [ "articles": [ - [ "title": "Migrating from OCUnit to XCTest", "author": "Kyle Fuller" ], - [ "title": "Memory Management with ARC", "author": "Kyle Fuller" ], + Article(title: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"), + Article(title: "Memory Management with ARC", author: "Kyle Fuller"), ] ]) do { - let template = try Template(named: "template.stencil") + let template = try Template(named: "template.html") let rendered = try template.render(context) print(rendered) } catch { diff --git a/Sources/Variable.swift b/Sources/Variable.swift index dcd462a..3c29bf6 100644 --- a/Sources/Variable.swift +++ b/Sources/Variable.swift @@ -87,6 +87,13 @@ public struct Variable : Equatable, Resolvable { #else current = object.value(forKey: bit) #endif + } else if let value = current { + let mirror = Mirror(reflecting: value) + current = mirror.descendant(bit) + + if current == nil { + return nil + } } else { return nil } diff --git a/Tests/StencilTests/StencilSpec.swift b/Tests/StencilTests/StencilSpec.swift index c7521e5..fa0cff2 100644 --- a/Tests/StencilTests/StencilSpec.swift +++ b/Tests/StencilTests/StencilSpec.swift @@ -2,16 +2,23 @@ import Spectre import Stencil -class CustomNode : NodeType { +fileprivate class CustomNode : NodeType { func render(_ context:Context) throws -> String { return "Hello World" } } +fileprivate struct Article { + let title: String + let author: String +} + + func testStencil() { describe("Stencil") { $0.it("can render the README example") { + let templateString = "There are {{ articles.count }} articles.\n" + "\n" + "{% for article in articles %}" + @@ -20,8 +27,8 @@ func testStencil() { let context = Context(dictionary: [ "articles": [ - [ "title": "Migrating from OCUnit to XCTest", "author": "Kyle Fuller" ], - [ "title": "Memory Management with ARC", "author": "Kyle Fuller" ], + Article(title: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"), + Article(title: "Memory Management with ARC", author: "Kyle Fuller"), ] ]) diff --git a/Tests/StencilTests/VariableSpec.swift b/Tests/StencilTests/VariableSpec.swift index 2713626..19123d6 100644 --- a/Tests/StencilTests/VariableSpec.swift +++ b/Tests/StencilTests/VariableSpec.swift @@ -9,6 +9,14 @@ import Stencil } #endif +fileprivate struct Person { + let name: String +} + +fileprivate struct Article { + let author: Person +} + func testVariable() { describe("Variable") { @@ -18,6 +26,7 @@ func testVariable() { "profiles": [ "github": "kylef", ], + "article": Article(author: Person(name: "Kyle")) ]) #if os(OSX) @@ -80,6 +89,12 @@ func testVariable() { try expect(result) == "Carlton" } + $0.it("can resolve a property with reflection") { + let variable = Variable("article.author.name") + let result = try variable.resolve(context) as? String + try expect(result) == "Kyle" + } + #if os(OSX) $0.it("can resolve a value via KVO") { let variable = Variable("object.title") diff --git a/docs/index.rst b/docs/index.rst index a2c0c5b..10fbb37 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,15 +17,20 @@ feel right at home with Stencil. .. code-block:: swift + struct Article { + let title: String + let author: String + } + let context = Context(dictionary: [ "articles": [ - [ "title": "Migrating from OCUnit to XCTest", "author": "Kyle Fuller" ], - [ "title": "Memory Management with ARC", "author": "Kyle Fuller" ], + Article(title: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"), + Article(title: "Memory Management with ARC", author: "Kyle Fuller"), ] ]) do { - let template = try Template(named: "template.stencil") + let template = try Template(named: "template.html") let rendered = try template.render(context) print(rendered) } catch { diff --git a/docs/templates.rst b/docs/templates.rst index d112936..6db5e4b 100644 --- a/docs/templates.rst +++ b/docs/templates.rst @@ -22,6 +22,7 @@ following lookup: - Dictionary lookup - Array lookup (first, last, count, index) - Key value coding lookup +- Type introspection For example, if `people` was an array: