diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 56bb016..9dda3b6 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip \ No newline at end of file +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip diff --git a/CHANGELOG b/CHANGELOG index bbde639..7c7c673 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,15 @@ CHANGELOG ========= +0.5.0 +----- + +* Add `Before`, `After` and `Around` combinators +* Use `kemitix-maven-tiles` +* Add `BeanBuilder` experiment +* Upgrade `lombok` to 1.16.20 +* Upgrade assertj to 3.9.1 + 0.4.0 ----- diff --git a/Jenkinsfile.groovy b/Jenkinsfile.groovy new file mode 100644 index 0000000..3f87b24 --- /dev/null +++ b/Jenkinsfile.groovy @@ -0,0 +1,46 @@ +final String gitRepoUrl = 'git@github.com:kemitix/mon.git' +final String mvn = "mvn --batch-mode --update-snapshots" + +pipeline { + agent any + stages { + stage('Prepare') { + steps { + git url: gitRepoUrl, branch: '**', credentialsId: 'github-kemitix' + } + } + stage('Build') { + parallel { + stage('Java 8') { + steps { + withMaven(maven: 'maven 3.5.2', jdk: 'JDK 1.8') { + sh 'mvn clean install' + } + } + } + // requires maven-failsafe-plugin:2.21 when it is released +// stage('Java 9') { +// steps { +// withMaven(maven: 'maven 3.5.2', jdk: 'JDK 9') { +// sh 'mvn clean install' +// } +// } +// } + } + } + stage('Reporting') { + steps { + junit '**/target/surefire-reports/*.xml' + archiveArtifacts '**/target/*.jar' + } + } + stage('Deploy') { + when { expression { (env.GIT_BRANCH == 'master') } } + steps { + withMaven(maven: 'maven 3.5.2', jdk: 'JDK 1.8') { + sh "${mvn} deploy --activate-profiles release -DskipTests=true" + } + } + } + } +} diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..00ebb3e --- /dev/null +++ b/lombok.config @@ -0,0 +1 @@ +lombok.addGeneratedAnnotation=false diff --git a/pom.xml b/pom.xml index ccf634f..912869d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,17 +7,32 @@ net.kemitix kemitix-parent - 3.2.4 + 5.1.0 + mon - 0.4.0 + 0.5.0 + 1.8 4.12 - 3.8.0 + 3.9.1 + 1.16.20 + 2.10 + 0.6.1 + 2.20.1 + 2.20.1 + net.kemitix.mon + 4.0.1 + + org.projectlombok + lombok + ${lombok.version} + provided + junit junit @@ -27,9 +42,26 @@ org.assertj assertj-core - ${assertj-core.version} + ${assertj.version} test + + + + io.repaint.maven + tiles-maven-plugin + ${tiles-maven-plugin.version} + true + + + net.kemitix.tiles:all:${kemitix-tiles.version} + net.kemitix.checkstyle:tile:${kemitix-checkstyle.version} + + + + + + diff --git a/src/main/java/net/kemitix/mon/BeanBuilder.java b/src/main/java/net/kemitix/mon/BeanBuilder.java new file mode 100644 index 0000000..672a088 --- /dev/null +++ b/src/main/java/net/kemitix/mon/BeanBuilder.java @@ -0,0 +1,61 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.mon; + +import lombok.RequiredArgsConstructor; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * Helper to create bean-style objects. + * + * @param The type of the bean being built + */ +@RequiredArgsConstructor +public class BeanBuilder { + + private final Supplier supplier; + + /** + * Create a BeanBuilder from the Supplier. + * + * @param constructor supplies a new instance of the bean + * @param the type of the bean being built + * @return a BeanBuilder instance + */ + public static BeanBuilder define(final Supplier constructor) { + return new BeanBuilder<>(constructor); + } + + /** + * Creates a new bean and passes it to the customiser. + * + * @param customiser customises the template bean + * @return the final customised bean + */ + public T with(final Consumer customiser) { + final T result = supplier.get(); + customiser.accept(result); + return result; + } +} diff --git a/src/main/java/net/kemitix/mon/combinator/After.java b/src/main/java/net/kemitix/mon/combinator/After.java new file mode 100644 index 0000000..3fd00c4 --- /dev/null +++ b/src/main/java/net/kemitix/mon/combinator/After.java @@ -0,0 +1,78 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.mon.combinator; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * After pattern combinator. + * + *

Original from http://boundsofjava.com/newsletter/003-introducing-combinators-part1

+ * + * @param the argument type + * @param the result type + * + * @author Federico Peralta Schaffner (fps@boundsofjava.com) + */ +@FunctionalInterface +public interface After extends + Function, + Function< + BiConsumer, + Function>> { + + /** + * Decorates a function with a Consumer that will be supplier with the argument before applying it to the function. + * + * @param function the function to apply the argument to and return the result value of + * @param after the bi-consumer that will receive the argument and the result of the function + * @param the argument type + * @param the result type + * + * @return a partially applied Function that will take an argument and return the result of applying it to the + * function parameter + */ + static Function decorate( + final Function function, + final BiConsumer after + ) { + return After.create().apply(function) + .apply(after); + } + + /** + * Create an After curried function. + * + * @param the argument type + * @param the result type + * + * @return a curried function that will pass the argument and the result of the function to the supplied bi-consumer + */ + static After create() { + return function -> after -> argument -> { + final R result = function.apply(argument); + after.accept(argument, result); + return result; + }; + } +} diff --git a/src/main/java/net/kemitix/mon/combinator/Around.java b/src/main/java/net/kemitix/mon/combinator/Around.java new file mode 100644 index 0000000..b6d8e2e --- /dev/null +++ b/src/main/java/net/kemitix/mon/combinator/Around.java @@ -0,0 +1,101 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.mon.combinator; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * Around pattern combinator. + * + *

Original from http://boundsofjava.com/newsletter/003-introducing-combinators-part1

+ * + * @param the argument type + * @param the result type + * + * @author Federico Peralta Schaffner (fps@boundsofjava.com) + */ +@FunctionalInterface +public interface Around extends + Function< + Function, + Function< + BiConsumer, T>, + Function>> { + + /** + * Decorates a function with an BiConsumer that will be supplier with an executable to perform the function, and the + * argument that will be applied when executed. + * + * @param function the function to apply the argument to and return the result value of + * @param around the bi-consumer that will supplied with the executable and the argument + * @param the argument type + * @param the result type + * + * @return a partially applied Function that will take an argument, and the result of applying it to function + */ + static Function decorate( + final Function function, + final BiConsumer, T> around + ) { + return Around.create().apply(function) + .apply(around); + } + + /** + * Create an Around curried function. + * + * @param the argument type + * @param the result type + * + * @return a curried function that will execute the around function, passing an executable and the invocations + * argument. The around function must {@code execute()} the executable and may capture the result. + */ + static Around create() { + return function -> around -> argument -> { + final AtomicReference result = new AtomicReference<>(); + final Executable callback = () -> { + result.set(function.apply(argument)); + return result.get(); + }; + around.accept(callback, argument); + return result.get(); + }; + } + + /** + * The executable that will be supplied to the around function to trigger the surrounded function. + * + * @param the return type of the function + */ + @FunctionalInterface + interface Executable { + + /** + * Executes the function. + * + * @return the result of applying the function + */ + R execute(); + } +} diff --git a/src/main/java/net/kemitix/mon/combinator/Before.java b/src/main/java/net/kemitix/mon/combinator/Before.java new file mode 100644 index 0000000..4e40a29 --- /dev/null +++ b/src/main/java/net/kemitix/mon/combinator/Before.java @@ -0,0 +1,78 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.mon.combinator; + +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * Before pattern combinator. + * + *

Original from http://boundsofjava.com/newsletter/003-introducing-combinators-part1

+ * + * @param the argument type + * @param the result type + * + * @author Federico Peralta Schaffner (fps@boundsofjava.com) + */ +@FunctionalInterface +public interface Before extends + Function< + Consumer, + Function< + Function, + Function>> { + + /** + * Decorates a function with a Consumer that will be supplied with the argument before applying it to the function. + * + * @param before the consumer that will receive the argument before the function + * @param function the function to apply the argument to and return the result value of + * @param the argument type + * @param the result type + * + * @return a partially applied Function that will take an argument and return the result of applying it to the + * function parameter + */ + static Function decorate( + final Consumer before, + final Function function + ) { + return Before.create().apply(before) + .apply(function); + } + + /** + * Create a Before curried function. + * + * @param the argument type + * @param the result type + * + * @return a curried function that will pass the argument to before applying the supplied function + */ + static Before create() { + return before -> function -> argument -> { + before.accept(argument); + return function.apply(argument); + }; + } +} diff --git a/src/main/java/net/kemitix/mon/combinator/package-info.java b/src/main/java/net/kemitix/mon/combinator/package-info.java new file mode 100644 index 0000000..9ff7a6d --- /dev/null +++ b/src/main/java/net/kemitix/mon/combinator/package-info.java @@ -0,0 +1,22 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Campbell + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies + * or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.kemitix.mon.combinator; diff --git a/src/test/java/net/kemitix/mon/BeanBuilderTest.java b/src/test/java/net/kemitix/mon/BeanBuilderTest.java new file mode 100644 index 0000000..a1b3ad3 --- /dev/null +++ b/src/test/java/net/kemitix/mon/BeanBuilderTest.java @@ -0,0 +1,42 @@ +package net.kemitix.mon; + +import static net.kemitix.mon.BeanBuilder.define; +import static org.assertj.core.api.Assertions.*; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.junit.Test; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class BeanBuilderTest { + + @Test + public void canCreateAndSetupObject() { + //given + final Supplier templateSupplier = () -> new DataObject("name"); + final Consumer propertySetter = data -> data.setValue("value"); + + //when + final DataObject result = define(templateSupplier) + .with(propertySetter); + + //then + assertThat(result) + .returns("name", DataObject::getName) + .returns("value", DataObject::getValue); + } + + @Getter + @RequiredArgsConstructor + private class DataObject { + + private final String name; + + @Setter + private String value; + + } +} diff --git a/src/test/java/net/kemitix/mon/combinator/AfterTest.java b/src/test/java/net/kemitix/mon/combinator/AfterTest.java new file mode 100644 index 0000000..8d5a4eb --- /dev/null +++ b/src/test/java/net/kemitix/mon/combinator/AfterTest.java @@ -0,0 +1,44 @@ +package net.kemitix.mon.combinator; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AfterTest { + + @Test + public void canCreateAfterCombinator() { + //given + final List events = new ArrayList<>(); + final Function squareDecorated = + After.decorate( + argument -> function(argument, events), + (argument, result) -> after(argument, result, events) + ); + //when + final Integer result = squareDecorated.apply(2); + //then + assertThat(result).isEqualTo(4); + assertThat(events).containsExactly("function", "after 2 -> 4"); + } + + private static void after( + final Integer argument, + final Integer result, + final List events + ) { + events.add(String.format("after %d -> %d", argument, result)); + } + + private static Integer function( + final Integer argument, + final List events + ) { + events.add("function"); + return argument * argument; + } +} diff --git a/src/test/java/net/kemitix/mon/combinator/AroundTest.java b/src/test/java/net/kemitix/mon/combinator/AroundTest.java new file mode 100644 index 0000000..ee94f2b --- /dev/null +++ b/src/test/java/net/kemitix/mon/combinator/AroundTest.java @@ -0,0 +1,46 @@ +package net.kemitix.mon.combinator; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AroundTest { + + @Test + public void canCreateAnAroundCombinator() { + //given + final List events = new ArrayList<>(); + final Function squareDecorated = + Around.decorate( + argument -> function(argument, events), + (executable, argument) -> around(executable, argument, events) + ); + //when + final Integer result = squareDecorated.apply(2); + //then + assertThat(result).isEqualTo(4); + assertThat(events).containsExactly("around before 2", "function", "around after 4"); + } + + private void around( + final Around.Executable executable, + final Integer argument, + final List events + ) { + events.add("around before " + argument); + final Integer result = executable.execute(); + events.add("around after " + result); + } + + private static Integer function( + final Integer argument, + final List events + ) { + events.add("function"); + return argument * argument; + } +} diff --git a/src/test/java/net/kemitix/mon/combinator/BeforeTest.java b/src/test/java/net/kemitix/mon/combinator/BeforeTest.java new file mode 100644 index 0000000..d14d85c --- /dev/null +++ b/src/test/java/net/kemitix/mon/combinator/BeforeTest.java @@ -0,0 +1,43 @@ +package net.kemitix.mon.combinator; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BeforeTest { + + @Test + public void canCreateBeforeCombinator() { + //given + final List events = new ArrayList<>(); + final Function squareDecorated = + Before.decorate( + argument -> before(argument, events), + argument -> function(argument, events) + ); + //when + final Integer result = squareDecorated.apply(2); + //then + assertThat(result).isEqualTo(4); + assertThat(events).containsExactly("before 2", "function"); + } + + private static void before( + final Integer argument, + final List events + ) { + events.add("before " + argument); + } + + private static Integer function( + final Integer argument, + final List events + ) { + events.add("function"); + return argument * argument; + } +}