feat(variable): Allow Swift type introspection

This commit is contained in:
Kyle Fuller
2016-11-28 06:13:46 +00:00
parent 9af9cf4005
commit 38d7ec87f6
7 changed files with 57 additions and 12 deletions

View File

@@ -17,6 +17,9 @@
### Enhancements ### 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`. - If tags can now use prefix and infix operators such as `not`, `and` and `or`.
```html+django ```html+django

View File

@@ -11,21 +11,28 @@ feel right at home with Stencil.
```html+django ```html+django
There are {{ articles.count }} articles. There are {{ articles.count }} articles.
{% for article in articles %} <ul>
- {{ article.title }} by {{ article.author }}. {% for article in articles %}
{% endfor %} <li>{{ article.title }} by {{ article.author }}</li>
{% endfor %}
</ul>
``` ```
```swift ```swift
struct Article {
let title: String
let author: String
}
let context = Context(dictionary: [ let context = Context(dictionary: [
"articles": [ "articles": [
[ "title": "Migrating from OCUnit to XCTest", "author": "Kyle Fuller" ], Article(title: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"),
[ "title": "Memory Management with ARC", "author": "Kyle Fuller" ], Article(title: "Memory Management with ARC", author: "Kyle Fuller"),
] ]
]) ])
do { do {
let template = try Template(named: "template.stencil") let template = try Template(named: "template.html")
let rendered = try template.render(context) let rendered = try template.render(context)
print(rendered) print(rendered)
} catch { } catch {

View File

@@ -87,6 +87,13 @@ public struct Variable : Equatable, Resolvable {
#else #else
current = object.value(forKey: bit) current = object.value(forKey: bit)
#endif #endif
} else if let value = current {
let mirror = Mirror(reflecting: value)
current = mirror.descendant(bit)
if current == nil {
return nil
}
} else { } else {
return nil return nil
} }

View File

@@ -2,16 +2,23 @@ import Spectre
import Stencil import Stencil
class CustomNode : NodeType { fileprivate class CustomNode : NodeType {
func render(_ context:Context) throws -> String { func render(_ context:Context) throws -> String {
return "Hello World" return "Hello World"
} }
} }
fileprivate struct Article {
let title: String
let author: String
}
func testStencil() { func testStencil() {
describe("Stencil") { describe("Stencil") {
$0.it("can render the README example") { $0.it("can render the README example") {
let templateString = "There are {{ articles.count }} articles.\n" + let templateString = "There are {{ articles.count }} articles.\n" +
"\n" + "\n" +
"{% for article in articles %}" + "{% for article in articles %}" +
@@ -20,8 +27,8 @@ func testStencil() {
let context = Context(dictionary: [ let context = Context(dictionary: [
"articles": [ "articles": [
[ "title": "Migrating from OCUnit to XCTest", "author": "Kyle Fuller" ], Article(title: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"),
[ "title": "Memory Management with ARC", "author": "Kyle Fuller" ], Article(title: "Memory Management with ARC", author: "Kyle Fuller"),
] ]
]) ])

View File

@@ -9,6 +9,14 @@ import Stencil
} }
#endif #endif
fileprivate struct Person {
let name: String
}
fileprivate struct Article {
let author: Person
}
func testVariable() { func testVariable() {
describe("Variable") { describe("Variable") {
@@ -18,6 +26,7 @@ func testVariable() {
"profiles": [ "profiles": [
"github": "kylef", "github": "kylef",
], ],
"article": Article(author: Person(name: "Kyle"))
]) ])
#if os(OSX) #if os(OSX)
@@ -80,6 +89,12 @@ func testVariable() {
try expect(result) == "Carlton" 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) #if os(OSX)
$0.it("can resolve a value via KVO") { $0.it("can resolve a value via KVO") {
let variable = Variable("object.title") let variable = Variable("object.title")

View File

@@ -17,15 +17,20 @@ feel right at home with Stencil.
.. code-block:: swift .. code-block:: swift
struct Article {
let title: String
let author: String
}
let context = Context(dictionary: [ let context = Context(dictionary: [
"articles": [ "articles": [
[ "title": "Migrating from OCUnit to XCTest", "author": "Kyle Fuller" ], Article(title: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"),
[ "title": "Memory Management with ARC", "author": "Kyle Fuller" ], Article(title: "Memory Management with ARC", author: "Kyle Fuller"),
] ]
]) ])
do { do {
let template = try Template(named: "template.stencil") let template = try Template(named: "template.html")
let rendered = try template.render(context) let rendered = try template.render(context)
print(rendered) print(rendered)
} catch { } catch {

View File

@@ -22,6 +22,7 @@ following lookup:
- Dictionary lookup - Dictionary lookup
- Array lookup (first, last, count, index) - Array lookup (first, last, count, index)
- Key value coding lookup - Key value coding lookup
- Type introspection
For example, if `people` was an array: For example, if `people` was an array: