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>
<p>
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
the new task. These get substituted into the &lt;sequential&gt;
or &lt;parallel&gt; task when the new task is run.
@@ -28,7 +28,7 @@
</tr>
<tr>
<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>
</tr>
<tr>
@@ -38,9 +38,20 @@
</td>
<td valign="top" align="center">No</td>
</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>
<h3>Parameters specified as nested elements</h3>
<h4>param</h4>
<h4>attribute</h4>
<p>
This is used to specify attributes of the new task. The values
of the attributes get substituted into the templated task.
@@ -52,6 +63,11 @@
task using the ant property notation - ${attribute name}.
Note that is not an actual ant property.
</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>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -61,13 +77,13 @@
</tr>
<tr>
<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>
</tr>
<tr>
<td valign="top">default</td>
<td valign="top">
the default value of the attribute.
The default value of the attribute.
</td>
<td valign="top" align="center">No</td>
</tr>
@@ -87,13 +103,13 @@
</tr>
<tr>
<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>
</tr>
<tr>
<td valign="top">optional</td>
<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
the new task.
</td>
@@ -109,7 +125,7 @@
<blockquote>
<pre>
&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;sequential&gt;
&lt;echo&gt;v is ${v}&lt;/echo&gt;
@@ -124,6 +140,23 @@
&lt;/testing&gt;
</pre>
</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>
The following fragment defines a task called &lt;call-cc&gt; which
take the attributes "target", "link" and "target.dir" and the
@@ -134,9 +167,9 @@
<blockquote>
<pre>
&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;sequential&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">
<macrodef name="my.echo">
<param name="text"/>
<attribute name="text"/>
<sequential>
<echo message="${text}"/>
</sequential>
@@ -12,7 +12,7 @@

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

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

+ 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.UnknownElement;

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

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

/**
* Name of the definition
@@ -105,6 +108,46 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
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.
* 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(
"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.
*
*/
public static class Param {
public static class Attribute {
private String name;
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) {
if (!isValidName(name)) {
throw new BuildException(
"Illegal name [" + name + "] for attribute");
}
this.name = name;
}

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

@@ -316,5 +397,17 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
((MacroInstance) o).setTemplate(template);
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 macroName = new StringBuffer();
boolean inMacro = false;
@@ -179,6 +179,59 @@ public class MacroInstance extends Task implements DynamicConfigurator {
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) {
UnknownElement ret = new UnknownElement(ue.getTag());
ret.setNamespace(ue.getNamespace());
@@ -234,25 +287,26 @@ public class MacroInstance extends Task implements DynamicConfigurator {

/**
* 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.
*
*/
public void execute() {
localProperties = new Hashtable();
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) {
value = param.getDefault();
value = attribute.getDefault();
}
if (value == null) {
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) {
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() {
expectLog("nested", "A nested element");
}

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


Loading…
Cancel
Save