Add andThen(Function)

This commit is contained in:
Paul Campbell 2018-07-08 19:46:45 +01:00
parent c8bdd77ac9
commit fb6b65e6de
5 changed files with 93 additions and 2 deletions

View file

@ -1,6 +1,11 @@
CHANGELOG CHANGELOG
========= =========
0.10.0
------
* Add `andThen(Function)`
0.9.0 0.9.0
----- -----

View file

@ -25,6 +25,7 @@ import lombok.RequiredArgsConstructor;
import net.kemitix.mon.maybe.Maybe; import net.kemitix.mon.maybe.Maybe;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -90,6 +91,11 @@ class Err<T> implements Result<T> {
errorConsumer.accept(error); errorConsumer.accept(error);
} }
@Override
public <R> Result<R> andThen(final Function<T, Callable<R>> f) {
return Result.error(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);

View file

@ -196,4 +196,25 @@ public interface Result<T> extends Functor<T, Result<?>> {
* @param errorConsumer the consumer to handle the error * @param errorConsumer the consumer to handle the error
*/ */
void onError(Consumer<Throwable> errorConsumer); void onError(Consumer<Throwable> errorConsumer);
/**
* Maps a Success Result to another Result using a Callable that is able to throw a checked exception.
*
* <p>Combination of {@link #flatMap(Function)} and {@link #of(Callable)}.</p>
*
* <p>Syntax is:</p>
* <pre><code>
* Integer doSomething() {...}
* String doSomethingElse(final Integer value) {...}
* Result&lt;String&gt; r = Result.of(() -&gt; doSomething())
* .andThen(value -&gt; () -&gt; doSomethingElse(value));
* </code></pre>
*
* <p>When the Result is an Err, then the original error is carried over and the Callable is never called.</p>
*
* @param f the function to map the Success value to the Callable
* @param <R> the type of the final Result
* @return a new Result
*/
<R> Result<R> andThen(Function<T, Callable<R>> f);
} }

View file

@ -25,6 +25,7 @@ import lombok.RequiredArgsConstructor;
import net.kemitix.mon.maybe.Maybe; import net.kemitix.mon.maybe.Maybe;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -94,6 +95,11 @@ class Success<T> implements Result<T> {
// do nothing - this is not an error // do nothing - this is not an error
} }
@Override
public <R> Result<R> andThen(final Function<T, Callable<R>> f) {
return Result.of(f.apply(value));
}
@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);

View file

@ -452,14 +452,16 @@ public class ResultTest implements WithAssertions {
assertThat(peeked).isSameAs(result); assertThat(peeked).isSameAs(result);
} }
@Test public void success_whenOnError_thenIgnore() { @Test
public void success_whenOnError_thenIgnore() {
//given //given
final Result<Integer> ok = Result.ok(1); final Result<Integer> ok = Result.ok(1);
//when //when
ok.onError(e -> fail("not an error")); ok.onError(e -> fail("not an error"));
} }
@Test public void error_whenOnError_thenConsume() { @Test
public void error_whenOnError_thenConsume() {
//given //given
final RuntimeException exception = new RuntimeException(); final RuntimeException exception = new RuntimeException();
final Result<Integer> error = Result.error(exception); final Result<Integer> error = Result.error(exception);
@ -500,6 +502,57 @@ public class ResultTest implements WithAssertions {
recovered.onError(e -> assertThat(e).hasMessage("updated")); recovered.onError(e -> assertThat(e).hasMessage("updated"));
} }
@Test
public void success_andThenSuccess_thenSuccess() {
//given
final Result<Integer> ok = Result.ok(1);
//when
final Result<String> result = ok.andThen(v -> () -> "success");
//then
assertThat(result.isOkay()).isTrue();
result.peek(v -> assertThat(v).isEqualTo("success"));
}
@Test
public void success_andThenError_thenError() {
//given
final Result<Integer> ok = Result.ok(1);
final RuntimeException exception = new RuntimeException();
//when
final Result<Object> result = ok.andThen(v -> () -> {
throw exception;
});
//then
assertThat(result.isError()).isTrue();
result.onError(e -> assertThat(e).isSameAs(exception));
}
@Test
public void error_andThenSuccess_thenError() {
//given
final RuntimeException exception = new RuntimeException();
final Result<Object> error = Result.error(exception);
//when
final Result<Object> result = error.andThen(v -> () -> "success");
//then
assertThat(result.isError()).isTrue();
result.onError(e -> assertThat(e).isSameAs(exception));
}
@Test
public void error_andThenError_thenError() {
//given
final RuntimeException exception1 = new RuntimeException();
final Result<Object> error = Result.error(exception1);
//when
final Result<Object> result = error.andThen(v -> () -> {
throw new RuntimeException();
});
//then
assertThat(result.isError()).isTrue();
result.onError(e -> assertThat(e).isSameAs(exception1));
}
@RequiredArgsConstructor @RequiredArgsConstructor
private static class UseCase { private static class UseCase {