feat: Allow iterating over tuple, struct and class properties

Closes #173
This commit is contained in:
Ilya Puchka
2017-12-27 22:13:33 +01:00
committed by Kyle Fuller
parent 0156f6f37b
commit c0e66eb96f
3 changed files with 95 additions and 0 deletions

View File

@@ -5,6 +5,8 @@
### Enhancements ### Enhancements
- Added support for resolving superclass properties for not-NSObject subclasses - Added support for resolving superclass properties for not-NSObject subclasses
- The `{% for %}` tag can now iterate over tuples, structures and classes via
their stored properties.
### Bug Fixes ### Bug Fixes

View File

@@ -94,6 +94,22 @@ class ForNode : NodeType {
values = Array(range) values = Array(range)
} else if let range = resolved as? CountableRange<Int> { } else if let range = resolved as? CountableRange<Int> {
values = Array(range) values = Array(range)
} else if let resolved = resolved {
let mirror = Mirror(reflecting: resolved)
switch mirror.displayStyle {
case .struct?, .tuple?:
values = Array(mirror.children)
case .class?:
var children = Array(mirror.children)
var currentMirror: Mirror? = mirror
while let superclassMirror = currentMirror?.superclassMirror {
children.append(contentsOf: superclassMirror.children)
currentMirror = superclassMirror
}
values = Array(children)
default:
values = []
}
} else { } else {
values = [] values = []
} }

View File

@@ -176,7 +176,84 @@ func testForNode() {
let error = TemplateSyntaxError("'for' statements should use the following 'for x in y where condition' `for i`.") let error = TemplateSyntaxError("'for' statements should use the following 'for x in y where condition' `for i`.")
try expect(try parser.parse()).toThrow(error) try expect(try parser.parse()).toThrow(error)
} }
$0.it("can iterate over struct properties") {
struct MyStruct {
let string: String
let number: Int
} }
let context = Context(dictionary: [
"struct": MyStruct(string: "abc", number: 123)
])
let nodes: [NodeType] = [
VariableNode(variable: "property"),
TextNode(text: "="),
VariableNode(variable: "value"),
TextNode(text: "\n"),
]
let node = ForNode(resolvable: Variable("struct"), loopVariables: ["property", "value"], nodes: nodes, emptyNodes: [])
let result = try node.render(context)
try expect(result) == "string=abc\nnumber=123\n"
}
$0.it("can iterate tuple items") {
let context = Context(dictionary: [
"tuple": (one: 1, two: "dva"),
])
let nodes: [NodeType] = [
VariableNode(variable: "label"),
TextNode(text: "="),
VariableNode(variable: "value"),
TextNode(text: "\n"),
]
let node = ForNode(resolvable: Variable("tuple"), loopVariables: ["label", "value"], nodes: nodes, emptyNodes: [])
let result = try node.render(context)
try expect(result) == "one=1\ntwo=dva\n"
}
$0.it("can iterate over class properties") {
class MyClass {
var baseString: String
var baseInt: Int
init(_ string: String, _ int: Int) {
baseString = string
baseInt = int
}
}
class MySubclass: MyClass {
var childString: String
init(_ childString: String, _ string: String, _ int: Int) {
self.childString = childString
super.init(string, int)
}
}
let context = Context(dictionary: [
"class": MySubclass("child", "base", 1)
])
let nodes: [NodeType] = [
VariableNode(variable: "label"),
TextNode(text: "="),
VariableNode(variable: "value"),
TextNode(text: "\n"),
]
let node = ForNode(resolvable: Variable("class"), loopVariables: ["label", "value"], nodes: nodes, emptyNodes: [])
let result = try node.render(context)
try expect(result) == "childString=child\nbaseString=base\nbaseInt=1\n"
}
}
} }