From 5b09c1b52597051ad319f0c3333c4e4200ce669b Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Thu, 19 Aug 2021 13:46:22 +0100 Subject: [PATCH] Add Reader.map and Reader.andThen methods (#227) --- .../java/net/kemitix/mon/reader/Reader.java | 27 +++++++++++ src/test/java/net/kemitix/mon/ReaderTest.java | 45 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/main/java/net/kemitix/mon/reader/Reader.java b/src/main/java/net/kemitix/mon/reader/Reader.java index 5a9c7a4..4ae091b 100644 --- a/src/main/java/net/kemitix/mon/reader/Reader.java +++ b/src/main/java/net/kemitix/mon/reader/Reader.java @@ -2,6 +2,9 @@ package net.kemitix.mon.reader; import org.apiguardian.api.API; +import java.util.function.BiFunction; +import java.util.function.Function; + /** * Returns a program ready to run upon the supply of a suitable environment. * @@ -20,4 +23,28 @@ public interface Reader { */ R run(E env); + /** + * Applies the function provided to the reader when it is run. + * + * @param f the function, which takes an {@link E} as its only parameter + * @param the type of the functions output + * @return a new Reader to provide the result of the supplied function + */ + @API(status = API.Status.EXPERIMENTAL) + default Reader map(Function f) { + return e -> f.apply(run(e)); + } + + /** + * Applies the function provided to the reader when it is run. + * + * @param f the function, which takes an {@link E} and the previously + * generated value as its two parameters + * @param the type of the functions output + * @return a new Reader to provided the result of the supplied function + */ + @API(status = API.Status.EXPERIMENTAL) + default Reader andThen(BiFunction f) { + return env -> f.apply(env, run(env)); + } } diff --git a/src/test/java/net/kemitix/mon/ReaderTest.java b/src/test/java/net/kemitix/mon/ReaderTest.java index 0cf801f..5313dd0 100644 --- a/src/test/java/net/kemitix/mon/ReaderTest.java +++ b/src/test/java/net/kemitix/mon/ReaderTest.java @@ -5,6 +5,8 @@ import org.assertj.core.api.WithAssertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.concurrent.atomic.AtomicInteger; + public class ReaderTest implements WithAssertions { @@ -30,6 +32,49 @@ public class ReaderTest assertThat(result).isEqualTo(value); } + @Test + @DisplayName("map") + void map() { + //given + AtomicInteger value = new AtomicInteger(123); + Environment env = new Environment() { + @Override + public Integer intValue() { + return value.incrementAndGet(); + } + }; + Reader program = + ((Reader) e -> e.intValue()) + .map(i -> i * 2) + .map(i -> Integer.toString(i)); + //when + String result = program.run(env); + //then + assertThat(result).isEqualTo("248");// (123 + 1) * 2 + } + + @Test + @DisplayName("andThen") + void andThen() { + //given + AtomicInteger value = new AtomicInteger(123); + Environment env = new Environment() { + @Override + public Integer intValue() { + return value.incrementAndGet(); + } + }; + Reader program = + ((Reader) e -> e.intValue()) + .andThen((e, i) -> e.intValue() + (i * 2)) + .andThen((e, i) -> String.format("%.2f", + i.floatValue() / e.intValue())); + //when + String result = program.run(env); + //then + assertThat(result).isEqualTo("2.96");// ((123 * 2) + (123 + 1)) / (123 + 2) + } + private interface Environment { Integer intValue();