Browse Source

macrodef changes:

* change nested element name from param to attribute
   (now the same as scriptdef)
 * expermintal testing for @attribute notation - controlled
   by an attributeStyle attribute
 * checking if correct attribute/element names are used
 * samedefinition method overloaded


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275105 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Reilly 22 years ago
parent
commit
e211cf05f7
5 changed files with 233 additions and 38 deletions
  1. +44
    -11
      docs/manual/CoreTasks/macrodef.html
  2. +14
    -3
      src/etc/testcases/taskdefs/macrodef.xml
  3. +108
    -15
      src/main/org/apache/tools/ant/taskdefs/MacroDef.java
  4. +63
    -9
      src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
  5. +4
    -0
      src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java

+ 44
- 11
docs/manual/CoreTasks/macrodef.html View File

@@ -11,7 +11,7 @@
<h3>Description</h3> <h3>Description</h3>
<p> <p>
This defines a new task using a &lt;sequential&gt; or &lt;parallel&gt; This defines a new task using a &lt;sequential&gt; or &lt;parallel&gt;
nested task as a template. Nested elements &lt;param&gt; and
nested task as a template. Nested elements &lt;attribute&gt; and
&lt;element&gt; are used to specify attributes and elements of &lt;element&gt; are used to specify attributes and elements of
the new task. These get substituted into the &lt;sequential&gt; the new task. These get substituted into the &lt;sequential&gt;
or &lt;parallel&gt; task when the new task is run. or &lt;parallel&gt; task when the new task is run.
@@ -28,7 +28,7 @@
</tr> </tr>
<tr> <tr>
<td valign="top">name</td> <td valign="top">name</td>
<td valign="top">the name of the new definition</td>
<td valign="top">The name of the new definition</td>
<td valign="top" align="center">Yes</td> <td valign="top" align="center">Yes</td>
</tr> </tr>
<tr> <tr>
@@ -38,9 +38,20 @@
</td> </td>
<td valign="top" align="center">No</td> <td valign="top" align="center">No</td>
</tr> </tr>
<tr>
<td valign="top">attributestyle</td>
<td valign="top">
<em>Temporary</em>
this attribute specifies if the attribute is in ant style
(i.e. ${attributeName}) or xpath style (i.e @attributeName).
Valid values are "ant" and "xpath". The default value
is "ant".
</td>
<td valign="top" align="center">No</td>
</tr>
</table> </table>
<h3>Parameters specified as nested elements</h3> <h3>Parameters specified as nested elements</h3>
<h4>param</h4>
<h4>attribute</h4>
<p> <p>
This is used to specify attributes of the new task. The values This is used to specify attributes of the new task. The values
of the attributes get substituted into the templated task. of the attributes get substituted into the templated task.
@@ -52,6 +63,11 @@
task using the ant property notation - ${attribute name}. task using the ant property notation - ${attribute name}.
Note that is not an actual ant property. Note that is not an actual ant property.
</p> </p>
<p>
If the attribute style is set to "xpath", the attribute is
specified in the body of the template task by prefixing the
name with a "@".
</p>
<h3>Parameters</h3> <h3>Parameters</h3>
<table border="1" cellpadding="2" cellspacing="0"> <table border="1" cellpadding="2" cellspacing="0">
<tr> <tr>
@@ -61,13 +77,13 @@
</tr> </tr>
<tr> <tr>
<td valign="top">name</td> <td valign="top">name</td>
<td valign="top">the name of the new attribute</td>
<td valign="top">The name of the new attribute</td>
<td valign="top" align="center">Yes</td> <td valign="top" align="center">Yes</td>
</tr> </tr>
<tr> <tr>
<td valign="top">default</td> <td valign="top">default</td>
<td valign="top"> <td valign="top">
the default value of the attribute.
The default value of the attribute.
</td> </td>
<td valign="top" align="center">No</td> <td valign="top" align="center">No</td>
</tr> </tr>
@@ -87,13 +103,13 @@
</tr> </tr>
<tr> <tr>
<td valign="top">name</td> <td valign="top">name</td>
<td valign="top">the name of the new attribute</td>
<td valign="top">The name of the new attribute</td>
<td valign="top" align="center">Yes</td> <td valign="top" align="center">Yes</td>
</tr> </tr>
<tr> <tr>
<td valign="top">optional</td> <td valign="top">optional</td>
<td valign="top"> <td valign="top">
if true this nested element is optional. Default is
If true this nested element is optional. Default is
false - i.e the nested element is required in false - i.e the nested element is required in
the new task. the new task.
</td> </td>
@@ -109,7 +125,7 @@
<blockquote> <blockquote>
<pre> <pre>
&lt;macrodef name="testing"&gt; &lt;macrodef name="testing"&gt;
&lt;param name="v" default="NOT SET"/&gt;
&lt;attribute name="v" default="NOT SET"/&gt;
&lt;element name="some-tasks" optional="yes"/&gt; &lt;element name="some-tasks" optional="yes"/&gt;
&lt;sequential&gt; &lt;sequential&gt;
&lt;echo&gt;v is ${v}&lt;/echo&gt; &lt;echo&gt;v is ${v}&lt;/echo&gt;
@@ -124,6 +140,23 @@
&lt;/testing&gt; &lt;/testing&gt;
</pre> </pre>
</blockquote> </blockquote>
<p>
The following fragment sets the attribute style to "xpath"
for the macro definition &lt;testing&gt; and calls the
macro. The fragment should output "attribute is this is a test".
</p>
<blockquote>
<pre>
&lt;macrodef name="testing" attributestyle="xpath"&gt;
&lt;attribute name="abc"/&gt;
&lt;sequential&gt;
&lt;echo&gt;attribute is @abc&lt;/echo&gt;
&lt;/sequential&gt;
&lt;/macrodef&gt;

