Index: src/main/groovy/lang/MetaClassImpl.java
===================================================================
--- src/main/groovy/lang/MetaClassImpl.java (revision 20259)
+++ src/main/groovy/lang/MetaClassImpl.java (revision )
@@ -107,7 +107,6 @@
private static final String CLOSURE_CALL_METHOD = "call";
private static final String CLOSURE_DO_CALL_METHOD = "doCall";
- private static final String CLOSURE_CURRY_METHOD = "curry";
protected static final String STATIC_METHOD_MISSING = "$static_methodMissing";
protected static final String STATIC_PROPERTY_MISSING = "$static_propertyMissing";
protected static final String METHOD_MISSING = "methodMissing";
@@ -930,8 +929,6 @@
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
if (method==null) invokeMissingMethod(object,methodName,arguments);
- } else if (CLOSURE_CURRY_METHOD.equals(methodName)) {
- return closure.curry(arguments);
}
final Object delegate = closure.getDelegate();
Index: src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
===================================================================
--- src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java (revision 20604)
+++ src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java (revision )
@@ -62,7 +62,6 @@
private static final Object[] EMPTY_ARGUMENTS = {};
private static final String CLOSURE_CALL_METHOD = "call";
private static final String CLOSURE_DO_CALL_METHOD = "doCall";
- private static final String CLOSURE_CURRY_METHOD = "curry";
static {
CLOSURE_METACLASS = new MetaClassImpl(Closure.class);
@@ -263,9 +262,9 @@
}
}
if (method == null) throw new MissingMethodException(methodName, theClass, arguments, false);
- } else if (CLOSURE_CURRY_METHOD.equals(methodName)) {
- return closure.curry(arguments);
- } else {
+ }
+
+ if (method == null && closure.getResolveStrategy() != Closure.DELEGATE_ONLY) {
method = CLOSURE_METACLASS.pickMethod(methodName, argClasses);
}
Index: src/main/org/codehaus/groovy/runtime/ComposedClosure.java
===================================================================
--- src/main/org/codehaus/groovy/runtime/ComposedClosure.java (revision )
+++ src/main/org/codehaus/groovy/runtime/ComposedClosure.java (revision )
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2003-2010 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+
+import java.util.List;
+
+/**
+ * A wrapper for Closure to support composition.
+ * Normally used only internally through the rightShift() and
+ * leftShift() methods on Closure.
+ *
+ * def twice = { a -> a * 2 }
+ * def inc = { b -> b + 1 }
+ * def f = { x -> twice(inc(x)) } // longhand
+ * def g = inc >> twice
+ * def h = twice << inc
+ * assert f(10) == 22
+ * assert g(10) == 22
+ * assert h(10) == 22
+ *
+ * def s2c = { it.chars[0] }
+ * def p = Integer.&toHexString >> s2c >> Character.&toUpperCase
+ * assert p(15) == 'F'
+ *
+ * def multiply = { a, b -> a * b }
+ * def identity = { a -> [a, a] }
+ * def sq = identity >> multiply
+ * assert (1..5).collect{ sq(it) } == [1, 4, 9, 16, 25]
+ *
+ * def add3 = { a, b, c -> a + b + c }
+ * def add2plus10 = add3.curry(10)
+ * def multBoth = { a, b, c -> [a*c, b*c] }
+ * def twiceBoth = multBoth.rcurry(2)
+ * def twiceBothPlus10 = twiceBoth >> add2plus10
+ * assert twiceBothPlus10(5, 10) == 40
+ *
+ *
+ * @author Paul King
+ */
+public final class ComposedClosure extends Closure {
+
+ private Closure first;
+ private Closure second;
+
+ public ComposedClosure(Closure first, Closure second) {
+ super(first);
+ this.first = (Closure) first.clone();
+ this.second = (Closure) second.clone();
+ maximumNumberOfParameters = first.getMaximumNumberOfParameters();
+ }
+
+ public void setDelegate(Object delegate) {
+ ((Closure) getOwner()).setDelegate(delegate);
+ second.setDelegate(delegate);
+ }
+
+ public Object getDelegate() {
+ return ((Closure) getOwner()).getDelegate();
+ }
+
+ public void setResolveStrategy(int resolveStrategy) {
+ ((Closure) getOwner()).setResolveStrategy(resolveStrategy);
+ second.setResolveStrategy(resolveStrategy);
+ }
+
+ public int getResolveStrategy() {
+ return ((Closure) getOwner()).getResolveStrategy();
+ }
+
+ public Object clone() {
+ return new ComposedClosure(first, second);
+ }
+
+ public Class[] getParameterTypes() {
+ return first.getParameterTypes();
+ }
+
+ @Override
+ public Object call(Object[] args) {
+ Object temp = first.call(args);
+ if (temp instanceof List && second.getParameterTypes().length > 1) temp = ((List) temp).toArray();
+ return temp instanceof Object[] ? second.call((Object[]) temp) : second.call(temp);
+ }
+}
Index: src/test/groovy/xml/MarkupBuilderTest.groovy
===================================================================
--- src/test/groovy/xml/MarkupBuilderTest.groovy (revision 19637)
+++ src/test/groovy/xml/MarkupBuilderTest.groovy (revision )
@@ -226,6 +226,23 @@
assertExpectedXmlDefault "
+ * def twice = { a -> a * 2 }
+ * def thrice = { a -> a * 3 }
+ * def times6 = twice >> thrice
+ * // equivalent: times6 = { a -> thrice(twice(a)) }
+ * assert times6(3) == 18
+ *
+ *
+ * @param other the Closure to compose with the current Closure
+ * @return the new composed Closure
+ */
+ public Closure rightShift(final Closure other) {
+ return new ComposedClosure(this, other);
+ }
+
+ /**
+ * Support for Closure reverse composition.
+ *
+ * Typical usage:
+ *
+ * def twice = { a -> a * 2 }
+ * def thrice = { a -> a * 3 }
+ * def times6 = thrice << twice
+ * // equivalent: times6 = { a -> thrice(twice(a)) }
+ * assert times6(3) == 18
+ *
+ *
+ * @param other the Closure to compose with the current Closure
+ * @return the new composed Closure
+ */
+ public Closure leftShift(final Closure other) {
+ return new ComposedClosure(other, this);
+ }
+
+ /* *
+ * Alias for calling a Closure for non-closure arguments.
+ *
+ * Typical usage:
+ *
+ * def twice = { a -> a * 2 }
+ * def thrice = { a -> a * 3 }
+ * assert thrice << twice << 3 == 18
+ *
+ *
+ * @param arg the argument to call the closure with
+ * @return the result of calling the Closure
+ */
+ public V leftShift(final Object arg) {
+ return call(arg);
+ }
+
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
Index: src/main/groovy/lang/ExpandoMetaClass.java
===================================================================
--- src/main/groovy/lang/ExpandoMetaClass.java (revision 20232)
+++ src/main/groovy/lang/ExpandoMetaClass.java (revision )
@@ -772,9 +772,10 @@
final DefiningClosure definer = new DefiningClosure();
Object delegate = closure.getDelegate();
closure.setDelegate(definer);
- closure.setResolveStrategy(Closure.DELEGATE_FIRST);
+ closure.setResolveStrategy(Closure.DELEGATE_ONLY);
closure.call(null);
closure.setDelegate(delegate);
+ closure.setResolveStrategy(Closure.DELEGATE_FIRST);
definer.definition = false;
return this;
}