diff --git a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/doubles/doubles.kt b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/doubles/doubles.kt index 4479511..9114ad7 100644 --- a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/doubles/doubles.kt +++ b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/doubles/doubles.kt @@ -5,7 +5,6 @@ import arrow.core.right import com.sksamuel.tribune.core.Parser import com.sksamuel.tribune.core.filter import com.sksamuel.tribune.core.flatMap -import com.sksamuel.tribune.core.map /** * Extends a [Parser] of output type string to parse that string into a double. @@ -44,10 +43,3 @@ fun Parser.inrange( flatMap { if (it in range) it.right() else ifError(it).leftNel() } - -fun Parser.nullIf(fn: (Double) -> Boolean): Parser = - this.map { if (fn(it)) null else it } - -@JvmName("nullIfNullable") -fun Parser.nullIf(fn: (Double) -> Boolean): Parser = - this.map { if (it == null || fn(it)) null else it } diff --git a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/filter.kt b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/filter.kt index bd8500a..f6fa80f 100644 --- a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/filter.kt +++ b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/filter.kt @@ -17,6 +17,36 @@ import arrow.core.right * * @return a parser which rejects input based on the result of predicate [p] */ -fun Parser.filter(p: (A) -> Boolean, ifFalse: (A) -> E): Parser { +fun Parser.filter(p: (O) -> Boolean, ifFalse: (O) -> E): Parser { return flatMap { if (p(it)) it.right() else ifFalse(it).leftNel() } } + +/** + * Returns a [Parser] that produces a null if the input value fails to pass the predicate [p]. + * + * In other words, if the underlying parser returns a valid output, that output is then + * passed to the given predicate, and if that predicate returns false, a null is produced. + * + * @param p the predicate to test input + * + * @return a parser which rejects input based on the result of predicate [p] + */ +fun Parser.nullIf(fn: (O) -> Boolean): Parser = + this.map { if (fn(it)) null else it } + +/** + * Returns a [Parser] that produces a null if the input value fails to pass the predicate [p]. + * + * In other words, if the underlying parser returns a valid output, that output is then + * passed to the given predicate, and if that predicate returns false, a null is produced. + * + * This variant of [nullIf] allows the output of the preceeding parser to already be null. + * + * @param p the predicate to test input + * + * @return a parser which rejects input based on the result of predicate [p] + */ +@JvmName("nullIfNullable") +fun Parser.nullIf(fn: (O) -> Boolean): Parser = + this.map { if (it == null || fn(it)) null else it } + diff --git a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/floats/floats.kt b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/floats/floats.kt index b4dd833..f1637d3 100644 --- a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/floats/floats.kt +++ b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/floats/floats.kt @@ -4,7 +4,6 @@ import arrow.core.leftNel import arrow.core.right import com.sksamuel.tribune.core.Parser import com.sksamuel.tribune.core.flatMap -import com.sksamuel.tribune.core.map /** * Extends a [Parser] of output type string to parse that string into a double. @@ -19,10 +18,3 @@ fun Parser.float(ifError: (String) -> E): Parser Parser.nullIf(fn: (Float) -> Boolean): Parser = - this.map { if (fn(it)) null else it } - -@JvmName("nullIfNullable") -fun Parser.nullIf(fn: (Float) -> Boolean): Parser = - this.map { if (it == null || fn(it)) null else it } diff --git a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/ints/ints.kt b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/ints/ints.kt index c6a9089..911633e 100644 --- a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/ints/ints.kt +++ b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/ints/ints.kt @@ -6,7 +6,6 @@ import arrow.core.right import com.sksamuel.tribune.core.Parser import com.sksamuel.tribune.core.filter import com.sksamuel.tribune.core.flatMap -import com.sksamuel.tribune.core.map /** * Chains a [Parser] to convert String -> Int. @@ -61,10 +60,3 @@ fun Parser.max(min: Int, ifError: (Int) -> E): Parser= min) it.right() else ifError(it).leftNel() } - -fun Parser.nullIf(fn: (Int) -> Boolean): Parser = - this.map { if (fn(it)) null else it } - -@JvmName("nullIfNullable") -fun Parser.nullIf(fn: (Int) -> Boolean): Parser = - this.map { if (it == null || fn(it)) null else it } diff --git a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/longs/longs.kt b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/longs/longs.kt index 321f896..dfe651c 100644 --- a/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/longs/longs.kt +++ b/tribune-core/src/main/kotlin/com/sksamuel/tribune/core/longs/longs.kt @@ -47,10 +47,3 @@ fun Parser.max(min: Long, ifError: (Long) -> E): Parser= min) it.right() else ifError(it).leftNel() } - -fun Parser.nullIf(fn: (Long) -> Boolean): Parser = - this.map { if (fn(it)) null else it } - -@JvmName("nullIfNullable") -fun Parser.nullIf(fn: (Long) -> Boolean): Parser = - this.map { if (it == null || fn(it)) null else it } 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 71227a2..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 @@ -77,10 +77,3 @@ fun Parser.nullOrNotBlank(ifBlank: () -> E): Parser Parser.nullIf(fn: (String) -> Boolean): Parser = - this.map { if (fn(it)) null else it } - -@JvmName("nullIfNullable") -fun Parser.nullIf(fn: (String) -> Boolean): Parser = - this.map { if (it == null || fn(it)) null else it } diff --git a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ComposeTest.kt b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ComposeTest.kt index 921d562..0ea310a 100644 --- a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ComposeTest.kt +++ b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/ComposeTest.kt @@ -1,6 +1,5 @@ package com.sksamuel.tribune.core -import com.sksamuel.tribune.core.doubles.nullIf import com.sksamuel.tribune.core.ints.min import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe @@ -39,6 +38,8 @@ class ComposeTest : FunSpec() { } } +val q = Parsers.nullableString.nullIf { it.length > 3 } + val weightParser = Parsers.nullableDouble .nullIf { it <= 0.0 } .mapIfNotNull { ParsedWeight(it) } diff --git a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/NullTest.kt b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/NullTest.kt index 11ed6d8..08600b7 100644 --- a/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/NullTest.kt +++ b/tribune-core/src/test/kotlin/com/sksamuel/tribune/core/NullTest.kt @@ -3,7 +3,6 @@ package com.sksamuel.tribune.core import arrow.core.Either import arrow.core.leftNel import arrow.core.right -import com.sksamuel.tribune.core.strings.nullIf import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe @@ -15,6 +14,19 @@ class NullTest : FunSpec() { p.parse("abc") shouldBe "wibble".right() } + test("nullIf on O -> A?") { + val p = Parser().nullIf { "foo" == it } + p.parse("foo") shouldBe null.right() + p.parse("bar") shouldBe "bar".right() + } + + test("nullIf on O? -> A?") { + val p = Parser().nullIf { "foo" == it } + p.parse(null) shouldBe null.right() + p.parse("foo") shouldBe null.right() + p.parse("bar") shouldBe "bar".right() + } + test("withDefault on I? -> A?") { val p = Parser().withDefault { "wibble" } p.parse("abc") shouldBe "abc".right()