&lt;testing abc="this is a test"/&gt;
</pre>
</blockquote>
<p> <p>
The following fragment defines a task called &lt;call-cc&gt; which The following fragment defines a task called &lt;call-cc&gt; which
take the attributes "target", "link" and "target.dir" and the take the attributes "target", "link" and "target.dir" and the
@@ -134,9 +167,9 @@
<blockquote> <blockquote>
<pre> <pre>
&lt;macrodef name="call-cc"&gt; &lt;macrodef name="call-cc"&gt;
&lt;param name="target"/&gt;
&lt;param name="link"/&gt;
&lt;param name="target.dir"/&gt;
&lt;attribute name="target"/&gt;
&lt;attribute name="link"/&gt;
&lt;attribute name="target.dir"/&gt;
&lt;element name="cc-elements"/&gt; &lt;element name="cc-elements"/&gt;
&lt;sequential&gt; &lt;sequential&gt;
&lt;mkdir dir="${obj.dir}/${target}"/&gt; &lt;mkdir dir="${obj.dir}/${target}"/&gt;


+ 14
- 3
src/etc/testcases/taskdefs/macrodef.xml View File

@@ -2,7 +2,7 @@


<target name="simple"> <target name="simple">
<macrodef name="my.echo"> <macrodef name="my.echo">
<param name="text"/>
<attribute name="text"/>
<sequential> <sequential>
<echo message="${text}"/> <echo message="${text}"/>
</sequential> </sequential>
@@ -12,7 +12,7 @@


<target name="text"> <target name="text">
<macrodef name="my.echo"> <macrodef name="my.echo">
<param name="text"/>
<attribute name="text"/>
<sequential> <sequential>
<echo>${text}</echo> <echo>${text}</echo>
</sequential> </sequential>
@@ -22,7 +22,7 @@


<target name="uri"> <target name="uri">
<macrodef name="echo" uri="abc"> <macrodef name="echo" uri="abc">
<param name="text"/>
<attribute name="text"/>
<sequential> <sequential>
<echo message="${text}"/> <echo message="${text}"/>
</sequential> </sequential>
@@ -44,4 +44,15 @@
</nested> </nested>
</nested> </nested>
</target> </target>

<target name="xpathstyle">
<macrodef name="testing" attributestyle="xpath">
<attribute name="abc"/>
<sequential>
<echo>attribute is @abc@abc</echo>
</sequential>
</macrodef>

<testing abc="this is a test"/>
</target>
</project> </project>

+ 108
- 15
src/main/org/apache/tools/ant/taskdefs/MacroDef.java View File

@@ -68,6 +68,8 @@ import org.apache.tools.ant.Task;
import org.apache.tools.ant.TaskContainer; import org.apache.tools.ant.TaskContainer;
import org.apache.tools.ant.UnknownElement; import org.apache.tools.ant.UnknownElement;


