Skip to content

Commit

Permalink
Added Suspendable Open Calls (#69)
Browse files Browse the repository at this point in the history
* Added Suspendable Open Calls

- updated README.md
- added equivalent suspend aware open csv calls
- added respectively suspend open call tests

* Fixed Comment Issue

Co-authored-by: Victor Harlan D. Lacson <[email protected]>
  • Loading branch information
blackmo18 and Victor Harlan D. Lacson authored Nov 4, 2020
1 parent f1fe2c8 commit 15e0ea3
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 1 deletion.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ csvReader().open("test.csv") {
}
```

#### Read in a `Suspending Function`
```kotlin
csvReader().openAsync("test.csv") {
val container = mutalbeListOf<List<String>>()
delay(100) //other suspending task
readAllAsSequence().asFlow().collect { row ->
delay(100) // other suspending task
container(row)
}
}
```
Note: `openAsync` can be and only be accessed through a `coroutine` or another `suspending` function

#### Customize

When you create CsvReader, you can choose read options.
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ kotlin {
dependencies {
implementation(kotlin("test"))
implementation(kotlin("test-junit"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2")
implementation("io.kotlintest:kotlintest-runner-junit5:3.3.2")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,25 @@ actual class CsvReader actual constructor(
return open(File(fileName), read)
}

/**
* open inputStreamReader and execute reading process on a **suspending** function.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
*
* Usage example:
* <pre>
* val data: Sequence<List<String?>> = csvReader().openAsync("test.csv") {
* readAllAsSequence()
* .map { fields -> fields.map { it.trim() } }
* .map { fields -> fields.map { if(it.isBlank()) null else it } }
* }
* </pre>
*/
suspend fun <T> openAsync(fileName: String, read: suspend CsvFileReader.() -> T): T {
return openAsync(File(fileName), read)
}

/**
* open inputStreamReader and execute reading process.
*
Expand All @@ -112,7 +131,21 @@ actual class CsvReader actual constructor(
}

/**
* open inputStreamReader and execute reading process.
* open inputStreamReader and execute reading process on a **suspending** function.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
*
* Usage example:
* @see openAsync method
*/
suspend fun <T> openAsync(file: File, read: suspend CsvFileReader.() -> T): T {
val br = file.inputStream().bufferedReader(charsetCode)
return openAsync(br, read)
}

/**
* open inputStreamReader and execute reading process on a **suspending** function.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
Expand All @@ -125,10 +158,31 @@ actual class CsvReader actual constructor(
return open(br, read)
}

/**
* open inputStreamReader and execute reading process on a **suspending** function.
*
* If you want to control read flow precisely, use this method.
* Otherwise, use utility method (e.g. CsvReader.readAll ).
*
* Usage example:
* @see openAsync method
*/
suspend fun <T> openAsync(ips: InputStream, read: suspend CsvFileReader.()-> T): T {
val br = ips.bufferedReader(charsetCode)
return openAsync(br, read)
}

private fun <T> open(br: BufferedReader, doRead: CsvFileReader.() -> T): T {
val reader = CsvFileReader(ctx, br)
return reader.use {
reader.doRead()
}
}

private suspend fun <T> openAsync(br: BufferedReader, doRead: suspend CsvFileReader.() -> T): T {
val reader = CsvFileReader(ctx, br)
return reader.use {
reader.doRead()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import com.github.doyaaaaaken.kotlincsv.util.Const
import com.github.doyaaaaaken.kotlincsv.util.MalformedCSVException
import io.kotlintest.shouldBe
import io.kotlintest.shouldThrow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collect
import java.io.File
import kotlin.test.assertEquals

Expand Down Expand Up @@ -253,6 +255,44 @@ class CsvReaderTest : WordSpec() {
}
rows shouldBe listOf(listOf("a", "b", "c"), listOf("d", "e", "f"))
}
"execute as suspending function" should {
"open suspending method (with fileName argument)" {
val rows = csvReader().openAsync("src/jvmTest/resources/testdata/csv/simple.csv") {
val row1 = readNext()
val row2 = readNext()
listOf(row1, row2)
}
rows shouldBe listOf(listOf("a", "b", "c"), listOf("d", "e", "f"))
}
"open suspending method (with file argument)" {
val file = readTestDataFile("simple.csv")
val rows = csvReader().openAsync(file) {
val row1 = readNext()
val row2 = readNext()
listOf(row1, row2)
}
rows shouldBe listOf(listOf("a", "b", "c"), listOf("d", "e", "f"))
}
"open suspending method (with InputStream argument)" {
val fileStream = readTestDataFile("simple.csv").inputStream()
val rows = csvReader().openAsync(fileStream) {
val row1 = readNext()
val row2 = readNext()
listOf(row1, row2)
}
rows shouldBe listOf(listOf("a", "b", "c"), listOf("d", "e", "f"))
}
"validate test as flow" {
val fileStream = readTestDataFile("simple.csv").inputStream()
val rows = mutableListOf<List<String>>()
csvReader().openAsync(fileStream) {
readAllAsSequence().asFlow().collect {
rows.add(it)
}
}
rows shouldBe listOf(listOf("a", "b", "c"), listOf("d", "e", "f"))
}
}
}
}

Expand Down

0 comments on commit 15e0ea3

Please sign in to comment.