Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterating array of tuples with more than two values #177

Merged
merged 2 commits into from
Mar 13, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- 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.
- Added support for iterating arrays of tuples

### Bug Fixes

Expand Down
23 changes: 12 additions & 11 deletions Sources/ForTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,26 @@ class ForNode : NodeType {
self.where = `where`
}

func push<Result>(value: Any, context: Context, closure: () throws -> (Result)) rethrows -> Result {
func push<Result>(value: Any, context: Context, closure: () throws -> (Result)) throws -> Result {
if loopVariables.isEmpty {
return try context.push() {
return try closure()
}
}

if let value = value as? (Any, Any) {
let first = loopVariables[0]

if loopVariables.count == 2 {
let second = loopVariables[1]

return try context.push(dictionary: [first: value.0, second: value.1]) {
return try closure()
}
let valueMirror = Mirror(reflecting: value)
if case .tuple? = valueMirror.displayStyle {
if loopVariables.count > Int(valueMirror.children.count) {
throw TemplateSyntaxError("Tuple '\(value)' has less values than loop variables")
}
var variablesContext = [String: Any]()
valueMirror.children.prefix(loopVariables.count).enumerated().forEach({ (offset, element) in
if loopVariables[offset] != "_" {
variablesContext[loopVariables[offset]] = element.value
}
})

return try context.push(dictionary: [first: value.0]) {
return try context.push(dictionary: variablesContext) {
return try closure()
}
}
Expand Down
50 changes: 49 additions & 1 deletion Tests/StencilTests/ForNodeSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ func testForNode() {
"dict": [
"one": "I",
"two": "II",
]
],
"tuples": [(1, 2, 3), (4, 5, 6)]
])

$0.it("renders the given nodes for each item") {
Expand Down Expand Up @@ -127,6 +128,53 @@ func testForNode() {
try expect(result) == fixture
}

$0.context("given array of tuples") {
$0.it("can iterate over all tuple values") {
let templateString = "{% for first,second,third in tuples %}" +
"{{ first }}, {{ second }}, {{ third }}\n" +
"{% endfor %}\n"

let template = Template(templateString: templateString)
let result = try template.render(context)

let fixture = "1, 2, 3\n4, 5, 6\n\n"
try expect(result) == fixture
}

$0.it("can iterate with less number of variables") {
let templateString = "{% for first,second in tuples %}" +
"{{ first }}, {{ second }}\n" +
"{% endfor %}\n"

let template = Template(templateString: templateString)
let result = try template.render(context)

let fixture = "1, 2\n4, 5\n\n"
try expect(result) == fixture
}

$0.it("can use _ to skip variables") {
let templateString = "{% for first,_,third in tuples %}" +
"{{ first }}, {{ third }}\n" +
"{% endfor %}\n"

let template = Template(templateString: templateString)
let result = try template.render(context)

let fixture = "1, 3\n4, 6\n\n"
try expect(result) == fixture
}

$0.it("throws when number of variables is more than number of tuple values") {
let templateString = "{% for key,value,smth in dict %}" +
"{% endfor %}\n"

let template = Template(templateString: templateString)
try expect(template.render(context)).toThrow()
}

}

$0.it("can iterate over dictionary") {
let templateString = "{% for key,value in dict %}" +
"{{ key }}: {{ value }}," +
Expand Down