import org.apache.tools.ant.types.EnumeratedAttribute;

/** /**
* Describe class <code>MacroDef</code> here. * Describe class <code>MacroDef</code> here.
* *
@@ -78,9 +80,10 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
private UnknownElement nestedTask; private UnknownElement nestedTask;
private String name; private String name;
private String componentName; private String componentName;
private List params = new ArrayList();
private List attributes = new ArrayList();
private Map elements = new HashMap(); private Map elements = new HashMap();
private String uri;
private String uri;
private int attributeStyle = AttributeStyle.ANT;


/** /**
* Name of the definition * Name of the definition
@@ -105,6 +108,46 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
this.uri = uri; this.uri = uri;
} }


/**
* Enumerated type for attributeStyle attribute
*
* @see EnumeratedAttribute
*/
public static class AttributeStyle extends EnumeratedAttribute {
/** Enumerated values */
public static final int ANT = 0, XPATH = 1;

/**
* get the values
* @return an array of the allowed values for this attribute.
*/
public String[] getValues() {
return new String[] {"ant", "xpath"};
}
}

/**
* <em>Expermential</em>
* I am uncertain at the moment how to encode attributes
* using ant style ${attribute} or xpath style @attribute.
* The first may get mixed up with ant properties and
* the second may get mixed up with xpath.
* The default at the moment is ant s
*
* @param style an <code>AttributeStyle</code> value
*/
public void setAttributeStyle(AttributeStyle style) {
attributeStyle = style.getIndex();
}

/**
* <em>Expermential</em>
* @return the attribute style
*/
public int getAttributeStyle() {
return attributeStyle;
}

/** /**
* Set the class loader. * Set the class loader.
* Not used * Not used
@@ -139,10 +182,10 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
} }


/** /**
* @return the nested Params
* @return the nested Attributes
*/ */
public List getParams() {
return params;
public List getAttributes() {
return attributes;
} }


/** /**
@@ -153,16 +196,46 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
} }


/** /**
* Add a param element.
* Check if a character is a valid character for an element or
* attribute name
* @param c the character to check
* @return true if the character is a letter or digit or '.' or '-'
* attribute name
*/
public static boolean isValidNameCharacter(char c) {
// ? is there an xml api for this ?
return Character.isLetterOrDigit(c) || c == '.' || c == '-';
}

/**
* Check if a string is a valid name for an element or
* attribute
* @param name the string to check
* @return true if the name consists of valid name characters
*/
private static boolean isValidName(String name) {
if (name.length() == 0) {
return false;
}
for (int i = 0; i < name.length(); ++i) {
if (!isValidNameCharacter(name.charAt(i))) {
return false;
}
}
return true;
}

/**
* Add an attribute element.
* *
* @param param a param nested element.
* @param attribute an attribute nested element.
*/ */
public void addConfiguredParam(Param param) {
if (param.getName() == null) {
public void addConfiguredAttribute(Attribute attribute) {
if (attribute.getName() == null) {
throw new BuildException( throw new BuildException(
"the param nested element needed a \"name\" attribute");
"the attribute nested element needed a \"name\" attribute");
} }
params.add(param);
attributes.add(attribute);
} }


/** /**
@@ -207,20 +280,24 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
* A nested element for the MacroDef task. * A nested element for the MacroDef task.
* *
*/ */
public static class Param {
public static class Attribute {
private String name; private String name;
private String defaultValue; private String defaultValue;
/** /**
* The name of the parameter.
* The name of the attribute.
* *
* @param name the name of the parameter
* @param name the name of the attribute
*/ */
public void setName(String name) { public void setName(String name) {
if (!isValidName(name)) {
throw new BuildException(
"Illegal name [" + name + "] for attribute");
}
this.name = name; this.name = name;
} }


/** /**
* @return the name of the parameter.
* @return the name of the attribute
*/ */
public String getName() { public String getName() {
return name; return name;
@@ -257,6 +334,10 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
* @param name the name of the element. * @param name the name of the element.
*/ */
public void setName(String name) { public void setName(String name) {
if (!isValidName(name)) {
throw new BuildException(
"Illegal name [" + name + "] for attribute");
}
this.name = name; this.name = name;
} }


@@ -316,5 +397,17 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
((MacroInstance) o).setTemplate(template); ((MacroInstance) o).setTemplate(template);
return o; return o;
} }

/**
* Equality method for this definition
* This only checks for pointer equality.
*
* @param other another definition
* @param project the current project
* @return true if the definitions are the same
*/
public boolean sameDefinition(AntTypeDefinition other, Project project) {
return this == other;
}
} }
} }

