git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275962 13f79535-47bb-0310-9956-ffa450edef68master
@@ -43,16 +43,6 @@ | |||||
</td> | </td> | ||||
<td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td valign="top">textname</td> | |||||
<td valign="top"> | |||||
The textname attribute value becomes a macrodef | |||||
attribute that | |||||
gets set to the value of the text contents of the macro. | |||||
<em>since ant 1.6.1</em> | |||||
</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>attribute</h4> | <h4>attribute</h4> | ||||
@@ -143,6 +133,54 @@ | |||||
<td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
</tr> | </tr> | ||||
</table> | </table> | ||||
<h4>text</h4> | |||||
<p> | |||||
This is used to specify the treatment of text contents of the macrodef. | |||||
If this element is not present, then any nested text in the macro | |||||
will be an error. If the text element is present, then the name | |||||
becomes an attribute that gets set to the nested text of the macro. | |||||
<em>Since ant 1.6.1.</em> | |||||
</p> | |||||
<p> | |||||
The case of the text name is ignored. | |||||
</p> | |||||
<h3>Parameters</h3> | |||||
<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">name</td> | |||||
<td valign="top">The name of the text attribute</td> | |||||
<td valign="top" align="center">Yes</td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top">optional</td> | |||||
<td valign="top"> | |||||
If true nested text in the macro is optional, default is "false". | |||||
</td> | |||||
<td valign="top" align="center">No</td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top">trim</td> | |||||
<td valign="top"> | |||||
If true, the nested text is trimmed of white space, | |||||
default is "false". | |||||
</td> | |||||
<td valign="top" align="center">No</td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top">description</td> | |||||
<td valign="top"> | |||||
This contains a description | |||||
informing the user what the nested text of the macro is expected | |||||
to be. | |||||
</td> | |||||
<td valign="top" align="center">No</td> | |||||
</tr> | |||||
</table> | |||||
<h3>Examples</h3> | <h3>Examples</h3> | ||||
<p> | <p> | ||||
@@ -211,11 +249,12 @@ | |||||
</pre> | </pre> | ||||
</blockquote> | </blockquote> | ||||
<p> | <p> | ||||
The following shows the use of the <code>textname</code> attribute. | |||||
The following shows the use of the <code>text</code> element. | |||||
</p> | </p> | ||||
<blockquote> | <blockquote> | ||||
<pre class="code"> | <pre class="code"> | ||||
<macrodef name="echotest" textname="text"> | |||||
<macrodef name="echotest"> | |||||
<text name="text"/text> | |||||
<sequential> | <sequential> | ||||
<echo>@{text}</echo> | <echo>@{text}</echo> | ||||
</sequential> | </sequential> | ||||
@@ -102,8 +102,9 @@ | |||||
</ignore> | </ignore> | ||||
</target> | </target> | ||||
<target name="textname"> | |||||
<macrodef name="echotest" textname="text"> | |||||
<target name="textelement"> | |||||
<macrodef name="echotest"> | |||||
<text name="text" optional="yes"/> | |||||
<sequential> | <sequential> | ||||
<echo>@{text}</echo> | <echo>@{text}</echo> | ||||
</sequential> | </sequential> | ||||
@@ -113,8 +114,31 @@ | |||||
</echotest> | </echotest> | ||||
</target> | </target> | ||||
<target name="text.trim"> | |||||
<macrodef name="echotest"> | |||||
<text name="text" trim="yes"/> | |||||
<sequential> | |||||
<echo>[@{text}]</echo> | |||||
</sequential> | |||||
</macrodef> | |||||
<echotest> | |||||
Hello world | |||||
</echotest> | |||||
</target> | |||||
<target name="duplicatetextname"> | <target name="duplicatetextname"> | ||||
<macrodef name="echotest" textname="text"> | |||||
<macrodef name="echotest"> | |||||
<attribute name="text"/> | |||||
<text name="text"/> | |||||
<sequential> | |||||
<echo>@{text}</echo> | |||||
</sequential> | |||||
</macrodef> | |||||
</target> | |||||
<target name="duplicatetextname2"> | |||||
<macrodef name="echotest"> | |||||
<text name="text"/> | |||||
<attribute name="text"/> | <attribute name="text"/> | ||||
<sequential> | <sequential> | ||||
<echo>@{text}</echo> | <echo>@{text}</echo> | ||||
@@ -59,6 +59,7 @@ import java.util.List; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Locale; | import java.util.Locale; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Iterator; | |||||
import org.apache.tools.ant.AntTypeDefinition; | import org.apache.tools.ant.AntTypeDefinition; | ||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
@@ -82,6 +83,7 @@ public class MacroDef extends AntlibDefinition { | |||||
private List attributes = new ArrayList(); | private List attributes = new ArrayList(); | ||||
private Map elements = new HashMap(); | private Map elements = new HashMap(); | ||||
private String textName = null; | private String textName = null; | ||||
private Text text = null; | |||||
/** | /** | ||||
* Name of the definition | * Name of the definition | ||||
@@ -92,22 +94,39 @@ public class MacroDef extends AntlibDefinition { | |||||
} | } | ||||
/** | /** | ||||
* Name of the text attribute. | |||||
* @param textName the name of the attribute to use for the | |||||
* text content of the macro. | |||||
* Add the text element. | |||||
* @param text the nested text element to add | |||||
* @since ant 1.6.1 | * @since ant 1.6.1 | ||||
*/ | */ | ||||
public void setTextName(String textName) { | |||||
this.textName = textName; | |||||
public void addConfiguredText(Text text) { | |||||
if (this.text != null) { | |||||
throw new BuildException( | |||||
"Only one nested text element allowed"); | |||||
} | |||||
if (text.getName() == null) { | |||||
throw new BuildException( | |||||
"the text nested element needed a \"name\" attribute"); | |||||
} | |||||
// Check if used by attributes | |||||
for (Iterator i = attributes.iterator(); i.hasNext();) { | |||||
Attribute attribute = (Attribute) i.next(); | |||||
if (text.getName().equals(attribute.getName())) { | |||||
throw new BuildException( | |||||
"the name \"" + text.getName() | |||||
+ "\" is already used as an attribute"); | |||||
} | |||||
} | |||||
this.text = text; | |||||
this.textName = text.getName(); | |||||
} | } | ||||
/** | /** | ||||
* @return the name of the text content attribute | |||||
* @return the nested text element | |||||
* @since ant 1.6.1 | * @since ant 1.6.1 | ||||
*/ | */ | ||||
public String getTextName() { | |||||
return textName; | |||||
public Text getText() { | |||||
return text; | |||||
} | } | ||||
/** | /** | ||||
@@ -245,7 +264,7 @@ public class MacroDef extends AntlibDefinition { | |||||
if (attribute.getName().equals(textName)) { | if (attribute.getName().equals(textName)) { | ||||
throw new BuildException( | throw new BuildException( | ||||
"the attribute name \"" + attribute.getName() | "the attribute name \"" + attribute.getName() | ||||
+ "\" has already been used by the textname attribute"); | |||||
+ "\" has already been used by the text element"); | |||||
} | } | ||||
for (int i = 0; i < attributes.size(); ++i) { | for (int i = 0; i < attributes.size(); ++i) { | ||||
if (((Attribute) attributes.get(i)).getName().equals( | if (((Attribute) attributes.get(i)).getName().equals( | ||||
@@ -403,6 +422,122 @@ public class MacroDef extends AntlibDefinition { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* A nested text element for the MacroDef task. | |||||
* @since ant 1.6.1 | |||||
*/ | |||||
public static class Text { | |||||
private String name; | |||||
private boolean optional; | |||||
private boolean trim; | |||||
private String description; | |||||
/** | |||||
* The name of the attribute. | |||||
* | |||||
* @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.toLowerCase(Locale.US); | |||||
} | |||||
/** | |||||
* @return the name of the attribute | |||||
*/ | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
/** | |||||
* The optional attribute of the text element. | |||||
* | |||||
* @param optional if true this is optional | |||||
*/ | |||||
public void setOptional(boolean optional) { | |||||
this.optional = optional; | |||||
} | |||||
/** | |||||
* @return true if the text is optional | |||||
*/ | |||||
public boolean getOptional() { | |||||
return optional; | |||||
} | |||||
/** | |||||
* The trim attribute of the text element. | |||||
* | |||||
* @param trim if true this String.trim() is called on | |||||
* the contents of the text element. | |||||
*/ | |||||
public void setTrim(boolean trim) { | |||||
this.trim = trim; | |||||
} | |||||
/** | |||||
* @return true if the text is trim | |||||
*/ | |||||
public boolean getTrim() { | |||||
return trim; | |||||
} | |||||
/** | |||||
* @param desc Description of the text. | |||||
*/ | |||||
public void setDescription(String desc) { | |||||
description = desc; | |||||
} | |||||
/** | |||||
* @return the description of the text, or <code>null</code> if | |||||
* no description is available. | |||||
*/ | |||||
public String getDescription() { | |||||
return description; | |||||
} | |||||
/** | |||||
* equality method | |||||
* | |||||
* @param obj an <code>Object</code> value | |||||
* @return a <code>boolean</code> value | |||||
*/ | |||||
public boolean equals(Object obj) { | |||||
if (obj == null) { | |||||
return false; | |||||
} | |||||
if (obj.getClass() != getClass()) { | |||||
return false; | |||||
} | |||||
Text other = (Text) obj; | |||||
if (name == null) { | |||||
if (other.name != null) { | |||||
return false; | |||||
} | |||||
} else if (!name.equals(other.name)) { | |||||
return false; | |||||
} | |||||
if (optional != other.optional) { | |||||
return false; | |||||
} | |||||
if (trim != other.trim) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* @return a hash code value for this object. | |||||
*/ | |||||
public int hashCode() { | |||||
return objectHashCode(name); | |||||
} | |||||
} | |||||
/** | /** | ||||
* A nested element for the MacroDef task. | * A nested element for the MacroDef task. | ||||
* | * | ||||
@@ -519,12 +654,12 @@ public class MacroDef extends AntlibDefinition { | |||||
if (!name.equals(other.name)) { | if (!name.equals(other.name)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (textName == null) { | |||||
if (other.textName != null) { | |||||
if (text == null) { | |||||
if (other.text != null) { | |||||
return false; | return false; | ||||
} | } | ||||
} else { | } else { | ||||
if (!textName.equals(other.textName)) { | |||||
if (!text.equals(other.text)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -88,7 +88,7 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
private Map nsElements = null; | private Map nsElements = null; | ||||
private Map presentElements = new HashMap(); | private Map presentElements = new HashMap(); | ||||
private Hashtable localProperties = new Hashtable(); | private Hashtable localProperties = new Hashtable(); | ||||
private String text = ""; | |||||
private String text = null; | |||||
/** | /** | ||||
* Called from MacroDef.MyAntTypeDefinition#create() | * Called from MacroDef.MyAntTypeDefinition#create() | ||||
@@ -251,6 +251,7 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
* Set the text contents for the macro. | * Set the text contents for the macro. | ||||
* @param text the text to be added to the macro. | * @param text the text to be added to the macro. | ||||
*/ | */ | ||||
public void addText(String text) { | public void addText(String text) { | ||||
this.text = text; | this.text = text; | ||||
} | } | ||||
@@ -340,10 +341,25 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||||
if (copyKeys.contains("id")) { | if (copyKeys.contains("id")) { | ||||
copyKeys.remove("id"); | copyKeys.remove("id"); | ||||
} | } | ||||
if (macroDef.getTextName() != null) { | |||||
localProperties.put(macroDef.getTextName(), text); | |||||
if (macroDef.getText() != null) { | |||||
if (text == null) { | |||||
if (!macroDef.getText().getOptional()) { | |||||
throw new BuildException( | |||||
"required text missing"); | |||||
} | |||||
text = ""; | |||||
} | |||||
if (macroDef.getText().getTrim()) { | |||||
text = text.trim(); | |||||
} | |||||
localProperties.put(macroDef.getText().getName(), text); | |||||
} else { | |||||
if (text != null && !text.trim().equals("")) { | |||||
throw new BuildException( | |||||
"The \"" + getTaskName() + "\" macro does not support" | |||||
+ " nested text data."); | |||||
} | |||||
} | } | ||||
if (copyKeys.size() != 0) { | if (copyKeys.size() != 0) { | ||||
throw new BuildException( | throw new BuildException( | ||||
"Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ") | "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ") | ||||
@@ -116,15 +116,25 @@ public class MacroDefTest extends BuildFileTest { | |||||
"nested elementnested element"); | "nested elementnested element"); | ||||
} | } | ||||
public void testTextName() { | |||||
public void testTextElement() { | |||||
expectLogContaining( | expectLogContaining( | ||||
"textname", "Hello world"); | |||||
"textelement", "Hello world"); | |||||
} | |||||
public void testTextTrim() { | |||||
expectLogContaining( | |||||
"text.trim", "[Hello world]"); | |||||
} | } | ||||
public void testDuplicateTextName() { | public void testDuplicateTextName() { | ||||
expectBuildException( | expectBuildException( | ||||
"duplicatetextname", | "duplicatetextname", | ||||
"the attribute text has already been specified"); | |||||
"the name \"text\" is already used as an attribute"); | |||||
} | |||||
public void testDuplicateTextName2() { | |||||
expectBuildException( | |||||
"duplicatetextname2", | |||||
"the attribute name \"text\" has already been used by the text element"); | |||||
} | } | ||||
} | } | ||||