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 | * Added <tokens> resource collection for convenient creation of string | ||||
| resources from other resources' content. Inspired by Bugzilla 40504. | 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 | Changes from Ant 1.7.0Beta1 to Ant 1.7.0Beta2 | ||||
| ============================================= | ============================================= | ||||
| @@ -463,6 +463,8 @@ platforms. | |||||
| containing a particular text string.</li> | containing a particular text string.</li> | ||||
| <li><a href="selectors.html#regexpselect">containsregexp</a> - select | <li><a href="selectors.html#regexpselect">containsregexp</a> - select | ||||
| resources whose contents match a particular regular expression.</li> | 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> | </ul> | ||||
| <h4><a name="rsel.name">name</a></h4> | <h4><a name="rsel.name">name</a></h4> | ||||
| @@ -621,12 +623,40 @@ platforms. | |||||
| </tr> | </tr> | ||||
| </table> | </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> | </blockquote> | ||||
| <h4><a name="sort">sort</a></h4> | <h4><a name="sort">sort</a></h4> | ||||
| <p>Sorts another nested resource collection according to the resources' | <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> | <blockquote> | ||||
| <table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
| <tr> | <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> | are available in the internal <a href="antlib.html">antlib</a> | ||||
| <code>org.apache.tools.ant.types.resources.comparators</code>: | <code>org.apache.tools.ant.types.resources.comparators</code>: | ||||
| </p> | </p> | ||||
| <h4><a name="rcmp">Resource Comparators:</a></h4> | |||||
| <ul> | <ul> | ||||
| <li><a href="#rcmp.name">name</a> - sort resources by name</li> | <li><a href="#rcmp.name">name</a> - sort resources by name</li> | ||||
| <li><a href="#rcmp.exists">exists</a> - sort resources by existence</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> | <antlib> | ||||
| <typedef name="and" | <typedef name="and" | ||||
| classname="org.apache.tools.ant.types.resources.selectors.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" | <typedef name="contains" | ||||
| classname="org.apache.tools.ant.types.selectors.ContainsSelector" /> | classname="org.apache.tools.ant.types.selectors.ContainsSelector" /> | ||||
| <typedef name="containsregexp" | <typedef name="containsregexp" | ||||
| @@ -1,5 +1,6 @@ | |||||
| <project default="all" xmlns:au="antlib:org.apache.ant.antunit" | <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"> | <target name="testname1"> | ||||
| <au:assertTrue> | <au:assertTrue> | ||||
| @@ -99,7 +100,7 @@ | |||||
| </au:assertTrue> | </au:assertTrue> | ||||
| </target> | </target> | ||||
| <target name="testinstanceoftype" | |||||
| <target name="instanceoftype" | |||||
| depends="testinstanceoftype1,testinstanceoftype2,testinstanceoftype3" /> | depends="testinstanceoftype1,testinstanceoftype2,testinstanceoftype3" /> | ||||
| <target name="testinstanceofclass"> | <target name="testinstanceofclass"> | ||||
| @@ -115,7 +116,7 @@ | |||||
| </au:assertTrue> | </au:assertTrue> | ||||
| </target> | </target> | ||||
| <target name="instanceof" depends="testinstanceoftype,testinstanceofclass" /> | |||||
| <target name="instanceof" depends="instanceoftype,testinstanceofclass" /> | |||||
| <target name="testtype"> | <target name="testtype"> | ||||
| <au:assertTrue> | <au:assertTrue> | ||||
| @@ -358,6 +359,68 @@ | |||||
| </au:assertTrue> | </au:assertTrue> | ||||
| </target> | </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" | <target name="majority" | ||||
| depends="testmajority1,testmajority2,testmajority3,testmajority4" /> | depends="testmajority1,testmajority2,testmajority3,testmajority4" /> | ||||
| @@ -365,7 +428,7 @@ | |||||
| depends="testand,testor,testnone,testnot,majority" /> | depends="testand,testor,testnone,testnot,majority" /> | ||||
| <target name="all" | <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 | The tests for oata.types.selectors.ModifiedSelectorTest as | ||||