Author: hlship
Date: Tue Jan  4 22:39:10 2011
New Revision: 1055223

URL: http://svn.apache.org/viewvc?rev=1055223&view=rev
Log:
TAP5-1390: Add predicate factories for matching String prefixes and suffixes
Make it easy to filter a ZippedFlow using a Predicate that applies to its first 
or second tuple values

Added:
    
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java
Modified:
    
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/F.java
    
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlow.java
    
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlowImpl.java
    
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java

Modified: 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/F.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/F.java?rev=1055223&r1=1055222&r2=1055223&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/F.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/F.java
 Tue Jan  4 22:39:10 2011
@@ -26,9 +26,9 @@ import java.util.Iterator;
  * created
  * using {...@link #flow(Collection)} and {...@link #flow(Object...)}.
  * <p>
- * F will be used a bit, thus it has a short name (for those who don't like 
static imports). It
- * provides a base set of Predicate, Mapper and Reducer factories. A good 
development pattern for
- * applications is to provide a similar, application-specific, set of such 
factories.
+ * F will be used a bit, thus it has a short name (for those who don't like 
static imports). It provides a base set of
+ * Predicate, Mapper and Reducer factories. A good development pattern for 
applications is to provide a similar,
+ * application-specific, set of such factories.
  * 
  * @since 5.2.0
  */
@@ -159,8 +159,7 @@ public class F
     }
 
     /**
-     * A Mapper factory that gets the string value of the flow value using
-     * {...@link String#valueOf(Object)}.
+     * A Mapper factory that gets the string value of the flow value using 
{...@link String#valueOf(Object)}.
      */
     public static <T> Mapper<T, String> stringValueOf()
     {
@@ -314,8 +313,8 @@ public class F
 
     /**
      * Creates a lazy Flow from the {...@link Iterator} obtained from the 
iterable. The Flow
-     * will be threadsafe as long as the iterable yields a new Iterator on 
each invocation
-     * <em>and</em> the underlying iterable object is not modified while the 
Flow is evaluating.
+     * will be threadsafe as long as the iterable yields a new Iterator on 
each invocation <em>and</em> the underlying
+     * iterable object is not modified while the Flow is evaluating.
      * In other words, not extremely threadsafe.
      */
     public static <T> Flow<T> flow(Iterable<T> iterable)
@@ -400,4 +399,72 @@ public class F
             }
         };
     }
+
+    /**
+     * A Predicate factory for matching String elements with a given prefix.
+     * 
+     * @since 5.3.0
+     */
+    public static Predicate<String> startsWith(String prefix)
+    {
+        return startsWith(prefix, false);
+    }
+
+    /**
+     * As {...@link #startsWith(String)}, but ignores case.
+     * 
+     * @since 5.3.0
+     */
+    public static Predicate<String> startsWithIgnoringCase(String prefix)
+    {
+        return startsWith(prefix, true);
+    }
+
+    /** @since 5.3.0 */
+    private static Predicate<String> startsWith(final String prefix, final 
boolean ignoreCase)
+    {
+        return new Predicate<String>()
+        {
+            @Override
+            public boolean accept(String element)
+            {
+                return element.regionMatches(ignoreCase, 0, prefix, 0, 
prefix.length());
+            }
+        };
+    }
+
+    /**
+     * A Predicate factory for matching String elements with a given suffix.
+     * 
+     * @since 5.3.0
+     */
+    public static Predicate<String> endsWith(String suffix)
+    {
+        return endsWith(suffix, false);
+    }
+
+    /**
+     * As with {...@link #endsWith(String)} but ignores case.
+     * 
+     * @since 5.3.0
+     */
+    public static Predicate<String> endsWithIgnoringCase(String suffix)
+    {
+        return endsWith(suffix, true);
+    }
+
+    /** @since 5.3.0 */
+    private static Predicate<String> endsWith(final String suffix, final 
boolean ignoreCase)
+    {
+        return new Predicate<String>()
+        {
+            @Override
+            public boolean accept(String element)
+            {
+                return element
+                        .regionMatches(ignoreCase, element.length() - 
suffix.length(), suffix, 0, suffix.length());
+            }
+        };
+    }
+
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlow.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlow.java?rev=1055223&r1=1055222&r2=1055223&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlow.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlow.java
 Tue Jan  4 22:39:10 2011
@@ -16,8 +16,7 @@ package org.apache.tapestry5.func;
 
 /**
  * The result of the {...@link Flow#zipWith(Flow)} method, a Flow of combined 
{...@link Tuple} values
- * (that can be deconstructed, eventually, using {...@link #unzip()}). Each 
operation of {...@link Flow}
- * has a corresponding implementation here, on the Tuple values.
+ * (that can be deconstructed, eventually, using {...@link #unzip()}).
  * 
  * @param <A>
  * @param <B>
@@ -51,4 +50,28 @@ public interface ZippedFlow<A, B> extend
      * operation.
      */
     Flow<B> seconds();
