diff --git a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/strings/strings.kt b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/strings/strings.kt index f026212..ee2f7cf 100644 --- a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/strings/strings.kt +++ b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/strings/strings.kt @@ -1,5 +1,6 @@ package com.sksamuel.tribune.core.strings +import arrow.core.Either import arrow.core.leftNel import arrow.core.right import com.sksamuel.tribune.core.Parser @@ -41,16 +42,23 @@ fun Parser.notNullOrBlank(ifError: () -> E): Parser String [Parser] to reject blank strings, + * Wraps an existing I -> String? [Parser] to reject blank strings, * with the error message generated by the given function [ifBlank]. * + * Note: This parser accepts null strings as valid. If you wish to reject null inputs as well, + * then use nullOrNotBlank. + * * @param ifBlank the error generating function * * @return invalid if the input string contains only whitespace, otherwise valid */ -fun Parser.notBlank(ifBlank: () -> E): Parser { +fun Parser.notBlank(ifBlank: () -> E): Parser { return flatMap { - if (it.isBlank()) ifBlank().leftNel() else it.right() + when { + it == null -> Either.Right(null) + it.isBlank() -> ifBlank().leftNel() + else -> it.right() + } } } diff --git a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ParserTest.kt b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ParserTest.kt index 9037efe..8e0525e 100644 --- a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ParserTest.kt +++ b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ParserTest.kt @@ -5,6 +5,7 @@ import arrow.core.leftNel import arrow.core.right import com.sksamuel.tribune.core.strings.minlen import com.sksamuel.tribune.core.strings.notBlank +import com.sksamuel.tribune.core.strings.notNullOrBlank import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe @@ -82,7 +83,7 @@ class ValidatedTest : FunSpec() { val nameParser: Parser = Parser() .map { it.name } - .notBlank { "Name cannot be blank" } + .notNullOrBlank { "Name cannot be blank" } .minlen(6) { "Name must have 6 characters" } .map { ValidName(it) } diff --git a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ZipTest.kt b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ZipTest.kt index 6f8e8cf..8c669ac 100644 --- a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ZipTest.kt +++ b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ZipTest.kt @@ -16,16 +16,16 @@ class ZipTest : FunSpec() { val p2 = Parser.from().notNullOrBlank { "bar" } val p = Parser.zip(p1, p2) p.parse(null) shouldBe nonEmptyListOf("foo", "bar").left() -// p.parse("a") shouldBe nonEmptyListOf("Must have length > 2").left() -// p.parse("ab") shouldBe Pair("ab", "ab").right() + p.parse("a") shouldBe nonEmptyListOf("Must have length > 2").left() + p.parse("ab") shouldBe Pair("ab", "ab").right() } - xtest("zip 3") { + test("zip 3") { val p1 = Parser.from().notNullOrBlank { "foo" }.minlen(2) { "Must have length > 2" } val p2 = Parser.from().notNullOrBlank { "bar" } val p3 = Parser.from().notNullOrBlank { "baz" } val p = Parser.zip(p1, p2, p3) -// p.parse(null) shouldBe nonEmptyListOf("foo", "bar", "baz").left() + p.parse(null) shouldBe nonEmptyListOf("foo", "bar", "baz").left() p.parse("a") shouldBe nonEmptyListOf("Must have length > 2").left() p.parse("ab") shouldBe Triple("ab", "ab", "ab").right() }