/*
* Copyright 2009 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.gradle.api.specs;
import groovy.lang.Closure;
import org.gradle.api.specs.internal.ClosureSpec;
import org.gradle.internal.Cast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Provides a number of {@link org.gradle.api.specs.Spec} implementations.
*/
public class Specs {
public static final Spec<Object> SATISFIES_ALL = new Spec<Object>() {
public boolean isSatisfiedBy(Object element) {
return true;
}
};
public static <T> Spec<T> satisfyAll() {
return Cast.uncheckedCast(SATISFIES_ALL);
}
public static final Spec<Object> SATISFIES_NONE = new Spec<Object>() {
public boolean isSatisfiedBy(Object element) {
return false;
}
};
public static <T> Spec<T> satisfyNone() {
return Cast.uncheckedCast(SATISFIES_NONE);
}
public static <T> Spec<T> convertClosureToSpec(final Closure closure) {
return new ClosureSpec<T>(closure);
}
/**
* Returns a spec that selects the intersection of those items selected by the given specs. Returns a spec that selects everything when no specs provided.
*/
public static <T> Spec<T> intersect(Spec<? super T>... specs) {
if (specs.length == 0) {
return satisfyAll();
}
if (specs.length == 1) {
return Cast.uncheckedCast(specs[0]);
}
return doIntersect(Arrays.asList(specs));
}
/**
* Returns a spec that selects the intersection of those items selected by the given specs. Returns a spec that selects everything when no specs provided.
*/
public static <T> Spec<T> intersect(Collection<? extends Spec<? super T>> specs) {
if (specs.size() == 0) {
return satisfyAll();
}
return doIntersect(specs);
}
private static <T> Spec<T> doIntersect(Collection<? extends Spec<? super T>> specs) {
List<Spec<? super T>> filtered = new ArrayList<Spec<? super T>>(specs.size());
for (Spec<? super T> spec : specs) {
if (spec == SATISFIES_NONE) {
return satisfyNone();
}
if (spec != SATISFIES_ALL) {
filtered.add(spec);
}
}
if (filtered.size() == 0) {
return satisfyAll();
}
if (filtered.size() == 1) {
return Cast.uncheckedCast(filtered.get(0));
}
return new AndSpec<T>(filtered);
}
/**
* Returns a spec that selects the union of those items selected by the provided spec. Selects everything when no specs provided.
*/
public static <T> Spec<T> union(Spec<? super T>... specs) {
if (specs.length == 0) {
return satisfyAll();
}
if (specs.length == 1) {
return Cast.uncheckedCast(specs[0]);
}
return doUnion(Arrays.asList(specs));
}
/**
* Returns a spec that selects the union of those items selected by the provided spec. Selects everything when no specs provided.
*/
public static <T> Spec<T> union(Collection<? extends Spec<? super T>> specs) {
if (specs.size() == 0) {
return satisfyAll();
}
return doUnion(specs);
}
private static <T> Spec<T> doUnion(Collection<? extends Spec<? super T>> specs) {
List<Spec<? super T>> filtered = new ArrayList<Spec<? super T>>(specs.size());
for (Spec<? super T> spec : specs) {
if (spec == SATISFIES_ALL) {
return satisfyAll();
}
if (spec != SATISFIES_NONE) {
filtered.add(spec);
}
}
if (filtered.size() == 0) {
return satisfyNone();
}
if (filtered.size() == 1) {
return Cast.uncheckedCast(filtered.get(0));
}
return new OrSpec<T>(filtered);
}
/**
* Returns a spec that selects everything that is not selected by the given spec.
*/
public static <T> Spec<T> negate(Spec<? super T> spec) {
if (spec == SATISFIES_ALL) {
return satisfyNone();
}
if (spec == SATISFIES_NONE) {
return satisfyAll();
}
if (spec instanceof NotSpec) {
NotSpec<? super T> notSpec = (NotSpec<? super T>) spec;
return Cast.uncheckedCast(notSpec.getSourceSpec());
}
return new NotSpec<T>(spec);
}
}