diff --git a/CHANGELOG.md b/CHANGELOG.md index d15d2df..8cd7555 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ Bugfixes: Other: --> +## Unreleased + +API Changes: + +- Allow `enumerateAsArray` and `enumerateAsDict` to accept a function that throws. + ## 0.10.0 Other: diff --git a/SwiftCSV/Parser.swift b/SwiftCSV/Parser.swift index ac329ff..e6db465 100644 --- a/SwiftCSV/Parser.swift +++ b/SwiftCSV/Parser.swift @@ -21,12 +21,14 @@ extension CSV { /// - rowLimit: Amount of rows to consume, beginning to count at `startAt`. Default value is `nil` to consume /// the whole input string. /// - rowCallback: Array of each row's columnar values, in order. - public func enumerateAsArray(startAt: Int = 0, rowLimit: Int? = nil, _ rowCallback: @escaping ([String]) -> ()) throws { + /// - Throws: `CSVParseError` or any error thrown by `rowCallback` + /// + public func enumerateAsArray(startAt: Int = 0, rowLimit: Int? = nil, _ rowCallback: @escaping ([String]) throws -> ()) throws { try Parser.enumerateAsArray(text: self.text, delimiter: self.delimiter, startAt: startAt, rowLimit: rowLimit, rowCallback: rowCallback) } - public func enumerateAsDict(_ block: @escaping ([String : String]) -> ()) throws { + public func enumerateAsDict(_ block: @escaping ([String : String]) throws -> ()) throws { try Parser.enumerateAsDict(header: self.header, content: self.text, delimiter: self.delimiter, block: block) } @@ -55,12 +57,12 @@ enum Parser { /// - rowLimit: Amount of rows to consume, beginning to count at `startAt`. Default value is `nil` to consume /// the whole input string. /// - rowCallback: Callback invoked for every parsed row between `startAt` and `limitTo` in `text`. - /// - Throws: `CSVParseError` + /// - Throws: `CSVParseError` or any error thrown by `rowCallback` static func enumerateAsArray(text: String, delimiter: CSVDelimiter, startAt offset: Int = 0, rowLimit: Int? = nil, - rowCallback: @escaping ([String]) -> ()) throws { + rowCallback: @escaping ([String]) throws -> ()) throws { let maxRowIndex = rowLimit.flatMap { $0 < 0 ? nil : offset + $0 } var currentIndex = text.startIndex @@ -72,7 +74,7 @@ enum Parser { var rowIndex = 0 - func finishRow() { + func finishRow() throws { defer { rowIndex += 1 fields = [] @@ -81,7 +83,7 @@ enum Parser { guard rowIndex >= offset else { return } fields.append(String(field)) - rowCallback(fields) + try rowCallback(fields) } var state: ParsingState = ParsingState( @@ -118,12 +120,12 @@ enum Parser { } if !fields.isEmpty { - rowCallback(fields) + try rowCallback(fields) } } } - static func enumerateAsDict(header: [String], content: String, delimiter: CSVDelimiter, rowLimit: Int? = nil, block: @escaping ([String : String]) -> ()) throws { + static func enumerateAsDict(header: [String], content: String, delimiter: CSVDelimiter, rowLimit: Int? = nil, block: @escaping ([String : String]) throws -> ()) throws { let enumeratedHeader = header.enumerated() @@ -133,7 +135,7 @@ enum Parser { for (index, head) in enumeratedHeader { dict[head] = index < fields.count ? fields[index] : "" } - block(dict) + try block(dict) } } } diff --git a/SwiftCSV/ParsingState.swift b/SwiftCSV/ParsingState.swift index ed37ce0..fc0e671 100644 --- a/SwiftCSV/ParsingState.swift +++ b/SwiftCSV/ParsingState.swift @@ -20,14 +20,14 @@ struct ParsingState { private(set) var innerQuotes = false let delimiter: Character - let finishRow: () -> Void - let appendChar: (Character) -> Void - let finishField: () -> Void + let finishRow: () throws -> Void + let appendChar: (Character) throws -> Void + let finishField: () throws -> Void init(delimiter: Character, - finishRow: @escaping () -> Void, - appendChar: @escaping (Character) -> Void, - finishField: @escaping () -> Void) { + finishRow: @escaping () throws -> Void, + appendChar: @escaping (Character) throws -> Void, + finishField: @escaping () throws -> Void) { self.delimiter = delimiter self.finishRow = finishRow @@ -42,20 +42,20 @@ struct ParsingState { atStart = false parsingQuotes = true } else if char == delimiter { - finishField() + try finishField() } else if char.isNewline { - finishRow() + try finishRow() } else if char.isWhitespace { // ignore whitespaces between fields } else { parsingField = true atStart = false - appendChar(char) + try appendChar(char) } } else if parsingField { if innerQuotes { if char == "\"" { - appendChar(char) + try appendChar(char) innerQuotes = false } else { throw CSVParseError.quotation(message: "Can't have non-quote here: \(char)") @@ -67,31 +67,31 @@ struct ParsingState { atStart = true parsingField = false innerQuotes = false - finishField() + try finishField() } else if char.isNewline { atStart = true parsingField = false innerQuotes = false - finishRow() + try finishRow() } else { - appendChar(char) + try appendChar(char) } } } else if parsingQuotes { if innerQuotes { if char == "\"" { - appendChar(char) + try appendChar(char) innerQuotes = false } else if char == delimiter { atStart = true parsingField = false innerQuotes = false - finishField() + try finishField() } else if char.isNewline { atStart = true parsingQuotes = false innerQuotes = false - finishRow() + try finishRow() } else if char.isWhitespace { // ignore whitespaces between fields } else { @@ -101,7 +101,7 @@ struct ParsingState { if char == "\"" { innerQuotes = true } else { - appendChar(char) + try appendChar(char) } } } else {