Skip to content

Commit 324d583

Browse files
Make enumerate methods accept a callback that throws (#144)
This updates the `enumerateAsArray` and `enumerateAsDict` methods to accept a row callback function that throws an error. If the function does throw an error it will be propogated to the caller of the `enumerate` method. This is inspired by #139 with the review comments addressed to hopefully get this functionality in to a release. ## Allow other `ParsingState` closures to throw This follows up on the previous commit which made the `finishRow` closure of `ParsingState` allowed to throw an error, by updating the other two closures of the private API to also throw an error. Although this is not as neccessary for the private API, it keeps the closures consistent, and there's no reason why one should throw and the others should not. --------- Co-authored-by: "Philip B." <145237+philipbel@users.noreply.github.com>
1 parent c8993f6 commit 324d583

3 files changed

Lines changed: 34 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ Bugfixes:
88
Other:
99
-->
1010

11+
## Unreleased
12+
13+
API Changes:
14+
15+
- Allow `enumerateAsArray` and `enumerateAsDict` to accept a function that throws.
16+
1117
## 0.10.0
1218

1319
Other:

SwiftCSV/Parser.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ extension CSV {
2121
/// - rowLimit: Amount of rows to consume, beginning to count at `startAt`. Default value is `nil` to consume
2222
/// the whole input string.
2323
/// - rowCallback: Array of each row's columnar values, in order.
24-
public func enumerateAsArray(startAt: Int = 0, rowLimit: Int? = nil, _ rowCallback: @escaping ([String]) -> ()) throws {
24+
/// - Throws: `CSVParseError` or any error thrown by `rowCallback`
25+
///
26+
public func enumerateAsArray(startAt: Int = 0, rowLimit: Int? = nil, _ rowCallback: @escaping ([String]) throws -> ()) throws {
2527

2628
try Parser.enumerateAsArray(text: self.text, delimiter: self.delimiter, startAt: startAt, rowLimit: rowLimit, rowCallback: rowCallback)
2729
}
2830

29-
public func enumerateAsDict(_ block: @escaping ([String : String]) -> ()) throws {
31+
public func enumerateAsDict(_ block: @escaping ([String : String]) throws -> ()) throws {
3032

3133
try Parser.enumerateAsDict(header: self.header, content: self.text, delimiter: self.delimiter, block: block)
3234
}
@@ -55,12 +57,12 @@ enum Parser {
5557
/// - rowLimit: Amount of rows to consume, beginning to count at `startAt`. Default value is `nil` to consume
5658
/// the whole input string.
5759
/// - rowCallback: Callback invoked for every parsed row between `startAt` and `limitTo` in `text`.
58-
/// - Throws: `CSVParseError`
60+
/// - Throws: `CSVParseError` or any error thrown by `rowCallback`
5961
static func enumerateAsArray(text: String,
6062
delimiter: CSVDelimiter,
6163
startAt offset: Int = 0,
6264
rowLimit: Int? = nil,
63-
rowCallback: @escaping ([String]) -> ()) throws {
65+
rowCallback: @escaping ([String]) throws -> ()) throws {
6466
let maxRowIndex = rowLimit.flatMap { $0 < 0 ? nil : offset + $0 }
6567

6668
var currentIndex = text.startIndex
@@ -72,7 +74,7 @@ enum Parser {
7274

7375
var rowIndex = 0
7476

75-
func finishRow() {
77+
func finishRow() throws {
7678
defer {
7779
rowIndex += 1
7880
fields = []
@@ -81,7 +83,7 @@ enum Parser {
8183

8284
guard rowIndex >= offset else { return }
8385
fields.append(String(field))
84-
rowCallback(fields)
86+
try rowCallback(fields)
8587
}
8688

8789
var state: ParsingState = ParsingState(
@@ -118,12 +120,12 @@ enum Parser {
118120
}
119121

120122
if !fields.isEmpty {
121-
rowCallback(fields)
123+
try rowCallback(fields)
122124
}
123125
}
124126
}
125127

126-
static func enumerateAsDict(header: [String], content: String, delimiter: CSVDelimiter, rowLimit: Int? = nil, block: @escaping ([String : String]) -> ()) throws {
128+
static func enumerateAsDict(header: [String], content: String, delimiter: CSVDelimiter, rowLimit: Int? = nil, block: @escaping ([String : String]) throws -> ()) throws {
127129

128130
let enumeratedHeader = header.enumerated()
129131

@@ -133,7 +135,7 @@ enum Parser {
133135
for (index, head) in enumeratedHeader {
134136
dict[head] = index < fields.count ? fields[index] : ""
135137
}
136-
block(dict)
138+
try block(dict)
137139
}
138140
}
139141
}

SwiftCSV/ParsingState.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ struct ParsingState {
2020
private(set) var innerQuotes = false
2121

2222
let delimiter: Character
23-
let finishRow: () -> Void
24-
let appendChar: (Character) -> Void
25-
let finishField: () -> Void
23+
let finishRow: () throws -> Void
24+
let appendChar: (Character) throws -> Void
25+
let finishField: () throws -> Void
2626

2727
init(delimiter: Character,
28-
finishRow: @escaping () -> Void,
29-
appendChar: @escaping (Character) -> Void,
30-
finishField: @escaping () -> Void) {
28+
finishRow: @escaping () throws -> Void,
29+
appendChar: @escaping (Character) throws -> Void,
30+
finishField: @escaping () throws -> Void) {
3131

3232
self.delimiter = delimiter
3333
self.finishRow = finishRow
@@ -42,20 +42,20 @@ struct ParsingState {
4242
atStart = false
4343
parsingQuotes = true
4444
} else if char == delimiter {
45-
finishField()
45+
try finishField()
4646
} else if char.isNewline {
47-
finishRow()
47+
try finishRow()
4848
} else if char.isWhitespace {
4949
// ignore whitespaces between fields
5050
} else {
5151
parsingField = true
5252
atStart = false
53-
appendChar(char)
53+
try appendChar(char)
5454
}
5555
} else if parsingField {
5656
if innerQuotes {
5757
if char == "\"" {
58-
appendChar(char)
58+
try appendChar(char)
5959
innerQuotes = false
6060
} else {
6161
throw CSVParseError.quotation(message: "Can't have non-quote here: \(char)")
@@ -67,31 +67,31 @@ struct ParsingState {
6767
atStart = true
6868
parsingField = false
6969
innerQuotes = false
70-
finishField()
70+
try finishField()
7171
} else if char.isNewline {
7272
atStart = true
7373
parsingField = false
7474
innerQuotes = false
75-
finishRow()
75+
try finishRow()
7676
} else {
77-
appendChar(char)
77+
try appendChar(char)
7878
}
7979
}
8080
} else if parsingQuotes {
8181
if innerQuotes {
8282
if char == "\"" {
83-
appendChar(char)
83+
try appendChar(char)
8484
innerQuotes = false
8585
} else if char == delimiter {
8686
atStart = true
8787
parsingField = false
8888
innerQuotes = false
89-
finishField()
89+
try finishField()
9090
} else if char.isNewline {
9191
atStart = true
9292
parsingQuotes = false
9393
innerQuotes = false
94-
finishRow()
94+
try finishRow()
9595
} else if char.isWhitespace {
9696
// ignore whitespaces between fields
9797
} else {
@@ -101,7 +101,7 @@ struct ParsingState {
101101
if char == "\"" {
102102
innerQuotes = true
103103
} else {
104-
appendChar(char)
104+
try appendChar(char)
105105
}
106106
}
107107
} else {

0 commit comments

Comments
 (0)