Deprecate Result.of in favour of runCatching factory function

Matches Kotlin's stdlib and becomes top-level
This commit is contained in:
Michael Bull 2019-08-24 00:07:27 +01:00
parent a8098db1c7
commit 586b260683
4 changed files with 62 additions and 25 deletions

View File

@ -15,6 +15,7 @@ import com.github.michaelbull.result.map
import com.github.michaelbull.result.mapAll
import com.github.michaelbull.result.mapBoth
import com.github.michaelbull.result.mapError
import com.github.michaelbull.result.runCatching
import com.github.michaelbull.result.toResultOr
import java.sql.SQLTimeoutException
@ -22,7 +23,7 @@ object CustomerService {
private val repository = InMemoryCustomerRepository()
fun getAll(): Result<Collection<Customer>, DomainMessage> {
return Result.of(repository::findAll)
return runCatching(repository::findAll)
.mapError(::exceptionToDomainMessage)
.mapAll(Customer.Companion::from)
}
@ -40,12 +41,12 @@ object CustomerService {
}
private fun updateCustomer(entity: CustomerEntity, old: Customer, new: Customer) =
Result.of { repository.update(entity) }
runCatching { repository.update(entity) }
.map { differenceBetween(old, new) }
.mapError(::exceptionToDomainMessage)
private fun createCustomer(entity: CustomerEntity) =
Result.of { repository.insert(entity) }
runCatching { repository.insert(entity) }
.map { CustomerCreated }
.mapError(::exceptionToDomainMessage)

View File

@ -0,0 +1,53 @@
package com.github.michaelbull.result
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
/**
* Calls the specified function [block] and returns its encapsulated result if
* invocation was successful, catching and encapsulating any thrown exception
* as a failure.
*/
inline fun <V> runCatching(block: () -> V): Result<V, Throwable> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return try {
Ok(block())
} catch (e: Throwable) {
Err(e)
}
}
/**
* Calls the specified function [block] with `this` value as its receiver and
* returns its encapsulated result if invocation was successful, catching and
* encapsulating any thrown exception as a failure.
*/
inline infix fun <T, V> T.runCatching(block: T.() -> V): Result<V, Throwable> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return try {
Ok(block())
} catch (e: Throwable) {
Err(e)
}
}
/**
* Converts a nullable of type [V] to a [Result]. Returns [Ok] if the value is
* non-null, otherwise the supplied [error].
*/
inline infix fun <V, E> V?.toResultOr(error: () -> E): Result<V, E> {
contract {
callsInPlace(error, InvocationKind.AT_MOST_ONCE)
}
return when (this) {
null -> Err(error())
else -> Ok(this)
}
}

View File

@ -1,8 +1,5 @@
package com.github.michaelbull.result
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
/**
* [Result] is a type that represents either success ([Ok]) or failure ([Err]).
*
@ -17,6 +14,7 @@ sealed class Result<out V, out E> {
* Invokes a [function] and wraps it in a [Result], returning an [Err]
* if an [Exception] was thrown, otherwise [Ok].
*/
@Deprecated("Use top-level runCatching instead", ReplaceWith("runCatching(function)"))
inline fun <V> of(function: () -> V): Result<V, Exception> {
return try {
Ok(function.invoke())
@ -36,18 +34,3 @@ data class Ok<out V>(val value: V) : Result<V, Nothing>()
* Represents a failed [Result], containing an [error].
*/
data class Err<out E>(val error: E) : Result<Nothing, E>()
/**
* Converts a nullable of type [V] to a [Result]. Returns [Ok] if the value is
* non-null, otherwise the supplied [error].
*/
inline infix fun <V, E> V?.toResultOr(error: () -> E): Result<V, E> {
contract {
callsInPlace(error, InvocationKind.AT_MOST_ONCE)
}
return when (this) {
null -> Err(error())
else -> Ok(this)
}
}

View File

@ -4,12 +4,12 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertSame
class ResultTest {
class Of {
class FactoryTest {
class RunCatching {
@Test
fun returnsOkIfInvocationSuccessful() {
val callback = { "example" }
val result = Result.of(callback)
val result = runCatching(callback)
assertEquals(
expected = "example",
@ -21,7 +21,7 @@ class ResultTest {
fun returnsErrIfInvocationFails() {
val exception = IllegalArgumentException("throw me")
val callback = { throw exception }
val result = Result.of(callback)
val result = runCatching(callback)
assertSame(
expected = exception,