+
+    /**
+     * Filters the tuples in the zipped flow by applying a predicate to the 
first value in each tuple.
+     * This is a lazy operation.
+     */
+    ZippedFlow<A, B> filterOnFirst(Predicate<? super A> predicate);
+
+    /**
+     * Filters the tuples in the zipped flow by applying a predicate to the 
second value in each tuple. This
+     * is a lazy operations.
+     */
+    ZippedFlow<A, B> filterOnSecond(Predicate<? super B> predicate);
+
+    /**
+     * Removes tuples from the zipped flow by applying a predicate to the 
first value in each tuple.
+     * This is a lazy operation.
+     */
+    ZippedFlow<A, B> removeOnFirst(Predicate<? super A> predicate);
+
+    /**
+     * Removes tuples from the zipped flow by applying a predicate to the 
second value in each tuple. This
+     * is a lazy operations.
+     */
+    ZippedFlow<A, B> removeOnSecond(Predicate<? super B> predicate);
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlowImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlowImpl.java?rev=1055223&r1=1055222&r2=1055223&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlowImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-func/src/main/java/org/apache/tapestry5/func/ZippedFlowImpl.java
 Tue Jan  4 22:39:10 2011
@@ -20,8 +20,8 @@ import java.util.List;
 import java.util.Set;
 
 /**
- * The single implementation of {...@link ZippedFlow}, that operates by 
wrapping around an ordinary
- * {...@link Flow} of the {...@link Tuples} of the zipped flow. In the future, 
we may create an
+ * The single implementation of {...@link ZippedFlow}, that operates by 
wrapping around an ordinary {...@link Flow} of the
+ * {...@link Tuples} of the zipped flow. In the future, we may create an
  * EmptyZippedFlow implementation as well.
  * 
  * @param <A>
@@ -141,7 +141,6 @@ class ZippedFlowImpl<A, B> implements Zi
     {
         return tupleFlow.map(new Mapper<Tuple<A, B>, A>()
         {
-
             @Override
             public A map(Tuple<A, B> value)
             {
@@ -159,7 +158,6 @@ class ZippedFlowImpl<A, B> implements Zi
     {
         return tupleFlow.map(new Mapper<Tuple<A, B>, B>()
         {
-
             @Override
             public B map(Tuple<A, B> value)
             {
@@ -168,4 +166,46 @@ class ZippedFlowImpl<A, B> implements Zi
         });
     }
 
+    public ZippedFlow<A, B> filterOnFirst(final Predicate<? super A> predicate)
+    {
+        assert predicate != null;
+
+        return filter(new Predicate<Tuple<A, B>>()
+        {
+            @Override
+            public boolean accept(Tuple<A, B> element)
+            {
+                return predicate.accept(element.first);
+            }
+        });
+    }
+
+    public ZippedFlow<A, B> filterOnSecond(final Predicate<? super B> 
predicate)
+    {
+        assert predicate != null;
+
+        return filter(new Predicate<Tuple<A, B>>()
+        {
+            @Override
+            public boolean accept(Tuple<A, B> element)
+            {
+                return predicate.accept(element.second);
+            }
+        });
+    }
+
+    public ZippedFlow<A, B> removeOnFirst(Predicate<? super A> predicate)
+    {
+        assert predicate != null;
+
+        return filterOnFirst(predicate.invert());
+    }
+
+    public ZippedFlow<A, B> removeOnSecond(Predicate<? super B> predicate)
+    {
+        assert predicate != null;
+
+        return filterOnSecond(predicate.invert());
+    }
+
 }

Added: 
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java?rev=1055223&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/StringPredicateTests.java
 Tue Jan  4 22:39:10 2011
@@ -0,0 +1,51 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// 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.apache.tapestry5.func;
+
+import org.testng.annotations.Test;
+
+public class StringPredicateTests extends BaseFuncTest
+{
+    @Test
+    public void prefix_predicate()
+    {
+        Flow<String> names = F.flow("Howard", "Henry", "Anna", "Hubert");
+
+        assertFlowValues(names.remove(F.startsWith("H")), "Anna");
+    }
+
+    @Test
+    public void case_insensitive_prefix_predicate()
+    {
+        Flow<String> names = F.flow("Howard", "Henry", "Anna", "Hubert");
+
+        assertFlowValues(names.filter(F.startsWithIgnoringCase("h")), 
"Howard", "Henry", "Hubert");
+    }
+
+    @Test
+    public void suffix_predicate()
+    {
+        Flow<String> names = F.flow("Ted", "Charly", "Fred", "Anna");
+
+        assertFlowValues(names.filter(F.endsWith("red")), "Fred");
+    }
+
+    @Test
+    public void case_insensitive_suffix_precicate()
+    {
+        Flow<String> names = F.flow("Ted", "Charly", "Fred", "Anna");
+
+        assertFlowValues(names.filter(F.endsWithIgnoringCase("RED")), "Fred");
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java?rev=1055223&r1=1055222&r2=1055223&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-func/src/test/java/org/apache/tapestry5/func/ZippedFlowTests.java
 Tue Jan  4 22:39:10 2011
@@ -29,6 +29,30 @@ public class ZippedFlowTests extends Bas
 
     ZippedFlow<Integer, String> zipped = numbers.zipWith(names);
 
+    @Test
+    public void filter_on_first()
+    {
+        assertFlowValues(zipped.filterOnFirst(F.eql(3)).seconds(), "wilma");
+    }
+
+    @Test
+    public void remove_on_first()
+    {
+        assertFlowValues(zipped.removeOnFirst(F.neq(2)).seconds(), "barney");
+    }
+
+    @Test
+    public void filter_on_second()
+    {
+        assertFlowValues(zipped.filterOnSecond(F.startsWith("b")).seconds(), 
"barney");
+    }
+
+    @Test
+    public void remove_on_second()
+    {
+        assertFlowValues(zipped.removeOnSecond(F.startsWith("b")).seconds(), 
"fred", "wilma");
+    }
+
     @SuppressWarnings("unchecked")
     @Test
     public void zip_flows_together()


Reply via email to