Merge branch 'master' into fix-float-from-int
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 = []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,22 +135,37 @@ func testForNode() {
|
|||||||
let template = Template(templateString: templateString)
|
let template = Template(templateString: templateString)
|
||||||
let result = try template.render(context)
|
let result = try template.render(context)
|
||||||
|
|
||||||
let fixture = "one: I\ntwo: II\n\n"
|
let sortedResult = result.split(separator: "\n").sorted(by: <)
|
||||||
try expect(result) == fixture
|
try expect(sortedResult) == ["one: I", "two: II"]
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("renders supports iterating over dictionary") {
|
$0.it("renders supports iterating over dictionary") {
|
||||||
let nodes: [NodeType] = [VariableNode(variable: "key")]
|
let nodes: [NodeType] = [
|
||||||
|
VariableNode(variable: "key"),
|
||||||
|
TextNode(text: ","),
|
||||||
|
]
|
||||||
let emptyNodes: [NodeType] = [TextNode(text: "empty")]
|
let emptyNodes: [NodeType] = [TextNode(text: "empty")]
|
||||||
let node = ForNode(resolvable: Variable("dict"), loopVariables: ["key"], nodes: nodes, emptyNodes: emptyNodes, where: nil)
|
let node = ForNode(resolvable: Variable("dict"), loopVariables: ["key"], nodes: nodes, emptyNodes: emptyNodes, where: nil)
|
||||||
try expect(try node.render(context)) == "onetwo"
|
let result = try node.render(context)
|
||||||
|
|
||||||
|
let sortedResult = result.split(separator: ",").sorted(by: <)
|
||||||
|
try expect(sortedResult) == ["one", "two"]
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("renders supports iterating over dictionary") {
|
$0.it("renders supports iterating over dictionary") {
|
||||||
let nodes: [NodeType] = [VariableNode(variable: "key"), VariableNode(variable: "value")]
|
let nodes: [NodeType] = [
|
||||||
|
VariableNode(variable: "key"),
|
||||||
|
TextNode(text: "="),
|
||||||
|
VariableNode(variable: "value"),
|
||||||
|
TextNode(text: ","),
|
||||||
|
]
|
||||||
let emptyNodes: [NodeType] = [TextNode(text: "empty")]
|
let emptyNodes: [NodeType] = [TextNode(text: "empty")]
|
||||||
let node = ForNode(resolvable: Variable("dict"), loopVariables: ["key", "value"], nodes: nodes, emptyNodes: emptyNodes, where: nil)
|
let node = ForNode(resolvable: Variable("dict"), loopVariables: ["key", "value"], nodes: nodes, emptyNodes: emptyNodes, where: nil)
|
||||||
try expect(try node.render(context)) == "oneItwoII"
|
|
||||||
|
let result = try node.render(context)
|
||||||
|
|
||||||
|
let sortedResult = result.split(separator: ",").sorted(by: <)
|
||||||
|
try expect(sortedResult) == ["one=I", "two=II"]
|
||||||
}
|
}
|
||||||
|
|
||||||
$0.it("handles invalid input") {
|
$0.it("handles invalid input") {
|
||||||
@@ -161,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"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user