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"); | |||||
| } | } | ||||
| } | } | ||||