git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275731 13f79535-47bb-0310-9956-ffa450edef68master
@@ -817,10 +817,10 @@ | |||
<macrodef name="optional-jar"> | |||
<attribute name="dep"/> | |||
<sequential> | |||
<jar destfile="${build.lib}/${optional.jars.prefix}-${dep}.jar" | |||
<jar destfile="${build.lib}/${optional.jars.prefix}-@{dep}.jar" | |||
basedir="${build.classes}" | |||
manifest="${manifest.tmp}"> | |||
<selector refid="needs.${dep}"/> | |||
<selector refid="needs.@{dep}"/> | |||
</jar> | |||
</sequential> | |||
</macrodef> | |||
@@ -3,6 +3,11 @@ | |||
<head> | |||
<meta http-equiv="Content-Language" content="en-us"></meta> | |||
<title>MacroDef Task</title> | |||
<style type="text/css"> | |||
<!-- | |||
.code { background: #EFEFEF; margin-top: } | |||
--> | |||
</style> | |||
</head> | |||
<body> | |||
@@ -49,8 +54,12 @@ | |||
</p> | |||
<p> | |||
This attribute is placed in the body of the templated | |||
task using the ant property notation - ${attribute name}. | |||
Note that is not an actual ant property. | |||
task using a notation similar to the ant property notation | |||
- @{attribute name}. (May be remembered as "put the substitution | |||
AT this location"). | |||
The escape sequence @@{x} is used to allow @{x} to be | |||
placed in the text without substitution of x. | |||
This corresponds to the $${x} escape sequence for properties | |||
</p> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
@@ -107,12 +116,12 @@ | |||
runs it. | |||
</p> | |||
<blockquote> | |||
<pre> | |||
<pre class=code> | |||
<macrodef name="testing"> | |||
<attribute name="v" default="NOT SET"/> | |||
<element name="some-tasks" optional="yes"/> | |||
<sequential> | |||
<echo>v is ${v}</echo> | |||
<echo>v is @{v}</echo> | |||
<some-tasks/> | |||
</sequential> | |||
</macrodef> | |||
@@ -122,7 +131,7 @@ | |||
<echo>this is a test</echo> | |||
</some-tasks> | |||
</testing> | |||
</pre> | |||
</pre> | |||
</blockquote> | |||
<p> | |||
The following fragment defines a task called <call-cc> which | |||
@@ -132,29 +141,29 @@ | |||
<a href="http://ant-contrib.sourceforge.net/">ant-contrib</a> project. | |||
</p> | |||
<blockquote> | |||
<pre> | |||
<pre class="code"> | |||
<macrodef name="call-cc"> | |||
<attribute name="target"/> | |||
<attribute name="link"/> | |||
<attribute name="target.dir"/> | |||
<element name="cc-elements"/> | |||
<sequential> | |||
<mkdir dir="${obj.dir}/${target}"/> | |||
<mkdir dir="${target.dir}"/> | |||
<cc link="${link}" objdir="${obj.dir}/${target}" | |||
outfile="${target.dir}/${target}"> | |||
<mkdir dir="${obj.dir}/@{target}"/> | |||
<mkdir dir="@{target.dir}"/> | |||
<cc link="@{link}" objdir="${obj.dir}/@{target}" | |||
outfile="@{target.dir}/@{target}"> | |||
<compiler refid="compiler.options"/> | |||
<cc-elements/> | |||
</cc> | |||
</sequential> | |||
</macrodef> | |||
</pre> | |||
</pre> | |||
</blockquote> | |||
<p> | |||
This then can be used as follows: | |||
</p> | |||
<blockquote> | |||
<pre> | |||
<pre class="code"> | |||
<call-cc target="unittests" link="executable" | |||
target.dir="${build.bin.dir}"> | |||
<cc-elements> | |||
@@ -165,7 +174,7 @@ | |||
<linker refid="linker-libs"/> | |||
</cc-elements> | |||
</call-cc> | |||
</pre> | |||
</pre> | |||
</blockquote> | |||
<hr> | |||
<p align="center">Copyright © 2003 Apache Software | |||
@@ -89,7 +89,7 @@ | |||
<attribute name="dir"/> | |||
<sequential> | |||
<antcontrib:shellscript shell="bash"> <!-- HERE --> | |||
ls -Rl ${dir} | |||
ls -Rl @{dir} | |||
</antcontrib:shellscript> | |||
</sequential> | |||
</macrodef> | |||
@@ -132,7 +132,7 @@ | |||
<element name="do"/> | |||
<sequential> | |||
<current:if> | |||
<current:isallowed test="${action}"/> | |||
<current:isallowed test="@{action}"/> | |||
<current:then> | |||
<current:do/> | |||
</current:then> | |||
@@ -4,7 +4,7 @@ | |||
<macrodef name="my.echo"> | |||
<attribute name="text"/> | |||
<sequential> | |||
<echo message="${text}"/> | |||
<echo message="@{text}"/> | |||
</sequential> | |||
</macrodef> | |||
<my.echo text="Hello World"/> | |||
@@ -14,7 +14,7 @@ | |||
<macrodef name="my.echo"> | |||
<attribute name="text"/> | |||
<sequential> | |||
<echo>${text}</echo> | |||
<echo>@{text}</echo> | |||
</sequential> | |||
</macrodef> | |||
<my.echo text="Inner Text"/> | |||
@@ -25,7 +25,7 @@ | |||
<attribute name="text"/> | |||
<attribute name="text"/> | |||
<sequential> | |||
<echo>${text}</echo> | |||
<echo>@{text}</echo> | |||
</sequential> | |||
</macrodef> | |||
</target> | |||
@@ -44,7 +44,7 @@ | |||
<macrodef name="echo" uri="abc"> | |||
<attribute name="text"/> | |||
<sequential> | |||
<echo message="${text}"/> | |||
<echo message="@{text}"/> | |||
</sequential> | |||
</macrodef> | |||
<x:echo xmlns:x="abc" text="Hello World"/> | |||
@@ -65,4 +65,14 @@ | |||
</nested> | |||
</target> | |||
<target name="double"> | |||
<macrodef name="double"> | |||
<attribute name="prop"/> | |||
<sequential> | |||
<echo>@@{prop} is '@{prop}', value of $${@{prop}} is '${@{prop}}'</echo> | |||
</sequential> | |||
</macrodef> | |||
<property name="property" value="A property value"/> | |||
<double prop="property"/> | |||
</target> | |||
</project> |
@@ -78,8 +78,8 @@ import org.apache.tools.ant.UnknownElement; | |||
public class MacroDef extends AntlibDefinition { | |||
private NestedSequential nestedSequential; | |||
private String name; | |||
private Map attributes = new HashMap(); | |||
private Map elements = new HashMap(); | |||
private List attributes = new ArrayList(); | |||
private Map elements = new HashMap(); | |||
/** | |||
* Name of the definition | |||
@@ -170,7 +170,7 @@ public class MacroDef extends AntlibDefinition { | |||
/** | |||
* @return the nested Attributes | |||
*/ | |||
public Map getAttributes() { | |||
public List getAttributes() { | |||
return attributes; | |||
} | |||
@@ -221,12 +221,15 @@ public class MacroDef extends AntlibDefinition { | |||
throw new BuildException( | |||
"the attribute nested element needed a \"name\" attribute"); | |||
} | |||
if (attributes.get(attribute.getName()) != null) { | |||
throw new BuildException( | |||
"the attribute " + attribute.getName() | |||
+ " has already been specified"); | |||
for (int i = 0; i < attributes.size(); ++i) { | |||
if (((Attribute) attributes.get(i)).getName().equals( | |||
attribute.getName())) { | |||
throw new BuildException( | |||
"the attribute " + attribute.getName() | |||
+ " has already been specified"); | |||
} | |||
} | |||
attributes.put(attribute.getName(), attribute); | |||
attributes.add(attribute); | |||
} | |||
/** | |||
@@ -347,6 +350,13 @@ public class MacroDef extends AntlibDefinition { | |||
} | |||
return true; | |||
} | |||
/** | |||
* @return a hash code value for this object. | |||
*/ | |||
public int hashCode() { | |||
return objectHashCode(defaultValue) + objectHashCode(name); | |||
} | |||
} | |||
/** | |||
@@ -416,6 +426,13 @@ public class MacroDef extends AntlibDefinition { | |||
} | |||
return optional == other.optional; | |||
} | |||
/** | |||
* @return a hash code value for this object. | |||
*/ | |||
public int hashCode() { | |||
return objectHashCode(name) + (optional ? 1 : 0); | |||
} | |||
} | |||
/** | |||
@@ -463,6 +480,17 @@ public class MacroDef extends AntlibDefinition { | |||
return true; | |||
} | |||
/** | |||
* @return a hash code value for this object. | |||
*/ | |||
public int hashCode() { | |||
return objectHashCode(name) | |||
+ objectHashCode(getURI()) | |||
+ objectHashCode(nestedSequential) | |||
+ objectHashCode(attributes) | |||
+ objectHashCode(elements); | |||
} | |||
/** | |||
* extends AntTypeDefinition, on create | |||
* of the object, the template macro definition | |||
@@ -526,4 +554,12 @@ public class MacroDef extends AntlibDefinition { | |||
return macroDef.equals(otherDef.macroDef); | |||
} | |||
} | |||
private static int objectHashCode(Object o) { | |||
if (o == null) { | |||
return 0; | |||
} else { | |||
return o.hashCode(); | |||
} | |||
} | |||
} |
@@ -87,7 +87,6 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
private Map nsElements = null; | |||
private Map presentElements = new HashMap(); | |||
private Hashtable localProperties = new Hashtable(); | |||
/** | |||
* Called from MacroDef.MyAntTypeDefinition#create() | |||
@@ -142,7 +141,7 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
} | |||
return nsElements; | |||
} | |||
/** | |||
* Embedded element in macro instance | |||
*/ | |||
@@ -166,11 +165,15 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
} | |||
} | |||
private static final int STATE_NORMAL = 0; | |||
private static final int STATE_NORMAL = 0; | |||
private static final int STATE_EXPECT_BRACKET = 1; | |||
private static final int STATE_EXPECT_NAME = 2; | |||
private static final int STATE_EXPECT_NAME = 2; | |||
private static final int STATE_EXPECT_EXCAPE = 3; | |||
private String macroSubs(String s, Map macroMapping) { | |||
if (s == null) { | |||
return null; | |||
} | |||
StringBuffer ret = new StringBuffer(); | |||
StringBuffer macroName = null; | |||
boolean inMacro = false; | |||
@@ -179,48 +182,67 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
char ch = s.charAt(i); | |||
switch (state) { | |||
case STATE_NORMAL: | |||
if (ch == '$') { | |||
state = 1; | |||
if (ch == '@') { | |||
state = STATE_EXPECT_BRACKET; | |||
} else { | |||
ret.append(ch); | |||
} | |||
} | |||
break; | |||
case STATE_EXPECT_BRACKET: | |||
if (ch == '{') { | |||
state = 2; | |||
state = STATE_EXPECT_NAME; | |||
macroName = new StringBuffer(); | |||
} else if (ch == '@') { | |||
state = STATE_EXPECT_EXCAPE; | |||
} else { | |||
state = 0; | |||
ret.append('$'); | |||
state = STATE_NORMAL; | |||
ret.append('@'); | |||
ret.append(ch); | |||
} | |||
break; | |||
case STATE_EXPECT_NAME: | |||
if (ch == '}') { | |||
state = 0; | |||
state = STATE_NORMAL; | |||
String name = macroName.toString(); | |||
String value = (String) macroMapping.get(name); | |||
if (value == null) { | |||
ret.append("${" + name + "}"); | |||
ret.append("@{" + name + "}"); | |||
} else { | |||
ret.append(value); | |||
} | |||
macroName = null; | |||
} else { | |||
macroName.append(s.charAt(i)); | |||
macroName.append(ch); | |||
} | |||
break; | |||
case STATE_EXPECT_EXCAPE: | |||
state = STATE_NORMAL; | |||
if (ch == '{') { | |||
ret.append("@"); | |||
} else { | |||
ret.append("@@"); | |||
} | |||
ret.append(ch); | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
switch (state) { | |||
case STATE_NORMAL: | |||
break; | |||
case STATE_EXPECT_BRACKET: | |||
ret.append('$'); | |||
ret.append('@'); | |||
break; | |||
case STATE_EXPECT_NAME: | |||
ret.append("${"); | |||
ret.append("@{"); | |||
ret.append(macroName.toString()); | |||
break; | |||
case STATE_EXPECT_EXCAPE: | |||
ret.append("@@"); | |||
break; | |||
default: | |||
break; | |||
} | |||
return ret.toString(); | |||
@@ -294,12 +316,12 @@ public class MacroInstance extends Task implements DynamicConfigurator { | |||
public void execute() { | |||
localProperties = new Hashtable(); | |||
Set copyKeys = new HashSet(map.keySet()); | |||
for (Iterator i = macroDef.getAttributes().values().iterator(); | |||
i.hasNext();) { | |||
for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) { | |||
MacroDef.Attribute attribute = (MacroDef.Attribute) i.next(); | |||
String value = (String) map.get(attribute.getName()); | |||
if (value == null) { | |||
value = attribute.getDefault(); | |||
value = macroSubs(value, localProperties); | |||
} | |||
if (value == null) { | |||
throw new BuildException( | |||
@@ -98,5 +98,10 @@ public class MacroDefTest extends BuildFileTest { | |||
expectLog("nested", "A nested element"); | |||
} | |||
public void testDouble() { | |||
expectLog( | |||
"double", | |||
"@{prop} is 'property', value of ${property} is 'A property value'"); | |||
} | |||
} | |||