This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 5d46759 GROOVY-9169: Groovy could support andThen/compose aliases for
rightShift/leftShift (closes #952)
5d46759 is described below
commit 5d4675988fc58a06553343039cb8b4943f035908
Author: Paul King <[email protected]>
AuthorDate: Tue Jun 11 21:06:05 2019 +1000
GROOVY-9169: Groovy could support andThen/compose aliases for
rightShift/leftShift (closes #952)
---
src/main/java/groovy/lang/Closure.java | 60 +++++++++++++++++++++++++++
src/test/groovy/ClosureComposeTest.groovy | 68 +++++++++++++++++++++++++++++++
2 files changed, 128 insertions(+)
diff --git a/src/main/java/groovy/lang/Closure.java
b/src/main/java/groovy/lang/Closure.java
index 6464a2d..f91c5f0 100644
--- a/src/main/java/groovy/lang/Closure.java
+++ b/src/main/java/groovy/lang/Closure.java
@@ -657,6 +657,66 @@ public abstract class Closure<V> extends
GroovyObjectSupport implements Cloneabl
}
/**
+ * Alias for {@link #rightShift(Closure)}
+ *
+ * @return the newly composed closure
+ */
+ public <W> Closure<W> andThen(final Closure<W> other) {
+ return rightShift(other);
+ }
+
+ /**
+ * Call {@link #andThen(Closure)} on {@code this}.
+ *
+ * @return the newly composed closure
+ */
+ public Closure<V> andThenSelf() {
+ return andThen(this);
+ }
+
+ /**
+ * Call {@link #andThen(Closure)} on {@code this} exactly {@code times}
times.
+ *
+ * @param times the number of times to reverse compose the closure with
itself
+ * @return the newly composed closure
+ */
+ public Closure<V> andThenSelf(int times) {
+ if (times == 0) return this;
+ if (times == 1) return andThen(this);
+ return andThen(andThenSelf(times - 1));
+ }
+
+ /**
+ * Alias for {@link #leftShift(Closure)}
+ *
+ * @return the newly composed closure
+ */
+ public Closure<V> compose(final Closure other) {
+ return leftShift(other);
+ }
+
+ /**
+ * Call {@link #compose(Closure)} on {@code this}.
+ *
+ * @return the newly composed closure
+ */
+ public Closure<V> composeSelf() {
+ return compose(this);
+ }
+
+ /**
+ * Call {@link #compose(Closure)} on {@code this} exactly {@code times}
times.
+ *
+ * @param times the number of times to compose the closure with itself
+ * @return the newly composed closure
+ */
+ public Closure<V> composeSelf(int times) {
+ if (times == 0) return this;
+ if (times == 1) return compose(this);
+ return compose(composeSelf(times - 1));
+ }
+
+ /**
* Alias for calling a Closure for non-closure arguments.
* <p>
* Typical usage:
diff --git a/src/test/groovy/ClosureComposeTest.groovy
b/src/test/groovy/ClosureComposeTest.groovy
index 2f759a5..75eaab1 100644
--- a/src/test/groovy/ClosureComposeTest.groovy
+++ b/src/test/groovy/ClosureComposeTest.groovy
@@ -18,6 +18,10 @@
*/
package groovy
+import groovy.transform.CompileStatic
+
+import java.util.function.Function
+
/**
* Tests for Closure composition
*/
@@ -100,6 +104,70 @@ class ClosureComposeTest extends GroovyTestCase {
"""
}
+ @CompileStatic
+ void testAndThenCS() {
+ Function<String, String> lower = String::toLowerCase
+ Function<String, String> upper = String::toUpperCase
+ Function<String, String> lu = lower.andThen(upper)
+ Function<? super String, String> ul = upper.andThen(lower)
+ assert lower('Hi') == ul('Hi')
+ assert upper('Hi') == lu('Hi')
+ }
+
+ void testAndThen() {
+ def lower = String::toLowerCase
+ def upper = String::toUpperCase
+ def lu1 = lower.rightShift(upper)
+ def ul1 = upper.rightShift(lower)
+ assert lower('Hi') == ul1('Hi')
+ assert upper('Hi') == lu1('Hi')
+ def lu2 = lower.andThen(upper)
+ def ul2 = upper.andThen(lower)
+ assert lower('Hi') == ul2('Hi')
+ assert upper('Hi') == lu2('Hi')
+ }
+
+ void testAndThenSelf() {
+ def inc = String::next
+ def inc2 = inc.andThenSelf()
+ def inc4 = inc.andThenSelf(3)
+ assert inc('abc') == 'abd'
+ assert inc2('abc') == 'abe'
+ assert inc4('abc') == 'abg'
+ }
+
+ @CompileStatic
+ void testComposeCS() {
+ Function<String, String> lower = String::toLowerCase
+ Function<String, String> upper = String::toUpperCase
+ Function<String, String> ul = lower.compose(upper)
+ Function<String, ? extends String> lu = upper.compose(lower)
+ assert lower('Hi') == ul('Hi')
+ assert upper('Hi') == lu('Hi')
+ }
+
+ void testCompose() {
+ def lower = String::toLowerCase
+ def upper = String::toUpperCase
+ def ul1 = lower.leftShift(upper)
+ def lu1 = upper.leftShift(lower)
+ assert lower('Hi') == ul1('Hi')
+ assert upper('Hi') == lu1('Hi')
+ def ul2 = lower.compose(upper)
+ def lu2 = upper.compose(lower)
+ assert lower('Hi') == ul2('Hi')
+ assert upper('Hi') == lu2('Hi')
+ }
+
+ void testComposeSelf() {
+ def inc = String::next
+ def inc2 = inc.composeSelf()
+ def inc4 = inc.composeSelf(3)
+ assert inc('abc') == 'abd'
+ assert inc2('abc') == 'abe'
+ assert inc4('abc') == 'abg'
+ }
+
class ComposeTestHelper {
def closure1 = { 40 }
def closure2 = { it * 40 }