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

Use String instead of ExactError #25

Open
wants to merge 2 commits 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
53 changes: 43 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ Exact allows automatically projecting smart-constructors on a `Companion Object`
example easily create a `NotBlankString` type that is a `String` that is not blank, leveraging
the Arrow's `Raise` DSL to `ensure` the value is not blank.

```kotlin
<!--- INCLUDE
import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

-->
```kotlin
@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankString {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankString(raw)
}
Expand All @@ -45,12 +45,46 @@ The output of the above program is:

```text
Either.Right(NotBlankString(value=Hello))
Either.Left(ExactError(message=Failed condition.))
Either.Left(Failed condition.)
```

<!--- KNIT example-readme-01.kt -->
<!--- TEST -->

By default, if no error message is provided it'll use `Failed condition.`,
but just like `require` from the Kotlin Standard Library you can provide your own error message.

<!--- INCLUDE
import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.core.raise.ensure
import kotlin.jvm.JvmInline
-->
```kotlin
@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank()) { "String must not be blank." }
return NotBlankString(raw)
}
}
}

fun example() {
println(NotBlankString.from(""))
}
```

The output of the above program is:

```text
Either.Left(String must not be blank.)
```

<!--- KNIT example-readme-02.kt -->
<!--- TEST -->

You can also define `Exact` by using Kotlin delegation.
<!--- INCLUDE
import arrow.exact.Exact
Expand All @@ -66,22 +100,21 @@ value class NotBlankString private constructor(val value: String) {
})
}
```
<!--- KNIT example-readme-02.kt -->
<!--- KNIT example-readme-03.kt -->

You can define a second type `NotBlankTrimmedString` that is a `NotBlankString` that is also
trimmed. `ensureExact` allows us to compose `Exact` instances and easily
reuse the `NotBlankString` type.
<!--- INCLUDE
import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankString {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankString(raw)
}
Expand All @@ -93,12 +126,12 @@ value class NotBlankString private constructor(val value: String) {
@JvmInline
value class NotBlankTrimmedString private constructor(val value: String) {
companion object : Exact<String, NotBlankTrimmedString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankTrimmedString {
override fun Raise<String>.spec(raw: String): NotBlankTrimmedString {
ensure(raw, NotBlankString)
return NotBlankTrimmedString(raw.trim())
}
}
}
```

<!--- KNIT example-readme-03.kt -->
<!--- KNIT example-readme-04.kt -->
3 changes: 1 addition & 2 deletions guide/src/commonMain/kotlin/examples/example-exact-01.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package arrow.exact.knit.example.exampleExact01

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankString {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankString(raw)
}
Expand Down
17 changes: 12 additions & 5 deletions guide/src/commonMain/kotlin/examples/example-exact-02.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// This file was automatically generated from Exact.kt by Knit tool. Do not edit.
package arrow.exact.knit.example.exampleExact02

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ensure
import arrow.core.raise.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> by Exact({
ensure(it.isNotBlank())
NotBlankString(it)
})
companion object : Exact<String, NotBlankString> {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank()) { "String must not be blank." }
return NotBlankString(raw)
}
}
}

fun example() {
println(NotBlankString.from(""))
}
23 changes: 5 additions & 18 deletions guide/src/commonMain/kotlin/examples/example-exact-03.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
// This file was automatically generated from Exact.kt by Knit tool. Do not edit.
package arrow.exact.knit.example.exampleExact03

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankString(raw)
}
}
}

@JvmInline
value class NotBlankTrimmedString private constructor(val value: String) {
companion object : Exact<String, NotBlankTrimmedString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankTrimmedString {
ensure(raw, NotBlankString)
return NotBlankTrimmedString(raw.trim())
}
}
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> by Exact({
ensure(it.isNotBlank())
NotBlankString(it)
})
}
32 changes: 9 additions & 23 deletions guide/src/commonMain/kotlin/examples/example-exact-04.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,25 @@
package arrow.exact.knit.example.exampleExact04

import arrow.core.raise.Raise
import arrow.core.raise.ensure
import arrow.exact.Exact
import arrow.exact.ExactEither
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankTrimmedString private constructor(val value: String) {
companion object : Exact<String, NotBlankTrimmedString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankTrimmedString {
class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankTrimmedString(raw.trim())
return NotBlankString(raw)
}
}
}

sealed interface UsernameError {
object Invalid : UsernameError
data class Offensive(val username: String) : UsernameError
}

