Merge pull request #33 from kemitix/single-consumers-for-maybe-and-result
Single consumers for maybe and result
This commit is contained in:
commit
c8bdd77ac9
9 changed files with 136 additions and 2 deletions
|
@ -1,6 +1,13 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.9.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Add `Maybe.ifNothing(Runnable)`
|
||||||
|
* Add `Result.recover(Function)`
|
||||||
|
* Add `Result.onError(Consumer)`
|
||||||
|
|
||||||
0.8.0
|
0.8.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,11 @@ final class Just<T> implements Maybe<T> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ifNothing(final Runnable runnable) {
|
||||||
|
// ignore - not nothing
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void orElseThrow(final Supplier<Exception> e) {
|
public void orElseThrow(final Supplier<Exception> e) {
|
||||||
// do not throw
|
// do not throw
|
||||||
|
|
|
@ -142,4 +142,11 @@ public interface Maybe<T> extends Functor<T, Maybe<?>> {
|
||||||
* @return this Maybe
|
* @return this Maybe
|
||||||
*/
|
*/
|
||||||
Maybe<T> peek(Consumer<T> consumer);
|
Maybe<T> peek(Consumer<T> consumer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the runnable if the Maybe is a Nothing, otherwise do nothing.
|
||||||
|
*
|
||||||
|
* @param runnable the runnable to call if this is a Nothing
|
||||||
|
*/
|
||||||
|
void ifNothing(Runnable runnable);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,11 @@ final class Nothing<T> implements Maybe<T> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ifNothing(final Runnable runnable) {
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void orElseThrow(final Supplier<Exception> e) throws Exception {
|
public void orElseThrow(final Supplier<Exception> e) throws Exception {
|
||||||
throw e.get();
|
throw e.get();
|
||||||
|
|
|
@ -80,6 +80,16 @@ class Err<T> implements Result<T> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<T> recover(final Function<Throwable, Result<T>> f) {
|
||||||
|
return f.apply(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Consumer<Throwable> errorConsumer) {
|
||||||
|
errorConsumer.accept(error);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object other) {
|
public boolean equals(final Object other) {
|
||||||
return other instanceof Err && Objects.equals(error, ((Err) other).error);
|
return other instanceof Err && Objects.equals(error, ((Err) other).error);
|
||||||
|
|
|
@ -94,7 +94,7 @@ public interface Result<T> extends Functor<T, Result<?>> {
|
||||||
* Creates a Result from the Maybe, where the Result will be an error if the Maybe is Nothing.
|
* Creates a Result from the Maybe, where the Result will be an error if the Maybe is Nothing.
|
||||||
*
|
*
|
||||||
* @param result the Result the might contain the value of the Result
|
* @param result the Result the might contain the value of the Result
|
||||||
* @param <T> the type of the Maybe and the Result
|
* @param <T> the type of the Maybe and the Result
|
||||||
* @return a Result containing the value of the Maybe when it is a Just, or the error when it is Nothing
|
* @return a Result containing the value of the Maybe when it is a Just, or the error when it is Nothing
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("illegalcatch")
|
@SuppressWarnings("illegalcatch")
|
||||||
|
@ -108,8 +108,9 @@ public interface Result<T> extends Functor<T, Result<?>> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swaps the inner Result of a Maybe, so that a Result is on the outside.
|
* Swaps the inner Result of a Maybe, so that a Result is on the outside.
|
||||||
|
*
|
||||||
* @param maybeResult the Maybe the contains a Result
|
* @param maybeResult the Maybe the contains a Result
|
||||||
* @param <T> the type of the value that may be in the Result
|
* @param <T> the type of the value that may be in the Result
|
||||||
* @return a Result containing a Maybe, the value in the Maybe was the value in a successful Result within the
|
* @return a Result containing a Maybe, the value in the Maybe was the value in a successful Result within the
|
||||||
* original Maybe. If the original Maybe is Nothing, the Result will contain Nothing. If the original Result was an
|
* original Maybe. If the original Maybe is Nothing, the Result will contain Nothing. If the original Result was an
|
||||||
* error, then the Result will also be an error.
|
* error, then the Result will also be an error.
|
||||||
|
@ -177,4 +178,22 @@ public interface Result<T> extends Functor<T, Result<?>> {
|
||||||
* @return this Result
|
* @return this Result
|
||||||
*/
|
*/
|
||||||
Result<T> peek(Consumer<T> consumer);
|
Result<T> peek(Consumer<T> consumer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a way to attempt to recover from an error state.
|
||||||
|
*
|
||||||
|
* @param f the function to recover from the error
|
||||||
|
* @return a new Result, either a Success, or if recovery is not possible an other Err.
|
||||||
|
*/
|
||||||
|
Result<T> recover(Function<Throwable, Result<T>> f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handler for error states.
|
||||||
|
*
|
||||||
|
* <p>When this is an error then tne Consumer will be supplier with the error. When this is a success, then nothing
|
||||||
|
* happens.</p>
|
||||||
|
*
|
||||||
|
* @param errorConsumer the consumer to handle the error
|
||||||
|
*/
|
||||||
|
void onError(Consumer<Throwable> errorConsumer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,16 @@ class Success<T> implements Result<T> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<T> recover(final Function<Throwable, Result<T>> f) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(final Consumer<Throwable> errorConsumer) {
|
||||||
|
// do nothing - this is not an error
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object other) {
|
public boolean equals(final Object other) {
|
||||||
return other instanceof Success && Objects.equals(value, ((Success) other).value);
|
return other instanceof Success && Objects.equals(value, ((Success) other).value);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
@ -171,4 +172,26 @@ public class MaybeTest implements WithAssertions {
|
||||||
assertThat(result.toOptional()).isEmpty();
|
assertThat(result.toOptional()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void just_ifNothing_isIgnored() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> just = Maybe.just(1);
|
||||||
|
final AtomicBoolean capture = new AtomicBoolean(false);
|
||||||
|
//when
|
||||||
|
just.ifNothing(() -> capture.set(true));
|
||||||
|
//then
|
||||||
|
assertThat(capture).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nothing_ifNothing_isCalled() {
|
||||||
|
//given
|
||||||
|
final Maybe<Integer> nothing = Maybe.nothing();
|
||||||
|
final AtomicBoolean capture = new AtomicBoolean(false);
|
||||||
|
//when
|
||||||
|
nothing.ifNothing(() -> capture.set(true));
|
||||||
|
//then
|
||||||
|
assertThat(capture).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,6 +452,54 @@ public class ResultTest implements WithAssertions {
|
||||||
assertThat(peeked).isSameAs(result);
|
assertThat(peeked).isSameAs(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void success_whenOnError_thenIgnore() {
|
||||||
|
//given
|
||||||
|
final Result<Integer> ok = Result.ok(1);
|
||||||
|
//when
|
||||||
|
ok.onError(e -> fail("not an error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void error_whenOnError_thenConsume() {
|
||||||
|
//given
|
||||||
|
final RuntimeException exception = new RuntimeException();
|
||||||
|
final Result<Integer> error = Result.error(exception);
|
||||||
|
final AtomicReference<Throwable> capture = new AtomicReference<>();
|
||||||
|
//when
|
||||||
|
error.onError(capture::set);
|
||||||
|
//then
|
||||||
|
assertThat(capture).hasValue(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void success_whenRecover_thenNoChange() {
|
||||||
|
//given
|
||||||
|
final Result<Integer> ok = Result.ok(1);
|
||||||
|
//when
|
||||||
|
final Result<Integer> recovered = ok.recover(e -> Result.ok(2));
|
||||||
|
//then
|
||||||
|
recovered.peek(v -> assertThat(v).isEqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void error_whenRecover_thenSuccess() {
|
||||||
|
//given
|
||||||
|
final Result<Integer> error = Result.error(new RuntimeException());
|
||||||
|
//when
|
||||||
|
final Result<Integer> recovered = error.recover(e -> Result.ok(2));
|
||||||
|
//then
|
||||||
|
recovered.peek(v -> assertThat(v).isEqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void error_whenRecoverFails_thenUpdatedError() {
|
||||||
|
//given
|
||||||
|
final Result<Integer> error = Result.error(new RuntimeException("original"));
|
||||||
|
//when
|
||||||
|
final Result<Integer> recovered = error.recover(e -> Result.error(new RuntimeException("updated")));
|
||||||
|
//then
|
||||||
|
recovered.onError(e -> assertThat(e).hasMessage("updated"));
|
||||||
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
private static class UseCase {
|
private static class UseCase {
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue