Skip to content
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ Bugfixes:
Other:
-->

## Unreleased

API Changes:

- Allow `enumerateAsArray` and `enumerateAsDict` to accept a function that throws.

## 0.10.0

Other:
Expand Down
20 changes: 11 additions & 9 deletions SwiftCSV/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand All @@ -72,7 +74,7 @@ enum Parser {

var rowIndex = 0

func finishRow() {
func finishRow() throws {
defer {
rowIndex += 1
fields = []
Expand All @@ -81,7 +83,7 @@ enum Parser {

guard rowIndex >= offset else { return }
fields.append(String(field))
rowCallback(fields)
try rowCallback(fields)
}

var state: ParsingState = ParsingState(
Expand Down Expand Up @@ -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()

Expand All @@ -133,7 +135,7 @@ enum Parser {
for (index, head) in enumeratedHeader {
dict[head] = index < fields.count ? fields[index] : ""
}
block(dict)
try block(dict)
}
}
}
10 changes: 5 additions & 5 deletions SwiftCSV/ParsingState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ struct ParsingState {
private(set) var innerQuotes = false

let delimiter: Character
let finishRow: () -> Void
let finishRow: () throws -> Void
let appendChar: (Character) -> Void
let finishField: () -> Void

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Genuine question, not a back-handed request: What do you think about allowing all closures to throw? The public API makes sense this way. But it's a bit odd that eventually this only affects finishRow -- why can finishing a row fail, but not finishing a field?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that makes a lot of sense to me. I'd only updated what was necessary to make the public API allow throw functions, but keeping the private API consistent is a good idea.

I've pushed a commit which covers this.


init(delimiter: Character,
finishRow: @escaping () -> Void,
finishRow: @escaping () throws -> Void,
appendChar: @escaping (Character) -> Void,
finishField: @escaping () -> Void) {

Expand All @@ -44,7 +44,7 @@ struct ParsingState {
} else if char == delimiter {
finishField()
} else if char.isNewline {
finishRow()
try finishRow()
} else if char.isWhitespace {
// ignore whitespaces between fields
} else {
Expand Down Expand Up @@ -72,7 +72,7 @@ struct ParsingState {
atStart = true
parsingField = false
innerQuotes = false
finishRow()
try finishRow()
} else {
appendChar(char)
}
Expand All @@ -91,7 +91,7 @@ struct ParsingState {
atStart = true
parsingQuotes = false
innerQuotes = false
finishRow()
try finishRow()
} else if char.isWhitespace {
// ignore whitespaces between fields
} else {
Expand Down