+ 63
- 9
src/main/org/apache/tools/ant/taskdefs/MacroInstance.java View File

@@ -146,7 +146,7 @@ public class MacroInstance extends Task implements DynamicConfigurator {
} }
} }


private static String macroSubs(String s, Map macroMapping) {
private String macroSubsAnt(String s, Map macroMapping) {
StringBuffer ret = new StringBuffer(); StringBuffer ret = new StringBuffer();
StringBuffer macroName = new StringBuffer(); StringBuffer macroName = new StringBuffer();
boolean inMacro = false; boolean inMacro = false;
@@ -179,6 +179,59 @@ public class MacroInstance extends Task implements DynamicConfigurator {
return ret.toString(); return ret.toString();
} }


private String macroSubsXPath(String s, Map macroMapping) {
StringBuffer ret = new StringBuffer();
StringBuffer macroName = new StringBuffer();
boolean inMacro = false;
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (!inMacro) {
if (c == '@') {
inMacro = true;
} else {
ret.append(c);
}
} else {
if (MacroDef.isValidNameCharacter(c)) {
macroName.append(c);
} else {
inMacro = false;
String name = macroName.toString();
String value = (String) macroMapping.get(name);
if (value == null) {
ret.append("@" + name);
} else {
ret.append(value);
}
if (c == '@') {
inMacro = true;
} else {
ret.append(c);
}
macroName = new StringBuffer();
}
}
}
if (inMacro) {
String name = macroName.toString();
String value = (String) macroMapping.get(name);
if (value == null) {
ret.append("@" + name);
} else {
ret.append(value);
}
}
return ret.toString();
}

private String macroSubs(String s, Map macroMapping) {
if (template.getAttributeStyle() == MacroDef.AttributeStyle.ANT) {
return macroSubsAnt(s, macroMapping);
} else {
return macroSubsXPath(s, macroMapping);
}
}

private UnknownElement copy(UnknownElement ue) { private UnknownElement copy(UnknownElement ue) {
UnknownElement ret = new UnknownElement(ue.getTag()); UnknownElement ret = new UnknownElement(ue.getTag());
ret.setNamespace(ue.getNamespace()); ret.setNamespace(ue.getNamespace());
@@ -234,25 +287,26 @@ public class MacroInstance extends Task implements DynamicConfigurator {


/** /**
* Execute the templates instance. * Execute the templates instance.
* Copies the unknown element, substitutes the parameters,
* Copies the unknown element, substitutes the attributes,
* and calls perform on the unknown element. * and calls perform on the unknown element.
* *
*/ */
public void execute() { public void execute() {
localProperties = new Hashtable(); localProperties = new Hashtable();
Set copyKeys = new HashSet(map.keySet()); Set copyKeys = new HashSet(map.keySet());
for (int i = 0; i < template.getParams().size(); ++i) {
MacroDef.Param param = (MacroDef.Param) template.getParams().get(i);
String value = (String) map.get(param.getName());
for (int i = 0; i < template.getAttributes().size(); ++i) {
MacroDef.Attribute attribute =
(MacroDef.Attribute) template.getAttributes().get(i);
String value = (String) map.get(attribute.getName());
if (value == null) { if (value == null) {
value = param.getDefault();
value = attribute.getDefault();
} }
if (value == null) { if (value == null) {
throw new BuildException( throw new BuildException(
"required parameter " + param.getName() + " not set");
"required attribute " + attribute.getName() + " not set");
} }
localProperties.put(param.getName(), value);
copyKeys.remove(param.getName());
localProperties.put(attribute.getName(), value);
copyKeys.remove(attribute.getName());
} }
if (copyKeys.size() != 0) { if (copyKeys.size() != 0) {
throw new BuildException( throw new BuildException(


+ 4
- 0
src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java View File

@@ -85,5 +85,9 @@ public class MacroDefTest extends BuildFileTest {
public void testNested() { public void testNested() {
expectLog("nested", "A nested element"); expectLog("nested", "A nested element");
} }

public void testXPathStyle() {
expectLog("xpathstyle", "attribute is this is a testthis is a test");
}
} }



Loading…
Cancel
Save