Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added lambda processing instead of returning a list #215

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ val someApi = TODO("Not a real API object")
// Returns a playlist in the M3U format
val m3uContent: String = someApi.getPlaylist("Best of Willy Astor")
val entries: List<M3uEntry> = M3uParser.parse(m3uContent)


// You can also use a lambda for processing each entry instead of returning a List
val m3uFile = Paths.get("myplaylist.m3u")
M3uParser.parse(m3uFile) { entry ->
println(entry->name)
}

```

### Nested playlists
Expand Down
5 changes: 5 additions & 0 deletions buildConfig/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ comments:
active: true
UndocumentedPublicFunction:
active: true
complexity:
TooManyFunctions:
ignoreOverridden: true
thresholdInClasses: 15
thresholdInObjects: 15
81 changes: 73 additions & 8 deletions src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,28 @@
@JvmOverloads
fun parse(m3uFile: Path, charset: Charset = Charsets.UTF_8): List<M3uEntry> {
require(Files.isRegularFile(m3uFile)) { "$m3uFile is not a file" }
return parse(Files.lines(m3uFile, charset).asSequence(), m3uFile.parent)
val entries = mutableListOf<M3uEntry>()
parse(Files.lines(m3uFile, charset).asSequence(), m3uFile.parent) { entry -> entries.add(entry) }
return entries
}

Check warning on line 61 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L61

Added line #L61 was not covered by tests

/**
* Parses the specified file.
*
* Comment lines and lines which can't be parsed are dropped.
*
* @param m3uFile a path to an .m3u file
* @param charset the file's encoding, defaults to UTF-8
* @param processFun a Unit to process each m3uentry
* @throws IOException if file can't be read
* @throws IllegalArgumentException if file is not a regular file
*/
@Throws(IOException::class)

Check warning on line 74 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L74

Added line #L74 was not covered by tests
@JvmStatic
@JvmOverloads
fun parse(m3uFile: Path, charset: Charset = Charsets.UTF_8, processFun: (M3uEntry) -> Unit) {

Check warning on line 77 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L77

Added line #L77 was not covered by tests
require(Files.isRegularFile(m3uFile)) { "$m3uFile is not a file" }
parse(Files.lines(m3uFile, charset).asSequence(), m3uFile.parent, processFun)

Check warning on line 79 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L79

Added line #L79 was not covered by tests
}

/**
Expand All @@ -70,7 +91,30 @@
@JvmStatic
@JvmOverloads
fun parse(m3uContentReader: InputStreamReader, baseDir: Path? = null): List<M3uEntry> {
return m3uContentReader.buffered().useLines { parse(it, baseDir) }
val entries = mutableListOf<M3uEntry>()
m3uContentReader.buffered().useLines {
parse(it, baseDir) {
entry ->
entries.add(entry)
}
}
return entries
}

Check warning on line 102 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L102

Added line #L102 was not covered by tests

/**
* Parses the [InputStream] from the specified reader.
*
* Comment lines and lines which can't be parsed are dropped.
*
* @param m3uContentReader a reader reading the content of an `.m3u` file
* @param baseDir a base dir for resolving relative paths
* @param processFun a Unit to process each m3uentry
*
*/
@JvmStatic
@JvmOverloads
fun parse(m3uContentReader: InputStreamReader, baseDir: Path? = null, processFun: (M3uEntry) -> Unit) {
return m3uContentReader.buffered().useLines { parse(it, baseDir, processFun) }
}

/**
Expand All @@ -85,7 +129,28 @@
@JvmStatic
@JvmOverloads
fun parse(m3uContent: String, baseDir: Path? = null): List<M3uEntry> {
return parse(m3uContent.lineSequence(), baseDir)
val entries = mutableListOf<M3uEntry>()
parse(m3uContent, baseDir) {
entry ->
entries.add(entry)
}
return entries
}

Check warning on line 138 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L138

Added line #L138 was not covered by tests

/**
* Parses the specified content of a `.m3u` file.
*
* Comment lines and lines which can't be parsed are dropped.
*
* @param m3uContent the content of a `.m3u` file
* @param baseDir a base dir for resolving relative paths
* @param processFun a Unit to process each m3uentry
*
*/
@JvmStatic

Check warning on line 150 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L150

Added line #L150 was not covered by tests
@JvmOverloads
fun parse(m3uContent: String, baseDir: Path? = null, processFun: (M3uEntry) -> Unit) {

Check warning on line 152 in src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/net/bjoernpetersen/m3u/M3uParser.kt#L152

Added line #L152 was not covered by tests
parse(m3uContent.lineSequence(), baseDir, processFun)
}

/**
Expand All @@ -106,14 +171,14 @@
}

@Suppress("NestedBlockDepth", "ReturnCount")
private fun parse(lines: Sequence<String>, baseDir: Path?): List<M3uEntry> {
private fun parse(lines: Sequence<String>, baseDir: Path?, processFun: (M3uEntry) -> Unit) {
val filtered = lines
.filterNot { it.isBlank() }
.map { it.trimEnd() }
.dropWhile { it == EXTENDED_HEADER }
.iterator()

if (!filtered.hasNext()) return emptyList()
if (!filtered.hasNext()) return

val entries = LinkedList<M3uEntry>()

Expand All @@ -134,7 +199,7 @@
if (filtered.hasNext()) {
currentLine = filtered.next()
} else {
return entries
return
}
}

Expand All @@ -149,13 +214,13 @@
match = null

if (entry != null) {
entries.add(entry)
processFun(entry)
} else {
logger.warn { "Ignored line $currentLine" }
}
}

return entries
return
}

private fun parseSimple(location: String, baseDir: Path?): M3uEntry? {
Expand Down
30 changes: 30 additions & 0 deletions src/test/kotlin/net/bjoernpetersen/m3u/M3uParserExampleTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,36 @@ class M3uParserExampleTest {
assertEquals("https://i.imgur.com/CnIVW9o.jpg", withLogo.metadata.logo)
}

@TestFactory
fun testWikiLambda(): List<DynamicTest> {
return listOf(
"wiki_mixed.m3u",
"wiki_mixed_empty_lines.m3u",
).map { name ->
dynamicTest(name) {
val entries = mutableListOf<M3uEntry>()
M3uParser.parse(javaClass.getResourceAsStream(name).reader()) { entry ->
entries.add(entry)
}
assertEquals(7, entries.size)

val simple = listOf(entries[1], entries[4])
simple.forEach {
assertThat(it)
.returns(null, M3uEntry::duration)
.returns(null, M3uEntry::title)
}

val extended = entries.filterNot { it in simple }
extended.forEach { entry ->
assertThat(entry)
.matches { it.duration != null }
.matches { it.title != null }
}
}
}
}

@Test
fun testRecursiveResolution() {
val files = listOf("rec_1.m3u", "rec_2.m3u", "rec_3.m3u")
Expand Down
Loading