Skip to content

Commit

Permalink
Merge pull request #242 from stencilproject/feature/deterministic-for…
Browse files Browse the repository at this point in the history
…-loop

Deterministic `for` loops for dictionaries
  • Loading branch information
djbe authored Sep 21, 2018
2 parents 275e583 + 064b2f7 commit 7ed95ae
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 8 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
- Now accessing undefined keys in NSObject does not cause runtime crash and instead renders empty string.
[Ilya Puchka](https://github.com/ilyapuchka)
[#234](https://github.com/stencilproject/Stencil/pull/234)
- `for` tag: When iterating over a dictionary the keys will now always be sorted (in an ascending order) to ensure consistent output generation.
[David Jennes](https://github.com/djbe)
[#240](https://github.com/stencilproject/Stencil/pull/240)

### Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion Sources/ForTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class ForNode : NodeType {
var values: [Any]

if let dictionary = resolved as? [String: Any], !dictionary.isEmpty {
values = dictionary.map { ($0.key, $0.value) }
values = dictionary.sorted { $0.key < $1.key }
} else if let array = resolved as? [Any] {
values = array
} else if let range = resolved as? CountableClosedRange<Int> {
Expand Down
16 changes: 9 additions & 7 deletions Tests/StencilTests/ForNodeSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,9 @@ func testForNode() {
let template = Template(templateString: templateString)
let result = try template.render(context)

let sortedResult = result.split(separator: ",").map(String.init).sorted(by: <)
try expect(sortedResult) == ["one: I", "two: II"]
try expect(result) == """
one: I,two: II,
"""
}

$0.it("renders supports iterating over dictionary") {
Expand All @@ -222,8 +223,9 @@ func testForNode() {
let node = ForNode(resolvable: Variable("dict"), loopVariables: ["key"], nodes: nodes, emptyNodes: emptyNodes, where: nil)
let result = try node.render(context)

let sortedResult = result.split(separator: ",").map(String.init).sorted(by: <)
try expect(sortedResult) == ["one", "two"]
try expect(result) == """
one,two,
"""
}

$0.it("renders supports iterating over dictionary") {
Expand All @@ -235,11 +237,11 @@ func testForNode() {
]
let emptyNodes: [NodeType] = [TextNode(text: "empty")]
let node = ForNode(resolvable: Variable("dict"), loopVariables: ["key", "value"], nodes: nodes, emptyNodes: emptyNodes, where: nil)

let result = try node.render(context)

let sortedResult = result.split(separator: ",").map(String.init).sorted(by: <)
try expect(sortedResult) == ["one=I", "two=II"]
try expect(result) == """
one=I,two=II,
"""
}

$0.it("handles invalid input") {
Expand Down

0 comments on commit 7ed95ae

Please sign in to comment.