http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/Functions.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/Functions.java b/core/functional/src/main/java/org/qi4j/functional/Functions.java new file mode 100644 index 0000000..bf86845 --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/Functions.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2010, Rickard Ãberg. All Rights Reserved. + * + * 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.qi4j.functional; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +/** + * Utility functions. Combine these with methods in Iterables, for example. See FunctionsTest for usages. + */ +public final class Functions +{ + public static <A, B, C> Function2<Function<? super B, C>, Function<A, B>, Function<A, C>> compose() + { + return new Function2<Function<? super B, C>, Function<A, B>, Function<A, C>>() + { + @Override + public Function<A, C> map( Function<? super B, C> bcFunction, Function<A, B> abFunction ) + { + return compose( bcFunction, abFunction ); + } + }; + } + + /** + * compose(F1(M,T),F2(F,M)) = F1(F2(F)) -> T + * + * @param outer The outer/encapsulating function + * @param inner The inner/encapsulated function + * + * @return A function that is a composition of an outer and inner function. + */ + public static <FROM, MIDDLE, TO> Function<FROM, TO> compose( final Function<? super MIDDLE, TO> outer, + final Function<FROM, MIDDLE> inner + ) + { + return new Function<FROM, TO>() + { + @Override + public TO map( FROM from ) + { + return outer.map( inner.map( from ) ); + } + }; + } + + public static <TO, FROM extends TO> Function<FROM, TO> identity() + { + return new Function<FROM, TO>() + { + @Override + public TO map( FROM from ) + { + return from; + } + }; + } + + public static <FROM, TO> Function<FROM, TO> fromMap( final Map<FROM, TO> map ) + { + return new Function<FROM, TO>() + { + @Override + public TO map( FROM from ) + { + return map.get( from ); + } + }; + } + + public static <T> Function<T, T> withDefault( final T defaultValue ) + { + return new Function<T, T>() + { + @Override + public T map( T from ) + { + if( from == null ) + { + return defaultValue; + } + else + { + return from; + } + } + }; + } + + public static Function<Number, Long> longSum() + { + return new Function<Number, Long>() + { + long sum; + + @Override + public Long map( Number number ) + { + sum += number.longValue(); + return sum; + } + }; + } + + public static Function<Number, Integer> intSum() + { + return new Function<Number, Integer>() + { + int sum; + + @Override + public Integer map( Number number ) + { + sum += number.intValue(); + return sum; + } + }; + } + + /** + * Count the number of items in an iterable that matches a given specification. + * + * Sample usage: last( map( count( in( "X" ) ), iterable( "X","Y","X","X","Y" ) ) ) + * Returns: 3 + * + * @param specification The items that adhere to the Specification is counted. + * @param <T> The type of the items. + * + * @return A Function that can count items adhering to a Specification. + */ + public static <T> Function<T, Integer> count( final Specification<T> specification ) + { + return new Function<T, Integer>() + { + int count; + + @Override + public Integer map( T item ) + { + if( specification.satisfiedBy( item ) ) + { + count++; + } + + return count; + } + }; + } + + /** + * Find out the index of an item matching a given specification in an iterable. + * Returns -1 if it is not found. + * + * @param specification The Specification that specifies what to look for. + * @param <T> The type of the items. + * + * @return A Function that will provide the 'index' where the Specifcation is fulfilled. The Function will + * return -1 if the current item doesn't fulfill the Specification. + */ + public static <T> Function<T, Integer> indexOf( final Specification<T> specification ) + { + return new Function<T, Integer>() + { + int index = -1; + int current = 0; + + @Override + public Integer map( T item ) + { + if( index == -1 && specification.satisfiedBy( item ) ) + { + index = current; + } + + current++; + + return index; + } + }; + } + + /** + * Find out the index of an item in an iterable. + * + * @param item The item to look for. + * @param iterable The Iterable to search. + * @param <T> The type of the items. + * + * @return The index in the Iterable where the item is located. + */ + @SuppressWarnings( "unchecked" ) + public static <T> int indexOf( T item, Iterable<T> iterable ) + { + return Iterables.first( Iterables.filter( Specifications.not( Specifications.in( -1 ) ), + Iterables.map( indexOf( Specifications.in( item ) ), iterable ) ) ); + } + + /** + * Only apply given function on objects that satisfies the given specification. + * + * @param specification A Specification that specifies what should be included in the filtered result. + * @param function The function to be applied to items that fulfills the Specification + * @param <T> The type of the items. + * + * @return A Function that performs the filter operation when applied to Iterables. + */ + public static <T> Function<T, T> filteredMap( final Specification<T> specification, final Function<T, T> function ) + { + return new Function<T, T>() + { + @Override + public T map( T from ) + { + return specification.satisfiedBy( from ) ? function.map( from ) : from; + } + }; + } + + /** + * Creates a comparator that takes a function as input. The returned comparator will use the + * function once for each item in the list to be sorted by Collections.sort. + * + * This should be used if the function to generate the sort key from an object is expensive, so + * that it is not done many times for each item in a list. + * + * @param comparableFunction The Function that the Comparator will delegate to. + * @param <T> The generic type to be used. + * + * @return A comparator that uses a Function for the compare operation. + */ + @SuppressWarnings( "raw" ) + public static <T> Comparator<T> comparator( final Function<T, Comparable> comparableFunction ) + { + return new Comparator<T>() + { + Map<T, Comparable> compareKeys = new HashMap<>(); + + @Override + @SuppressWarnings( "unchecked" ) + public int compare( T o1, T o2 ) + { + Comparable key1 = compareKeys.get( o1 ); + if( key1 == null ) + { + key1 = comparableFunction.map( o1 ); + compareKeys.put( o1, key1 ); + } + + Comparable key2 = compareKeys.get( o2 ); + if( key2 == null ) + { + key2 = comparableFunction.map( o2 ); + compareKeys.put( o2, key2 ); + } + + return key1.compareTo( key2 ); + } + }; + } + + private Functions() + { + } +}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitor.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitor.java b/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitor.java new file mode 100644 index 0000000..1d328cb --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitor.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012, Niclas Hedhman. All Rights Reserved. + * + * 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.qi4j.functional; + +/** + * Visitor to visit hierarchies. + */ +public interface HierarchicalVisitor<NODE, LEAF, ThrowableType extends Throwable> extends Visitor<LEAF, ThrowableType> +{ + /** + * Enter an instance of T + * + * @param visited the visited instance which is now entered + * + * @return true if the visitor pattern should continue, false if it should be aborted for this level + * + * @throws ThrowableType if an exception occurred during processing. Any client call that initiated the visiting should + * get the exception in order to handle it properly. + */ + boolean visitEnter( NODE visited ) + throws ThrowableType; + + /** + * Leave an instance of T + * + * @param visited the visited instance which is now left + * + * @return true if the visitor pattern should continue, false if it should be aborted for the level of this node + * + * @throws ThrowableType if an exception occurred during processing. Any client call that initiated the visiting should + * get the exception in order to handle it properly. + */ + boolean visitLeave( NODE visited ) + throws ThrowableType; + + @Override + boolean visit( LEAF visited ) + throws ThrowableType; +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitorAdapter.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitorAdapter.java b/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitorAdapter.java new file mode 100644 index 0000000..2023655 --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/HierarchicalVisitorAdapter.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.qi4j.functional; + +/** + * Generic Hierarchical Visitor interface. + */ +public class HierarchicalVisitorAdapter<NODE, LEAF, ThrowableType extends Throwable> + implements HierarchicalVisitor<NODE, LEAF, ThrowableType> +{ + @Override + public boolean visitEnter( NODE visited ) + throws ThrowableType + { + return true; + } + + @Override + public boolean visitLeave( NODE visited ) + throws ThrowableType + { + return true; + } + + @Override + public boolean visit( LEAF visited ) + throws ThrowableType + { + return true; + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/Iterables.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/Iterables.java b/core/functional/src/main/java/org/qi4j/functional/Iterables.java new file mode 100644 index 0000000..ec5ae43 --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/Iterables.java @@ -0,0 +1,939 @@ +/* + * Copyright (c) 2010, Rickard Ãberg. All Rights Reserved. + * + * 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.qi4j.functional; + +import java.lang.reflect.Array; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * Utility methods for working with Iterables. See test for examples of how to use. + */ +public final class Iterables +{ + @SuppressWarnings( "raw" ) + private static final Iterable EMPTY = new Iterable() + { + Iterator iterator = new Iterator() + { + @Override + public boolean hasNext() + { + return false; + } + + @Override + public Object next() + { + throw new NoSuchElementException(); + } + + @Override + public void remove() + { + } + }; + + @Override + public Iterator iterator() + { + return iterator; + } + }; + + @SuppressWarnings( "unchecked" ) + public static <T> Iterable<T> empty() + { + return EMPTY; + } + + public static <T> Iterable<T> constant( final T item ) + { + return new Iterable<T>() + { + @Override + public Iterator<T> iterator() + { + return new Iterator<T>() + { + @Override + public boolean hasNext() + { + return true; + } + + @Override + public T next() + { + return item; + } + + @Override + public void remove() + { + } + }; + } + }; + } + + public static <T> Iterable<T> limit( final int limitItems, final Iterable<T> iterable ) + { + return new Iterable<T>() + { + @Override + public Iterator<T> iterator() + { + final Iterator<T> iterator = iterable.iterator(); + + return new Iterator<T>() + { + int count; + + @Override + public boolean hasNext() + { + return count < limitItems && iterator.hasNext(); + } + + @Override + public T next() + { + count++; + return iterator.next(); + } + + @Override + public void remove() + { + iterator.remove(); + } + }; + } + }; + } + + public static <T> Iterable<T> unique( final Iterable<T> iterable ) + { + return new Iterable<T>() + { + @Override + public Iterator<T> iterator() + { + final Iterator<T> iterator = iterable.iterator(); + + return new Iterator<T>() + { + private final Set<T> items = new HashSet<>(); + private T nextItem; + + @Override + public boolean hasNext() + { + while( iterator.hasNext() ) + { + nextItem = iterator.next(); + if( items.add( nextItem ) ) + { + return true; + } + } + + return false; + } + + @Override + public T next() + { + if( nextItem == null && !hasNext() ) + { + throw new NoSuchElementException(); + } + + return nextItem; + } + + @Override + public void remove() + { + } + }; + } + }; + } + + public static <T, C extends Collection<T>> C addAll( C collection, Iterable<? extends T> iterable ) + { + for( T item : iterable ) + { + collection.add( item ); + } + return collection; + } + + public static long count( Iterable<?> iterable ) + { + long c = 0; + for( Object anIterable : iterable ) + { + c++; + } + return c; + } + + @SuppressWarnings( "unchecked" ) + public static <X> Iterable<X> filter( Specification<? /* super X*/> specification, Iterable<X> i ) + { + return new FilterIterable<>( i, (Specification<? super X>) specification ); + } + + public static <X> X first( Iterable<X> i ) + { + Iterator<X> iter = i.iterator(); + if( iter.hasNext() ) + { + return iter.next(); + } + else + { + return null; + } + } + + public static <X> X single( Iterable<X> i ) + { + Iterator<X> iter = i.iterator(); + if( iter.hasNext() ) + { + X result = iter.next(); + + if( iter.hasNext() ) + { + throw new IllegalArgumentException( "More than one element in iterable" ); + } + + return result; + } + else + { + throw new IllegalArgumentException( "No elements in iterable" ); + } + } + + public static <X> Iterable<X> skip( final int skip, final Iterable<X> iterable ) + { + return new Iterable<X>() + { + @Override + public Iterator<X> iterator() + { + Iterator<X> iterator = iterable.iterator(); + + for( int i = 0; i < skip; i++ ) + { + if( iterator.hasNext() ) + { + iterator.next(); + } + else + { + return Iterables.<X>empty().iterator(); + } + } + + return iterator; + } + }; + } + + public static <X> X last( Iterable<X> i ) + { + Iterator<X> iter = i.iterator(); + X item = null; + while( iter.hasNext() ) + { + item = iter.next(); + } + + return item; + } + + public static <X> Iterable<X> reverse( Iterable<X> iterable ) + { + List<X> list = toList( iterable ); + Collections.reverse( list ); + return list; + } + + public static <T> boolean matchesAny( Specification<? super T> specification, Iterable<T> iterable ) + { + boolean result = false; + + for( T item : iterable ) + { + if( ( (Specification<? super T>) specification ).satisfiedBy( item ) ) + { + result = true; + break; + } + } + + return result; + } + + public static <T> boolean matchesAll( Specification<? super T> specification, Iterable<T> iterable ) + { + boolean result = true; + for( T item : iterable ) + { + if( !specification.satisfiedBy( item ) ) + { + result = false; + } + } + + return result; + } + + public static <X> Iterable<X> flatten( Iterable<?>... multiIterator ) + { + return new FlattenIterable<>( Iterables.<Iterable<X>>cast( Arrays.asList( multiIterator ) ) ); + } + + public static <X, I extends Iterable<? extends X>> Iterable<X> flattenIterables( Iterable<I> multiIterator ) + // public static <X> Iterable<X> flattenIterables( Iterable<Iterable<?>> multiIterator ) + { + return new FlattenIterable<>( Iterables.<Iterable<X>>cast( multiIterator ) ); + } + + @SafeVarargs + public static <T> Iterable<T> mix( final Iterable<T>... iterables ) + { + return new Iterable<T>() + { + @Override + public Iterator<T> iterator() + { + final Iterable<Iterator<T>> iterators = toList( map( new Function<Iterable<T>, Iterator<T>>() + { + @Override + public Iterator<T> map( Iterable<T> iterable ) + { + return iterable.iterator(); + } + }, Iterables.iterable( iterables ) ) ); + + return new Iterator<T>() + { + Iterator<Iterator<T>> iterator; + + Iterator<T> iter; + + @Override + public boolean hasNext() + { + for( Iterator<T> iterator : iterators ) + { + if( iterator.hasNext() ) + { + return true; + } + } + + return false; + } + + @Override + public T next() + { + if( iterator == null ) + { + iterator = iterators.iterator(); + } + + while( iterator.hasNext() ) + { + iter = iterator.next(); + + if( iter.hasNext() ) + { + return iter.next(); + } + } + + iterator = null; + + return next(); + } + + @Override + public void remove() + { + if( iter != null ) + { + iter.remove(); + } + } + }; + } + }; + } + + @SuppressWarnings( "unchecked" ) + public static <FROM, TO> Iterable<TO> map( Function<? /* super FROM */, TO> function, Iterable<FROM> from ) + { + return new MapIterable<>( from, (Function<FROM, TO>) function ); + } + + public static <T> Iterable<T> iterable( Enumeration<T> enumeration ) + { + List<T> list = new ArrayList<>(); + while( enumeration.hasMoreElements() ) + { + T item = enumeration.nextElement(); + list.add( item ); + } + + return list; + } + + @SafeVarargs + public static <T> Iterable<T> iterable( T... items ) + { + return Arrays.asList( items ); + } + + @SuppressWarnings( {"raw", "unchecked"} ) + public static <T> Iterable<T> cast( Iterable<?> iterable ) + { + Iterable iter = iterable; + return iter; + } + + public static <FROM, TO> Function<FROM, TO> cast() + { + return new Function<FROM, TO>() + { + @Override + @SuppressWarnings( "unchecked" ) + public TO map( FROM from ) + { + return (TO) from; + } + }; + } + + public static <FROM, TO> TO fold( Function<? super FROM, TO> function, Iterable<? extends FROM> i ) + { + return last( map( function, i ) ); + } + + public static <T> Iterable<T> prepend( final T item, final Iterable<T> iterable ) + { + return new Iterable<T>() + { + @Override + public Iterator<T> iterator() + { + return new Iterator<T>() + { + T first = item; + Iterator<T> iterator; + + @Override + public boolean hasNext() + { + if( first != null ) + { + return true; + } + else + { + if( iterator == null ) + { + iterator = iterable.iterator(); + } + } + + return iterator.hasNext(); + } + + @Override + public T next() + { + if( first != null ) + { + try + { + return first; + } + finally + { + first = null; + } + } + else + { + return iterator.next(); + } + } + + @Override + public void remove() + { + } + }; + } + }; + } + + public static <T> Iterable<T> append( final T item, final Iterable<T> iterable ) + { + return new Iterable<T>() + { + @Override + public Iterator<T> iterator() + { + final Iterator<T> iterator = iterable.iterator(); + + return new Iterator<T>() + { + T last = item; + + @Override + public boolean hasNext() + { + if( iterator.hasNext() ) + { + return true; + } + else + { + return last != null; + } + } + + @Override + public T next() + { + if( iterator.hasNext() ) + { + return iterator.next(); + } + else + { + try + { + return last; + } + finally + { + last = null; + } + } + } + + @Override + public void remove() + { + } + }; + } + }; + } + + @SafeVarargs + public static <T> Iterable<T> debug( String format, + final Iterable<T> iterable, + final Function<T, String>... functions + ) + { + final MessageFormat msgFormat = new MessageFormat( format ); + + return map( new Function<T, T>() + { + @Override + public T map( T t ) + { + if( functions.length != 0 ) + { + String[] mapped = new String[ functions.length ]; + for( int i = 0; i < functions.length; i++ ) + { + Function<T, String> function = functions[i]; + mapped[i] = function.map( t ); + } + } + return t; + } + }, iterable ); + } + + public static <T> Iterable<T> cache( Iterable<T> iterable ) + { + return new CacheIterable<>( iterable ); + } + + public static <T> String toString( Iterable<T> iterable ) + { + return toString( iterable, new Function<T, String>() + { + @Override + public String map( T t ) + { + return t == null ? "[null]" : t.toString(); + } + }, "," ); + } + + public static <T> String toString( Iterable<T> iterable, Function<T, String> toStringFunction, String separator ) + { + StringBuilder builder = new StringBuilder(); + boolean first = true; + for( T item : iterable ) + { + if( !first ) + { + builder.append( separator ); + } + builder.append( toStringFunction.map( item ) ); + first = false; + } + return builder.toString(); + } + + public static <T> List<T> toList( Iterable<T> iterable ) + { + return addAll( new ArrayList<T>(), iterable ); + } + + public static Object[] toArray( Iterable<Object> iterable ) + { + return toArray( Object.class, iterable ); + } + + @SuppressWarnings( "unchecked" ) + public static <T> T[] toArray( Class<T> componentType, Iterable<T> iterable ) + { + if( iterable == null ) + { + return null; + } + List<T> list = toList( iterable ); + return list.toArray( (T[]) Array.newInstance( componentType, list.size() ) ); + } + + @SuppressWarnings( {"raw", "unchecked"} ) + public static <X extends Comparable> Iterable<X> sort( Iterable<X> iterable ) + { + List<X> list = toList( iterable ); + Collections.sort( list ); + return list; + } + + public static <X> Iterable<X> sort( Comparator<? super X> comparator, Iterable<X> iterable ) + { + List<X> list = toList( iterable ); + Collections.sort( list, comparator ); + return list; + } + + private static class MapIterable<FROM, TO> + implements Iterable<TO> + { + private final Iterable<FROM> from; + private final Function<? super FROM, TO> function; + + private MapIterable( Iterable<FROM> from, Function<? super FROM, TO> function ) + { + this.from = from; + this.function = function; + } + + @Override + public Iterator<TO> iterator() + { + return new MapIterator<>( from.iterator(), function ); + } + + static class MapIterator<FROM, TO> + implements Iterator<TO> + { + private final Iterator<FROM> fromIterator; + private final Function<? super FROM, TO> function; + + private MapIterator( Iterator<FROM> fromIterator, Function<? super FROM, TO> function ) + { + this.fromIterator = fromIterator; + this.function = function; + } + + @Override + public boolean hasNext() + { + return fromIterator.hasNext(); + } + + @Override + public TO next() + { + FROM from = fromIterator.next(); + return function.map( from ); + } + + @Override + public void remove() + { + fromIterator.remove(); + } + } + + } + + private static class FilterIterable<T> + implements Iterable<T> + { + private final Iterable<T> iterable; + + private final Specification<? super T> specification; + + private FilterIterable( Iterable<T> iterable, Specification<? super T> specification ) + { + this.iterable = iterable; + this.specification = specification; + } + + @Override + public Iterator<T> iterator() + { + return new FilterIterator<>( iterable.iterator(), specification ); + } + + private static class FilterIterator<T> + implements Iterator<T> + { + private final Iterator<T> iterator; + + private final Specification<? super T> specification; + + private T currentValue; + boolean finished = false; + boolean nextConsumed = true; + + private FilterIterator( Iterator<T> iterator, Specification<? super T> specification ) + { + this.specification = specification; + this.iterator = iterator; + } + + public boolean moveToNextValid() + { + boolean found = false; + while( !found && iterator.hasNext() ) + { + T currentValue = iterator.next(); + boolean satisfies = specification.satisfiedBy( currentValue ); + + if( satisfies ) + { + found = true; + this.currentValue = currentValue; + nextConsumed = false; + } + } + if( !found ) + { + finished = true; + } + return found; + } + + @Override + public T next() + { + if( !nextConsumed ) + { + nextConsumed = true; + return currentValue; + } + else + { + if( !finished ) + { + if( moveToNextValid() ) + { + nextConsumed = true; + return currentValue; + } + } + } + return null; + } + + @Override + public boolean hasNext() + { + return !finished + && ( !nextConsumed || moveToNextValid() ); + } + + @Override + public void remove() + { + } + } + + } + + private static class FlattenIterable<T, I extends Iterable<? extends T>> + implements Iterable<T> + { + private final Iterable<I> iterable; + + private FlattenIterable( Iterable<I> iterable ) + { + this.iterable = iterable; + } + + @Override + public Iterator<T> iterator() + { + return new FlattenIterator<>( iterable.iterator() ); + } + + static class FlattenIterator<T, I extends Iterable<? extends T>> + implements Iterator<T> + { + private final Iterator<I> iterator; + private Iterator<? extends T> currentIterator; + + private FlattenIterator( Iterator<I> iterator ) + { + this.iterator = iterator; + currentIterator = null; + } + + @Override + public boolean hasNext() + { + if( currentIterator == null ) + { + if( iterator.hasNext() ) + { + I next = iterator.next(); + currentIterator = next.iterator(); + } + else + { + return false; + } + } + + while( !currentIterator.hasNext() + && iterator.hasNext() ) + { + currentIterator = iterator.next().iterator(); + } + + return currentIterator.hasNext(); + } + + @Override + public T next() + { + return currentIterator.next(); + } + + @Override + public void remove() + { + if( currentIterator == null ) + { + throw new IllegalStateException(); + } + + currentIterator.remove(); + } + } + + } + + private static class CacheIterable<T> + implements Iterable<T> + { + private final Iterable<T> iterable; + private Iterable<T> cache; + + private CacheIterable( Iterable<T> iterable ) + { + this.iterable = iterable; + } + + @Override + public Iterator<T> iterator() + { + if( cache != null ) + { + return cache.iterator(); + } + + final Iterator<T> source = iterable.iterator(); + + return new Iterator<T>() + { + List<T> iteratorCache = new ArrayList<>(); + + @Override + public boolean hasNext() + { + boolean hasNext = source.hasNext(); + if( !hasNext ) + { + cache = iteratorCache; + } + return hasNext; + } + + @Override + public T next() + { + T next = source.next(); + iteratorCache.add( next ); + return next; + } + + @Override + public void remove() + { + + } + }; + } + } + + private Iterables() + { + } + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/Specification.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/Specification.java b/core/functional/src/main/java/org/qi4j/functional/Specification.java new file mode 100644 index 0000000..93c61a9 --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/Specification.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010, Rickard Ãberg. All Rights Reserved. + * + * 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.qi4j.functional; + +/** + * Generic specification interface. + * + * @param <T> + */ +// START SNIPPET: specification +public interface Specification<T> +{ +// END SNIPPET: specification + + /** + * Test whether an item matches the given specification + * + * @param item the item to be tested + * + * @return true if the item matches, false otherwise + */ +// START SNIPPET: specification + boolean satisfiedBy( T item ); +} +// END SNIPPET: specification http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/Specifications.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/Specifications.java b/core/functional/src/main/java/org/qi4j/functional/Specifications.java new file mode 100644 index 0000000..7635579 --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/Specifications.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2010, Rickard Ãberg. All Rights Reserved. + * + * 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.qi4j.functional; + +/** + * Common generic specification expressions + */ +public class Specifications +{ + public static <T> Specification<T> TRUE() + { + return new Specification<T>() + { + @Override + public boolean satisfiedBy( T instance ) + { + return true; + } + }; + } + + public static <T> Specification<T> not( final Specification<T> specification ) + { + return new Specification<T>() + { + @Override + public boolean satisfiedBy( T instance ) + { + return !specification.satisfiedBy( instance ); + } + }; + } + + @SafeVarargs + public static <T> AndSpecification<T> and( final Specification<T>... specifications ) + { + return and( Iterables.iterable( specifications ) ); + } + + public static <T> AndSpecification<T> and( final Iterable<Specification<T>> specifications ) + { + return new AndSpecification<>( specifications ); + } + + @SafeVarargs + public static <T> OrSpecification<T> or( final Specification<T>... specifications ) + { + return or( Iterables.iterable( specifications ) ); + } + + public static <T> OrSpecification<T> or( final Iterable<Specification<T>> specifications ) + { + return new OrSpecification<>( specifications ); + } + + @SafeVarargs + public static <T> Specification<T> in( final T... allowed ) + { + return in( Iterables.iterable( allowed ) ); + } + + public static <T> Specification<T> in( final Iterable<T> allowed ) + { + return new Specification<T>() + { + @Override + public boolean satisfiedBy( T item ) + { + for( T allow : allowed ) + { + if( allow.equals( item ) ) + { + return true; + } + } + return false; + } + }; + } + + public static <T> Specification<T> notNull() + { + return new Specification<T>() + { + @Override + public boolean satisfiedBy( T item ) + { + return item != null; + } + }; + } + + public static <FROM, TO> Specification<FROM> translate( final Function<FROM, TO> function, + final Specification<? super TO> specification + ) + { + return new Specification<FROM>() + { + @Override + public boolean satisfiedBy( FROM item ) + { + return specification.satisfiedBy( function.map( item ) ); + } + }; + } + + /** + * AND Specification. + */ + public static class AndSpecification<T> + implements Specification<T> + { + private final Iterable<Specification<T>> specifications; + + private AndSpecification( Iterable<Specification<T>> specifications ) + { + this.specifications = specifications; + } + + @Override + public boolean satisfiedBy( T instance ) + { + for( Specification<T> specification : specifications ) + { + if( !specification.satisfiedBy( instance ) ) + { + return false; + } + } + + return true; + } + + @SafeVarargs + public final AndSpecification<T> and( Specification<T>... specifications ) + { + Iterable<Specification<T>> iterable = Iterables.iterable( specifications ); + Iterable<Specification<T>> flatten = Iterables.flatten( this.specifications, iterable ); + return Specifications.and( flatten ); + } + + @SafeVarargs + public final OrSpecification<T> or( Specification<T>... specifications ) + { + return Specifications.or( Iterables.prepend( this, Iterables.iterable( specifications ) ) ); + } + } + + /** + * OR Specification. + */ + public static class OrSpecification<T> + implements Specification<T> + { + private final Iterable<Specification<T>> specifications; + + private OrSpecification( Iterable<Specification<T>> specifications ) + { + this.specifications = specifications; + } + + @Override + public boolean satisfiedBy( T instance ) + { + for( Specification<T> specification : specifications ) + { + if( specification.satisfiedBy( instance ) ) + { + return true; + } + } + + return false; + } + + @SafeVarargs + public final AndSpecification<T> and( Specification<T>... specifications ) + { + return Specifications.and( Iterables.prepend( this, Iterables.iterable( specifications ) ) ); + } + + @SafeVarargs + public final OrSpecification<T> or( Specification<T>... specifications ) + { + Iterable<Specification<T>> iterable = Iterables.iterable( specifications ); + Iterable<Specification<T>> flatten = Iterables.flatten( this.specifications, iterable ); + return Specifications.or( flatten ); + } + } + + private Specifications() + { + } + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/Visitable.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/Visitable.java b/core/functional/src/main/java/org/qi4j/functional/Visitable.java new file mode 100644 index 0000000..b1ed8ba --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/Visitable.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.qi4j.functional; + +/** + * Interface that visitable objects should implement. + */ +public interface Visitable<T> +{ + <ThrowableType extends Throwable> boolean accept( Visitor<? super T, ThrowableType> visitor ) + throws ThrowableType; +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/VisitableHierarchy.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/VisitableHierarchy.java b/core/functional/src/main/java/org/qi4j/functional/VisitableHierarchy.java new file mode 100644 index 0000000..fe37d1f --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/VisitableHierarchy.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.qi4j.functional; + +/** + * Interface that visitable hierarchies of objects should implement. + */ +public interface VisitableHierarchy<NODE, LEAF> +{ + <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super NODE, ? super LEAF, ThrowableType> visitor ) + throws ThrowableType; +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/Visitor.java ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/Visitor.java b/core/functional/src/main/java/org/qi4j/functional/Visitor.java new file mode 100644 index 0000000..3cf6005 --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/Visitor.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.qi4j.functional; + +/** + * Generic Visitor interface. + */ +public interface Visitor<T, ThrowableType extends Throwable> +{ + /** + * Visit an instance of T + * + * @param visited the visited instance + * + * @return true if the visitor pattern should continue, false if it should be aborted + * + * @throws ThrowableType if an exception occurred during processing. Any client call that initiated the visiting should + * get the exception in order to handle it properly. + */ + boolean visit( T visited ) + throws ThrowableType; +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/main/java/org/qi4j/functional/package.html ---------------------------------------------------------------------- diff --git a/core/functional/src/main/java/org/qi4j/functional/package.html b/core/functional/src/main/java/org/qi4j/functional/package.html new file mode 100644 index 0000000..920a9ef --- /dev/null +++ b/core/functional/src/main/java/org/qi4j/functional/package.html @@ -0,0 +1,21 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You 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. +--> +<html> + <body> + <h2>Functional API.</h2> + </body> +</html> http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/test/java/org/apache/zest/functional/FunctionsTest.java ---------------------------------------------------------------------- diff --git a/core/functional/src/test/java/org/apache/zest/functional/FunctionsTest.java b/core/functional/src/test/java/org/apache/zest/functional/FunctionsTest.java deleted file mode 100644 index 0c9ea0f..0000000 --- a/core/functional/src/test/java/org/apache/zest/functional/FunctionsTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.zest.functional; - -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.apache.zest.functional.ForEach.forEach; -import static org.apache.zest.functional.Functions.compose; -import static org.apache.zest.functional.Functions.count; -import static org.apache.zest.functional.Functions.indexOf; -import static org.apache.zest.functional.Functions.intSum; -import static org.apache.zest.functional.Functions.longSum; -import static org.apache.zest.functional.Iterables.iterable; -import static org.apache.zest.functional.Iterables.last; -import static org.apache.zest.functional.Iterables.map; -import static org.apache.zest.functional.Specifications.in; - -/** - * Test of utility functions - */ -public class FunctionsTest -{ - Function<Object, String> stringifier = new Function<Object, String>() - { - @Override - public String map( Object s ) - { - return s.toString(); - } - }; - - Function<String, Integer> length = new Function<String, Integer>() - { - @Override - public Integer map( String s ) - { - return s.length(); - } - }; - - @Test - public void testCompose() - { - assertThat( Functions.<Object, String, Integer>compose() - .map( length, stringifier ) - .map( 12345L ), equalTo( 5 ) ); - assertThat( compose( length, stringifier ).map( 12345L ), equalTo( 5 ) ); - } - - @Test - public void testFromMap() - { - Map<String, String> map = new HashMap<String, String>(); - map.put( "A", "1" ); - map.put( "B", "2" ); - map.put( "C", "3" ); - assertThat( Iterables.toList( Iterables.filter( Specifications.notNull(), Iterables.map( Functions.fromMap( map ), Iterables - .iterable( "A", "B", "D" ) ) ) ).toString(), equalTo( "[1, 2]" ) ); - } - - @Test - public void testWithDefault() - { - assertThat( Iterables.toList( Iterables.map( Functions.withDefault( "DEFAULT" ), Iterables.iterable( "123", null, "456" ) ) ) - .toString(), equalTo( "[123, DEFAULT, 456]" ) ); - } - - @Test - public void testLongSum() - { - assertThat( last( map( longSum(), iterable( 1, 2L, 3F, 4D ) ) ), equalTo( 10L ) ); - } - - @Test - public void testLongSum2() - { - assertThat( forEach( iterable( 1, 2, 3, 4 ) ).map( longSum() ).last(), equalTo( 10L ) ); - } - - @Test - public void testIntSum() - { - assertThat( last( map( intSum(), iterable( 1, 2L, 3F, 4D ) ) ), equalTo( 10 ) ); - } - - @Test - public void testCount() - { - assertThat( last( map( count( in( "X" ) ), iterable( "X", "Y", "X", "X", "Y" ) ) ), equalTo( 3 ) ); - } - - @Test - public void testIndexOf() - { - assertThat( last( map( indexOf( in( "D" ) ), iterable( "A", "B", "C", "D", "D" ) ) ), equalTo( 3 ) ); - } - - @Test - public void testIndexOf2() - { - assertThat( indexOf( "D", iterable( "A", "B", "C", "D", "D" ) ), equalTo( 3 ) ); - } - - @Test - public void testComparator() - { - Comparator<Integer> comparator = Functions.comparator( new Function<Integer, Comparable>() - { - @Override - public Comparable map( Integer integer ) - { - return integer.toString(); - } - } ); - Iterable<Integer> iterable = Iterables.iterable( 1, 5, 3, 6, 8 ); - List<Integer> integers = Iterables.toList( iterable ); - Collections.sort( integers, comparator ); - assertThat( integers.toString(), equalTo( "[1, 3, 5, 6, 8]" ) ); - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/test/java/org/apache/zest/functional/IntegerRangeSpecificationTest.java ---------------------------------------------------------------------- diff --git a/core/functional/src/test/java/org/apache/zest/functional/IntegerRangeSpecificationTest.java b/core/functional/src/test/java/org/apache/zest/functional/IntegerRangeSpecificationTest.java deleted file mode 100644 index fa082fe..0000000 --- a/core/functional/src/test/java/org/apache/zest/functional/IntegerRangeSpecificationTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012, Niclas Hedhman. All Rights Reserved. - * - * 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.zest.functional; - -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -// This test exist primarily for the documentation. Don't remove. -public class IntegerRangeSpecificationTest -{ - @Test - public void test1() - { - Specification<Integer> spec = new IntegerRangeSpecification( 10, 12 ); - assertTrue( spec.satisfiedBy( 10 ) ); - assertTrue( spec.satisfiedBy( 11 ) ); - assertTrue( spec.satisfiedBy( 12 ) ); - assertFalse( spec.satisfiedBy( 9 ) ); - assertFalse( spec.satisfiedBy( 13 ) ); - } - - // START SNIPPET: specification - public static class IntegerRangeSpecification - implements Specification<Integer> - { - - private int lower; - private int higher; - - public IntegerRangeSpecification( int lower, int higher ) - { - this.lower = lower; - this.higher = higher; - } - - @Override - public boolean satisfiedBy( Integer item ) - { - return item >= lower && item <= higher; - } - } - // END SNIPPET: specification -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/test/java/org/apache/zest/functional/IterablesTest.java ---------------------------------------------------------------------- diff --git a/core/functional/src/test/java/org/apache/zest/functional/IterablesTest.java b/core/functional/src/test/java/org/apache/zest/functional/IterablesTest.java deleted file mode 100644 index e970666..0000000 --- a/core/functional/src/test/java/org/apache/zest/functional/IterablesTest.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2010, Rickard Ãberg. All Rights Reserved. - * - * 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.zest.functional; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.List; -import org.hamcrest.CoreMatchers; -import org.junit.Test; - -import static java.util.Collections.*; -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.assertThat; - -/** - * Test of Iterables utility methods - */ -public class IterablesTest -{ - - private List<String> numbers = Arrays.asList( "1", "2", "3" ); - private Iterable<Long> numberLongs = Arrays.asList( 1L, 2L, 3L ); - private Iterable<Integer> numberIntegers = Arrays.asList( 1, 2, 3 ); - - @Test - public void testConstant() - { - String str = ""; - - for( String string : Iterables.limit( 3, Iterables.constant( "123" ) ) ) - { - str += string; - } - - assertThat( str, CoreMatchers.equalTo( "123123123" ) ); - } - - @Test - public void testUnique() - { - String str = ""; - - for( String string : Iterables.unique( Iterables.<String>flatten( numbers, numbers, numbers ) ) ) - { - str += string; - } - assertThat( str, CoreMatchers.equalTo( "123" ) ); - } - - @Test - public void testAddAll() - { - List<String> strings = Iterables.toList( numbers ); - assertThat( strings.toString(), equalTo( "[1, 2, 3]" ) ); - assertThat( Iterables.toList( numberLongs ).toString(), equalTo( "[1, 2, 3]" ) ); - } - - @Test - public void testCount() - { - assertThat( Iterables.count( numbers ), equalTo( 3L ) ); - } - - @Test - public void testFilter() - { - assertThat( Iterables.first( Iterables.filter( Specifications.in( "2" ), numbers ) ), equalTo( "2" ) ); - } - - @Test - public void testFirst() - { - assertThat( Iterables.first( numbers ), equalTo( "1" ) ); - assertThat( Iterables.first( emptyList() ), nullValue() ); - } - - @Test - public void testLast() - { - assertThat( Iterables.last( numbers ), equalTo( "3" ) ); - assertThat( Iterables.last( emptyList() ), nullValue() ); - } - - @Test - public void testFolding() - { - assertThat( Iterables.fold( new Function<Integer, Integer>() - { - - int sum = 0; - - @Override - public Integer map( Integer number ) - { - return sum += number; - } - - }, numberIntegers ), equalTo( 6 ) ); - } - - @Test - public void testAppend() - { - assertThat( Iterables.toList( Iterables.append( "C", Iterables.iterable( "A", "B" ) ) ).toString(), - equalTo( "[A, B, C]" ) ); - } - - @Test - public void testReverse() - { - assertThat( Iterables.reverse( numbers ).toString(), equalTo( "[3, 2, 1]" ) ); - assertThat( Iterables.reverse( emptyList() ), equalTo( (Object) emptyList() ) ); - } - - @Test - public void testMatchesAny() - { - assertThat( Iterables.matchesAny( Specifications.in( "2" ), numbers ), equalTo( true ) ); - assertThat( Iterables.matchesAny( Specifications.in( "4" ), numbers ), equalTo( false ) ); - } - - @Test - public void testMatchesAll() - { - assertThat( Iterables.matchesAll( Specifications.in( "1", "2", "3" ), numbers ), equalTo( true ) ); - assertThat( Iterables.matchesAll( Specifications.in( "2", "3", "4" ), numbers ), equalTo( false ) ); - } - - @Test - public void testFlatten() - { - assertThat( Iterables.toList( Iterables.flatten( numbers, numbers ) ).toString(), - equalTo( "[1, 2, 3, 1, 2, 3]" ) ); - - Iterable<? extends Number> flatten = Iterables.flatten( numberIntegers, numberLongs ); - assertThat( Iterables.toList( flatten ).toString(), equalTo( "[1, 2, 3, 1, 2, 3]" ) ); - } - - @Test - public void testFlattenIterables() - { - Iterable<List<String>> iterable = Iterables.iterable( numbers, numbers ); - assertThat( Iterables.toList( Iterables.flattenIterables( iterable ) ).toString(), - equalTo( "[1, 2, 3, 1, 2, 3]" ) ); - } - - @Test - public void testMix() - { - assertThat( Iterables.toList( Iterables.mix( Iterables.iterable( "A", "B", "C" ), - Iterables.iterable( "1", "2", "3", "4", "5" ), - Iterables.iterable( "X", "Y", "Z" ) ) ).toString(), - equalTo( "[A, 1, X, B, 2, Y, C, 3, Z, 4, 5]" ) ); - } - - @Test - public void testMap() - { - assertThat( Iterables.toList( Iterables.map( new Function<String, String>() - { - - public String map( String s ) - { - return s + s; - } - - }, numbers ) ).toString(), equalTo( "[11, 22, 33]" ) ); - - Iterable<List<String>> numberIterable = Iterables.iterable( numbers, numbers, numbers ); - assertThat( Iterables.toList( Iterables.map( new Function<Collection, Integer>() - { - - @Override - public Integer map( Collection collection ) - { - return collection.size(); - } - - }, numberIterable ) ).toString(), equalTo( "[3, 3, 3]" ) ); - } - - @Test - public void testIterableEnumeration() - { - - Enumeration<String> enumeration = enumeration( numbers ); - assertThat( Iterables.toList( Iterables.iterable( enumeration ) ).toString(), - equalTo( "[1, 2, 3]" ) ); - } - - @Test - public void testIterableVarArg() - { - assertThat( Iterables.toList( Iterables.iterable( "1", "2", "3" ) ).toString(), - equalTo( "[1, 2, 3]" ) ); - } - - @Test - public void testCast() - { - Iterable<Long> values = numberLongs; - Iterable<Number> numbers = Iterables.cast( values ); - } - - @Test - public void testDebug() - { - assertThat( Iterables.first( Iterables.debug( "Filtered number:{0}", - Iterables.filter( Specifications.in( "2" ), - Iterables.debug( "Number:{0}", numbers ) ) ) ), - equalTo( "2" ) ); - } - - @Test - public void testDebugWithFunctions() - { - Function<String, String> fun = new Function<String, String>() - { - - @Override - public String map( String s ) - { - return s + ":" + s.length(); - } - - }; - assertThat( Iterables.first( Iterables.debug( "Filtered number:{0}", - Iterables.filter( Specifications.in( "2" ), - Iterables.debug( "Number:{0}", numbers, fun ) ) ) ), - equalTo( "2" ) ); - } - - @Test - public void testCache() - { - final int[] count = new int[ 1 ]; - - Iterable<String> b = Iterables.cache( Iterables.filter( Specifications.and( new Specification<String>() - { - - @Override - public boolean satisfiedBy( String item ) - { - count[ 0] = count[ 0] + 1; - return true; - } - - }, Specifications.in( "B" ) ), Iterables.iterable( "A", "B", "C" ) ) ); - - assertThat( count[ 0], equalTo( 0 ) ); - - Iterables.toList( b ); - - assertThat( count[ 0], equalTo( 3 ) ); - - Iterables.toList( b ); - - assertThat( count[ 0], equalTo( 3 ) ); - } - - @Test - public void testSort() - { - assertThat( Iterables.sort( Iterables.reverse( numberLongs ) ).toString(), equalTo( "[1, 2, 3]" ) ); - - Comparator<Long> inverseLongComparator = new Comparator<Long>() - { - - @Override - public int compare( Long left, Long right ) - { - return left.compareTo( right ) * -1; - } - - }; - assertThat( Iterables.sort( inverseLongComparator, numberLongs ).toString(), equalTo( "[3, 2, 1]" ) ); - } - -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/test/java/org/apache/zest/functional/SpecificationsTest.java ---------------------------------------------------------------------- diff --git a/core/functional/src/test/java/org/apache/zest/functional/SpecificationsTest.java b/core/functional/src/test/java/org/apache/zest/functional/SpecificationsTest.java deleted file mode 100644 index 7a1601d..0000000 --- a/core/functional/src/test/java/org/apache/zest/functional/SpecificationsTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2010, Rickard Ãberg. All Rights Reserved. - * - * 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.zest.functional; - -import org.junit.Assert; -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.equalTo; - -/** - * JAVADOC - */ -public class SpecificationsTest -{ - @Test - public void testTRUE() - { - Assert.assertThat( Specifications.<Object>TRUE().satisfiedBy( new Object() ), equalTo( true ) ); - } - - @Test - public void testNot() - { - Assert.assertThat( Specifications.not( Specifications.<Object>TRUE() ) - .satisfiedBy( new Object() ), equalTo( false ) ); - } - - @Test - public void testAnd() - { - Specification<Object> trueSpec = Specifications.<Object>TRUE(); - Specification<Object> falseSpec = Specifications.not( Specifications.<Object>TRUE() ); - - Assert.assertThat( Specifications.and( falseSpec, falseSpec ).satisfiedBy( new Object() ), equalTo( false ) ); - Assert.assertThat( Specifications.and( trueSpec, falseSpec ).satisfiedBy( new Object() ), equalTo( false ) ); - Assert.assertThat( Specifications.and( falseSpec, trueSpec ).satisfiedBy( new Object() ), equalTo( false ) ); - Assert.assertThat( Specifications.and( trueSpec, trueSpec ).satisfiedBy( new Object() ), equalTo( true ) ); - } - - @Test - public void testOr() - { - Specification<Object> trueSpec = Specifications.<Object>TRUE(); - Specification<Object> falseSpec = Specifications.not( Specifications.<Object>TRUE() ); - - Assert.assertThat( Specifications.or( falseSpec, falseSpec ).satisfiedBy( new Object() ), equalTo( false ) ); - Assert.assertThat( Specifications.or( trueSpec, falseSpec ).satisfiedBy( new Object() ), equalTo( true ) ); - Assert.assertThat( Specifications.or( falseSpec, trueSpec ).satisfiedBy( new Object() ), equalTo( true ) ); - Assert.assertThat( Specifications.or( trueSpec, trueSpec ).satisfiedBy( new Object() ), equalTo( true ) ); - } - - @Test - public void testIn() - { - Assert.assertThat( Specifications.in( "1", "2", "3" ).satisfiedBy( "2" ), equalTo( true ) ); - Assert.assertThat( Specifications.in( "1", "2", "3" ).satisfiedBy( "4" ), equalTo( false ) ); - } - - @Test - public void testTranslate() - { - Function<Object, String> stringifier = new Function<Object, String>() - { - @Override - public String map( Object s ) - { - return s.toString(); - } - }; - - Assert.assertTrue( Specifications.translate( stringifier, Specifications.in( "3" ) ).satisfiedBy( 3L ) ); - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/test/java/org/apache/zest/functional/docsupport/FunctionalDocs.java ---------------------------------------------------------------------- diff --git a/core/functional/src/test/java/org/apache/zest/functional/docsupport/FunctionalDocs.java b/core/functional/src/test/java/org/apache/zest/functional/docsupport/FunctionalDocs.java deleted file mode 100644 index 12a218d..0000000 --- a/core/functional/src/test/java/org/apache/zest/functional/docsupport/FunctionalDocs.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.zest.functional.docsupport; - -import java.util.ArrayList; - -// START SNIPPET: func2 -import static org.apache.zest.functional.ForEach.forEach; -import static org.apache.zest.functional.Functions.longSum; -// END SNIPPET: func2 - -public class FunctionalDocs -{ - public static void main( String[] args ) - { - { -// START SNIPPET: func1 - Iterable<Long> data = new ArrayList<Long>(); -// END SNIPPET: func1 -// START SNIPPET: func1 - - long sum = 0; - for( Long point : data ) - { - sum = sum + point; - } - System.out.println( "The sum is " + sum ); -// END SNIPPET: func1 - } - { -// START SNIPPET: func2 - Iterable<Number> data = new ArrayList<Number>(); - Long sum = forEach( data ).map( longSum() ).last(); - System.out.println( "The sum is " + sum ); - -// END SNIPPET: func2 - } - } -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/test/java/org/qi4j/functional/FunctionsTest.java ---------------------------------------------------------------------- diff --git a/core/functional/src/test/java/org/qi4j/functional/FunctionsTest.java b/core/functional/src/test/java/org/qi4j/functional/FunctionsTest.java new file mode 100644 index 0000000..a5e1956 --- /dev/null +++ b/core/functional/src/test/java/org/qi4j/functional/FunctionsTest.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.qi4j.functional; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.qi4j.functional.ForEach.forEach; +import static org.qi4j.functional.Functions.compose; +import static org.qi4j.functional.Functions.count; +import static org.qi4j.functional.Functions.indexOf; +import static org.qi4j.functional.Functions.intSum; +import static org.qi4j.functional.Functions.longSum; +import static org.qi4j.functional.Iterables.iterable; +import static org.qi4j.functional.Iterables.last; +import static org.qi4j.functional.Iterables.map; +import static org.qi4j.functional.Specifications.in; + +/** + * Test of utility functions + */ +public class FunctionsTest +{ + Function<Object, String> stringifier = new Function<Object, String>() + { + @Override + public String map( Object s ) + { + return s.toString(); + } + }; + + Function<String, Integer> length = new Function<String, Integer>() + { + @Override + public Integer map( String s ) + { + return s.length(); + } + }; + + @Test + public void testCompose() + { + assertThat( Functions.<Object, String, Integer>compose() + .map( length, stringifier ) + .map( 12345L ), equalTo( 5 ) ); + assertThat( compose( length, stringifier ).map( 12345L ), equalTo( 5 ) ); + } + + @Test + public void testFromMap() + { + Map<String, String> map = new HashMap<String, String>(); + map.put( "A", "1" ); + map.put( "B", "2" ); + map.put( "C", "3" ); + assertThat( Iterables.toList( Iterables.filter( Specifications.notNull(), Iterables.map( Functions.fromMap( map ), Iterables + .iterable( "A", "B", "D" ) ) ) ).toString(), equalTo( "[1, 2]" ) ); + } + + @Test + public void testWithDefault() + { + assertThat( Iterables.toList( Iterables.map( Functions.withDefault( "DEFAULT" ), Iterables.iterable( "123", null, "456" ) ) ) + .toString(), equalTo( "[123, DEFAULT, 456]" ) ); + } + + @Test + public void testLongSum() + { + assertThat( last( map( longSum(), iterable( 1, 2L, 3F, 4D ) ) ), equalTo( 10L ) ); + } + + @Test + public void testLongSum2() + { + assertThat( forEach( iterable( 1, 2, 3, 4 ) ).map( longSum() ).last(), equalTo( 10L ) ); + } + + @Test + public void testIntSum() + { + assertThat( last( map( intSum(), iterable( 1, 2L, 3F, 4D ) ) ), equalTo( 10 ) ); + } + + @Test + public void testCount() + { + assertThat( last( map( count( in( "X" ) ), iterable( "X", "Y", "X", "X", "Y" ) ) ), equalTo( 3 ) ); + } + + @Test + public void testIndexOf() + { + assertThat( last( map( indexOf( in( "D" ) ), iterable( "A", "B", "C", "D", "D" ) ) ), equalTo( 3 ) ); + } + + @Test + public void testIndexOf2() + { + assertThat( indexOf( "D", iterable( "A", "B", "C", "D", "D" ) ), equalTo( 3 ) ); + } + + @Test + public void testComparator() + { + Comparator<Integer> comparator = Functions.comparator( new Function<Integer, Comparable>() + { + @Override + public Comparable map( Integer integer ) + { + return integer.toString(); + } + } ); + Iterable<Integer> iterable = Iterables.iterable( 1, 5, 3, 6, 8 ); + List<Integer> integers = Iterables.toList( iterable ); + Collections.sort( integers, comparator ); + assertThat( integers.toString(), equalTo( "[1, 3, 5, 6, 8]" ) ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/a789141d/core/functional/src/test/java/org/qi4j/functional/IntegerRangeSpecificationTest.java ---------------------------------------------------------------------- diff --git a/core/functional/src/test/java/org/qi4j/functional/IntegerRangeSpecificationTest.java b/core/functional/src/test/java/org/qi4j/functional/IntegerRangeSpecificationTest.java new file mode 100644 index 0000000..d29b24b --- /dev/null +++ b/core/functional/src/test/java/org/qi4j/functional/IntegerRangeSpecificationTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, Niclas Hedhman. All Rights Reserved. + * + * 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.qi4j.functional; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +// This test exist primarily for the documentation. Don't remove. +public class IntegerRangeSpecificationTest +{ + @Test + public void test1() + { + Specification<Integer> spec = new IntegerRangeSpecification( 10, 12 ); + assertTrue( spec.satisfiedBy( 10 ) ); + assertTrue( spec.satisfiedBy( 11 ) ); + assertTrue( spec.satisfiedBy( 12 ) ); + assertFalse( spec.satisfiedBy( 9 ) ); + assertFalse( spec.satisfiedBy( 13 ) ); + } + + // START SNIPPET: specification + public static class IntegerRangeSpecification + implements Specification<Integer> + { + + private int lower; + private int higher; + + public IntegerRangeSpecification( int lower, int higher ) + { + this.lower = lower; + this.higher = higher; + } + + @Override + public boolean satisfiedBy( Integer item ) + { + return item >= lower && item <= higher; + } + } + // END SNIPPET: specification +}
