results of their comparison to other resources. Inspired by userlist thread http://marc.theaimsgroup.com/?t=115998761500004&r=1&w=2 . Still lacks an example other than testcases. :( git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@454842 13f79535-47bb-0310-9956-ffa450edef68master
@@ -66,6 +66,9 @@ Other changes: | |||
* Added <tokens> resource collection for convenient creation of string | |||
resources from other resources' content. Inspired by Bugzilla 40504. | |||
* Added <compare> resource selector to select resources based on the | |||
results of their comparison to other resources. | |||
Changes from Ant 1.7.0Beta1 to Ant 1.7.0Beta2 | |||
============================================= | |||
@@ -463,6 +463,8 @@ platforms. | |||
containing a particular text string.</li> | |||
<li><a href="selectors.html#regexpselect">containsregexp</a> - select | |||
resources whose contents match a particular regular expression.</li> | |||
<li><a href="#rsel.compare">compare</a> - select resources | |||
based on comparison to other resources.</li> | |||
</ul> | |||
<h4><a name="rsel.name">name</a></h4> | |||
@@ -621,12 +623,40 @@ platforms. | |||
</tr> | |||
</table> | |||
<h4><a name="rsel.compare">compare</a></h4> | |||
<p>Selects a resource based on its comparison to one or more "control" | |||
resources using nested <a href="#rcmp">resource comparators</a>.</p> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">when</td> | |||
<td valign="top">Comparison ("equal"/"eq", "greater"/"gt", "less"/"lt", | |||
"le" (less or equal), "ge" (greater or equal), "ne" (not equal).</td> | |||
<td valign="top">No, default "equal"</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">against</td> | |||
<td valign="top">Quantifier ("all"/"each"/"every", "any"/"some", | |||
(exactly) "one", "most"/"majority", "none".</td> | |||
<td valign="top">No, default "all"</td> | |||
</tr> | |||
</table> | |||
<h4>Parameters specified as nested elements</h4> | |||
<p>The resources against which comparisons will be made must be specified | |||
using the nested <control> element, which denotes a | |||
<a href="#resources">resources</a> collection.</p> | |||
</blockquote> | |||
<h4><a name="sort">sort</a></h4> | |||
<p>Sorts another nested resource collection according to the resources' | |||
natural order, or by one or more nested resource comparators:</p> | |||
natural order, or by one or more nested <a href="#rcmp">resource | |||
comparators</a>:</p> | |||
<blockquote> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
@@ -650,7 +680,7 @@ natural order, or by one or more nested resource comparators:</p> | |||
are available in the internal <a href="antlib.html">antlib</a> | |||
<code>org.apache.tools.ant.types.resources.comparators</code>: | |||
</p> | |||
<h4><a name="rcmp">Resource Comparators:</a></h4> | |||
<ul> | |||
<li><a href="#rcmp.name">name</a> - sort resources by name</li> | |||
<li><a href="#rcmp.exists">exists</a> - sort resources by existence</li> | |||
@@ -0,0 +1,139 @@ | |||
/* | |||
* 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.tools.ant.types; | |||
import org.apache.tools.ant.BuildException; | |||
/** | |||
* EnumeratedAttribute for quantifier comparisons. Evaluates a | |||
* <code>boolean[]</code> or raw <code>true</code> and <code>false</code> | |||
* counts. Accepts the following values:<ul> | |||
* <li>"all"</li> - none <code>false</code> | |||
* <li>"each"</li> - none <code>false</code> | |||
* <li>"every"</li> - none <code>false</code> | |||
* <li>"any"</li> - at least one <code>true</code> | |||
* <li>"some"</li> - at least one <code>true</code> | |||
* <li>"one"</li> - exactly one <code>true</code> | |||
* <li>"majority"</li> - more <code>true</code> than <code>false</code> | |||
* <li>"most"</li> - more <code>true</code> than <code>false</code> | |||
* <li>"none"</li> - none <code>true</code> | |||
* </ul> | |||
* @since Ant 1.7 | |||
*/ | |||
public class Quantifier extends EnumeratedAttribute { | |||
private static final String[] VALUES | |||
= new String[] {"all", "each", "every", "any", "some", "one", | |||
"majority", "most", "none"}; | |||
public static final Quantifier ALL = new Quantifier("all"); | |||
public static final Quantifier ANY = new Quantifier("any"); | |||
public static final Quantifier ONE = new Quantifier("one"); | |||
public static final Quantifier MAJORITY = new Quantifier("majority"); | |||
public static final Quantifier NONE = new Quantifier("none"); | |||
private static abstract class Predicate { | |||
abstract boolean eval(int t, int f); | |||
} | |||
private static final Predicate ALL_PRED = new Predicate() { | |||
boolean eval(int t, int f) { return f == 0; } | |||
}; | |||
private static final Predicate ANY_PRED = new Predicate() { | |||
boolean eval(int t, int f) { return t > 0 ; } | |||
}; | |||
private static final Predicate ONE_PRED = new Predicate() { | |||
boolean eval(int t, int f) { return t == 1; } | |||
}; | |||
private static final Predicate MAJORITY_PRED = new Predicate() { | |||
boolean eval(int t, int f) { return t > f; } | |||
}; | |||
private static final Predicate NONE_PRED = new Predicate() { | |||
boolean eval(int t, int f) { return t == 0; } | |||
}; | |||
private static final Predicate[] PREDS = new Predicate[VALUES.length]; | |||
static { | |||
PREDS[0] = ALL_PRED; | |||
PREDS[1] = ALL_PRED; | |||
PREDS[2] = ALL_PRED; | |||
PREDS[3] = ANY_PRED; | |||
PREDS[4] = ANY_PRED; | |||
PREDS[5] = ONE_PRED; | |||
PREDS[6] = MAJORITY_PRED; | |||
PREDS[7] = MAJORITY_PRED; | |||
PREDS[8] = NONE_PRED; | |||
} | |||
/** | |||
* Default constructor. | |||
*/ | |||
public Quantifier() { | |||
} | |||
/** | |||
* Construct a new Quantifier with the specified value. | |||
* @param value the EnumeratedAttribute value. | |||
*/ | |||
public Quantifier(String value) { | |||
setValue(value); | |||
} | |||
/** | |||
* Return the possible values. | |||
* @return String[] of EnumeratedAttribute values. | |||
*/ | |||
public String[] getValues() { | |||
return VALUES; | |||
} | |||
/** | |||
* Evaluate a <code>boolean<code> array. | |||
* @param b the <code>boolean[]</code> to evaluate. | |||
* @return true if the argument fell within the parameters of this Quantifier. | |||
*/ | |||
public boolean evaluate(boolean[] b) { | |||
int t = 0; | |||
for (int i = 0; i < b.length; i++) { | |||
if (b[i]) { | |||
t++; | |||
} | |||
} | |||
return evaluate(t, b.length - t); | |||
} | |||
/** | |||
* Evaluate integer <code>true</code> vs. <code>false</code> counts. | |||
* @param t the number of <code>true</code> values. | |||
* @param f the number of <code>false</code> values. | |||
* @return true if the arguments fell within the parameters of this Quantifier. | |||
*/ | |||
public boolean evaluate(int t, int f) { | |||
int index = getIndex(); | |||
if (index == -1) { | |||
throw new BuildException("Quantifier value not set."); | |||
} | |||
return PREDS[index].eval(t, f); | |||
} | |||
} | |||
@@ -0,0 +1,153 @@ | |||
/* | |||
* 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.tools.ant.types.resources.selectors; | |||
import java.util.Stack; | |||
import java.util.Vector; | |||
import java.util.TreeMap; | |||
import java.util.Iterator; | |||
import java.util.Collection; | |||
import java.util.Comparator; | |||
import java.util.Collections; | |||
import java.util.AbstractCollection; | |||
import java.util.NoSuchElementException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.types.Comparison; | |||
import org.apache.tools.ant.types.DataType; | |||
import org.apache.tools.ant.types.Resource; | |||
import org.apache.tools.ant.types.Quantifier; | |||
import org.apache.tools.ant.types.ResourceCollection; | |||
import org.apache.tools.ant.types.resources.Union; | |||
import org.apache.tools.ant.types.resources.comparators.ResourceComparator; | |||
import org.apache.tools.ant.types.resources.comparators.DelegatedResourceComparator; | |||
/** | |||
* ResourceSelector that compares against "control" Resource(s) | |||
* using ResourceComparators. | |||
* @since Ant 1.7 | |||
*/ | |||
public class Compare extends DataType implements ResourceSelector { | |||
private static final String ONE_CONTROL_MESSAGE | |||
= " the <control> element should be specified exactly once."; | |||
private DelegatedResourceComparator comp = new DelegatedResourceComparator(); | |||
private Quantifier against = Quantifier.ALL; | |||
private Comparison when = Comparison.EQUAL; | |||
private Union control; | |||
/** | |||
* Add a ResourceComparator to this Compare selector. | |||
* If multiple ResourceComparators are added, they will be processed in LIFO order. | |||
* @param c the ResourceComparator to add. | |||
*/ | |||
public synchronized void add(ResourceComparator c) { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
comp.add(c); | |||
} | |||
/** | |||
* Set the quantifier to be used. Default "all". | |||
* @param against the Quantifier EnumeratedAttribute to use. | |||
*/ | |||
public synchronized void setAgainst(Quantifier against) { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
this.against = against; | |||
} | |||
/** | |||
* Set the comparison to be used. Default "equal". | |||
* @param when the Comparison EnumeratedAttribute to use. | |||
*/ | |||
public synchronized void setWhen(Comparison when) { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
this.when = when; | |||
} | |||
/** | |||
* Create the nested control element. These are the | |||
* resources to compare against. | |||
* @return ResourceCollection. | |||
*/ | |||
public synchronized ResourceCollection createControl() { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
if (control != null) { | |||
throw oneControl(); | |||
} | |||
control = new Union(); | |||
return control; | |||
} | |||
//implement ResourceSelector; inherit doc | |||
public synchronized boolean isSelected(Resource r) { | |||
if (isReference()) { | |||
return ((ResourceSelector) getCheckedRef()).isSelected(r); | |||
} | |||
if (control == null) { | |||
throw oneControl(); | |||
} | |||
int t = 0, f = 0; | |||
for (Iterator it = control.iterator(); it.hasNext();) { | |||
if (when.evaluate(comp.compare(r, (Resource) it.next()))) { | |||
t++; | |||
} else { | |||
f++; | |||
} | |||
} | |||
return against.evaluate(t, f); | |||
} | |||
/** | |||
* Overrides the version from DataType | |||
* to recurse on nested ResourceComparators. | |||
* @param stk the stack of data types to use (recursively). | |||
* @param p the project to use to dereference the references. | |||
* @throws BuildException on error. | |||
*/ | |||
protected synchronized void dieOnCircularReference(Stack stk, Project p) | |||
throws BuildException { | |||
if (isChecked()) { | |||
return; | |||
} | |||
if (isReference()) { | |||
super.dieOnCircularReference(stk, p); | |||
} else { | |||
if (control != null) { | |||
DataType.invokeCircularReferenceCheck(control, stk, p); | |||
} | |||
DataType.invokeCircularReferenceCheck(comp, stk, p); | |||
setChecked(true); | |||
} | |||
} | |||
private BuildException oneControl() { | |||
return new BuildException(super.toString() + ONE_CONTROL_MESSAGE); | |||
} | |||
} |
@@ -1,6 +1,8 @@ | |||
<antlib> | |||
<typedef name="and" | |||
classname="org.apache.tools.ant.types.resources.selectors.And" /> | |||
<typedef name="compare" | |||
classname="org.apache.tools.ant.types.resources.selectors.Compare" /> | |||
<typedef name="contains" | |||
classname="org.apache.tools.ant.types.selectors.ContainsSelector" /> | |||
<typedef name="containsregexp" | |||
@@ -1,5 +1,6 @@ | |||
<project default="all" xmlns:au="antlib:org.apache.ant.antunit" | |||
xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors"> | |||
xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors" | |||
xmlns:rcmp="antlib:org.apache.tools.ant.types.resources.comparators"> | |||
<target name="testname1"> | |||
<au:assertTrue> | |||
@@ -99,7 +100,7 @@ | |||
</au:assertTrue> | |||
</target> | |||
<target name="testinstanceoftype" | |||
<target name="instanceoftype" | |||
depends="testinstanceoftype1,testinstanceoftype2,testinstanceoftype3" /> | |||
<target name="testinstanceofclass"> | |||
@@ -115,7 +116,7 @@ | |||
</au:assertTrue> | |||
</target> | |||
<target name="instanceof" depends="testinstanceoftype,testinstanceofclass" /> | |||
<target name="instanceof" depends="instanceoftype,testinstanceofclass" /> | |||
<target name="testtype"> | |||
<au:assertTrue> | |||
@@ -358,6 +359,68 @@ | |||
</au:assertTrue> | |||
</target> | |||
<target name="testcompare"> | |||
<au:assertTrue> | |||
<and> | |||
<!-- basic test, natural ordering --> | |||
<resourcecount count="3"> | |||
<restrict> | |||
<rsel:compare when="greater" against="each"> | |||
<control><string value="b" /></control> | |||
</rsel:compare> | |||
<resources> | |||
<string value="a" /> | |||
<string value="b" /> | |||
<string value="c" /> | |||
<string value="d" /> | |||
<string value="e" /> | |||
</resources> | |||
</restrict> | |||
</resourcecount> | |||
<!-- one comparator, default when/against --> | |||
<resourcecount count="5"> | |||
<restrict> | |||
<rsel:compare> | |||
<control><string value="." /></control> | |||
<rcmp:size /> | |||
</rsel:compare> | |||
<resources> | |||
<string value="a" /> | |||
<string value="b" /> | |||
<string value="c" /> | |||
<string value="d" /> | |||
<string value="e" /> | |||
</resources> | |||
</restrict> | |||
</resourcecount> | |||
<!-- multiple controls, comparators --> | |||
<resourcecount count="3"> | |||
<restrict> | |||
<rsel:compare when="greater" against="each"> | |||
<control> | |||
<string value="a" /> | |||
<string value="b" /> | |||
<string value="bb" /> | |||
<string value="c" /> | |||
<string value="ccc" /> | |||
</control> | |||
<rcmp:name /> | |||
<rcmp:size /> | |||
</rsel:compare> | |||
<resources> | |||
<string value="a" /> | |||
<string value="bbbb" /> | |||
<string value="ccc" /> | |||
<string value="cccc" /> | |||
<string value="d" /> | |||
<string value="e" /> | |||
</resources> | |||
</restrict> | |||
</resourcecount> | |||
</and> | |||
</au:assertTrue> | |||
</target> | |||
<target name="majority" | |||
depends="testmajority1,testmajority2,testmajority3,testmajority4" /> | |||
@@ -365,7 +428,7 @@ | |||
depends="testand,testor,testnone,testnot,majority" /> | |||
<target name="all" | |||
depends="name,testexists,instanceof,testtype,testdate,testsize,testcontains,testcontainsregexp,logical" /> | |||
depends="name,testexists,instanceof,testtype,testdate,testsize,testcontains,testcontainsregexp,logical,testcompare" /> | |||
<!-- | |||
The tests for oata.types.selectors.ModifiedSelectorTest as | |||