@JvmInline
value class Username private constructor(val value: String) {
companion object : ExactEither<UsernameError, String, Username> {
override fun Raise<UsernameError>.spec(raw: String): Username {
val username =
ensure(raw, NotBlankTrimmedString) {
UsernameError.Invalid
}.value
ensure(username.length < 100) { UsernameError.Invalid }
ensure(username !in listOf("offensive")) { UsernameError.Offensive(username) }
return Username(username)
value class NotBlankTrimmedString private constructor(val value: String) {
companion object : Exact<String, NotBlankTrimmedString> {
override fun Raise<String>.spec(raw: String): NotBlankTrimmedString {
ensure(raw, NotBlankString)
return NotBlankTrimmedString(raw.trim())
}
}
}
39 changes: 39 additions & 0 deletions guide/src/commonMain/kotlin/examples/example-exact-05.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// This file was automatically generated from Exact.kt by Knit tool. Do not edit.
package arrow.exact.knit.example.exampleExact05

import arrow.core.raise.Raise
import arrow.core.raise.ensure
import arrow.exact.Exact
import arrow.exact.ExactEither
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankTrimmedString private constructor(val value: String) {
companion object : Exact<String, NotBlankTrimmedString> {
override fun Raise<String>.spec(raw: String): NotBlankTrimmedString {
ensure(raw.isNotBlank())
return NotBlankTrimmedString(raw.trim())
}
}
}

sealed interface UsernameError {
object Invalid : UsernameError
data class Offensive(val username: String) : UsernameError
}

@JvmInline
value class Username private constructor(val value: String) {
companion object : ExactEither<UsernameError, String, Username> {
override fun Raise<UsernameError>.spec(raw: String): Username {
val username =
ensure(raw, NotBlankTrimmedString) {
UsernameError.Invalid
}.value
ensure(username.length < 100) { UsernameError.Invalid }
ensure(username !in listOf("offensive")) { UsernameError.Offensive(username) }
return Username(username)
}
}
}
3 changes: 1 addition & 2 deletions guide/src/commonMain/kotlin/examples/example-readme-01.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package arrow.exact.knit.example.exampleReadme01

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankString {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankString(raw)
}
Expand Down
19 changes: 13 additions & 6 deletions guide/src/commonMain/kotlin/examples/example-readme-02.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// This file was automatically generated from README.md by Knit tool. Do not edit.
package arrow.exact.knit.example.exampleReadme02

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ensure
import arrow.core.raise.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> by Exact({
ensure(it.isNotBlank())
NotBlankString(it)
})
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank()) { "String must not be blank." }
return NotBlankString(raw)
}
}
}

fun example() {
println(NotBlankString.from(""))
}
22 changes: 4 additions & 18 deletions guide/src/commonMain/kotlin/examples/example-readme-03.kt
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
// This file was automatically generated from README.md by Knit tool. Do not edit.
package arrow.exact.knit.example.exampleReadme03

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ExactError
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankString(raw)
}
}
}

@JvmInline
value class NotBlankTrimmedString private constructor(val value: String) {
companion object : Exact<String, NotBlankTrimmedString> {
override fun Raise<ExactError>.spec(raw: String): NotBlankTrimmedString {
ensure(raw, NotBlankString)
return NotBlankTrimmedString(raw.trim())
}
}
companion object : Exact<String, NotBlankString> by Exact({
ensure(it.isNotBlank())
NotBlankString(it)
})
}
27 changes: 27 additions & 0 deletions guide/src/commonMain/kotlin/examples/example-readme-04.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// This file was automatically generated from README.md by Knit tool. Do not edit.
package arrow.exact.knit.example.exampleReadme04

import arrow.core.raise.Raise
import arrow.exact.Exact
import arrow.exact.ensure
import kotlin.jvm.JvmInline

@JvmInline
value class NotBlankString private constructor(val value: String) {
companion object : Exact<String, NotBlankString> {
override fun Raise<String>.spec(raw: String): NotBlankString {
ensure(raw.isNotBlank())
return NotBlankString(raw)
}
}
}

@JvmInline
value class NotBlankTrimmedString private constructor(val value: String) {
companion object : Exact<String, NotBlankTrimmedString> {
override fun Raise<String>.spec(raw: String): NotBlankTrimmedString {
ensure(raw, NotBlankString)
return NotBlankTrimmedString(raw.trim())
}
}
}
9 changes: 8 additions & 1 deletion guide/src/jvmTest/kotlin/examples/spec/ExactExampleSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ class ExactExampleSpec : StringSpec({
captureOutput("ExampleExact01") { arrow.exact.knit.example.exampleExact01.example() }
.verifyOutputLines(
"Either.Right(NotBlankString(value=Hello))",
"Either.Left(ExactError(message=Failed condition.))"
"Either.Left(Failed condition.)"
)
}

"ExampleExact02" {
captureOutput("ExampleExact02") { arrow.exact.knit.example.exampleExact02.example() }
.verifyOutputLines(
"Either.Left(String must not be blank.)"
)
}

Expand Down
Loading