ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Reilly <peterrei...@apache.org>
Subject Re: About <macrodef> in the trenches
Date Fri, 10 Dec 2004 15:15:32 GMT
All these features sould great.

1) this attribute is good.
     however,  it is only really usefull in combination with the iftrue 
attribute,
     or with ant-contrib "if" task

2) a default value for the element is good. The default value should
    be in the declaration, but it is ok to have it the body of the
    macrodef.

3) this sounds good if a little stange initially.

4) this is good as well, if one is useing elements with macrodefs a lot. 
It may
    be a bit confusing.

I would say go for it!

Peter

Dominique Devienne wrote:

>This past two weeks, I've worked on coming up with a generic build file
>for our multiple projects, which I'd say are 80% to 99% common from one
>project to the next. Of course, I'm using heavily <import>, target
>overriding, and <macrodef>, but even with these fine features, it's not
>always easy to accomodate the variations from one build to the next, 
>especially if I want to avoid having to rewrite whole tasks/targets.
> 
>To achieve this maximum reuse, and minimum overriding, i.e. to avoid being
>forced to rewrite whole tasks, I've defined complex macros with built-in
>conditionals, and lots of default attributes. Alas, there's no default
>'value' for macro elements, so providing default tags for a macro element
>is currently not possible. I believe this lack of element default makes
><macrodef> less powerful that it can be.
> 
>So finally today I had a look at the macrodef code, and tried to understand
>how things worked under the hood. I was surprised to find out I understood
>the code ;-) (if I glossed over most of the UE/RC cuisine that is).
> 
>  BTW, I'm amazed this can all be implemented in a couple of tasks with no
>  changes to the framework itself. The new fully dynamic nature of Ant 1.6
>  (everything's a UE) is powerful indeed!
> 
>I then proceeded to copy MacroDef/MacroInstance to my own antlib, and
>amazingly after repackaging and adding a single import, everything worked
>fine. (I duplicate the code because we only use an official Ant release.)
>I then tweaked <macrodef> to add the following features:
> 
>1) Everytime a macro attribute or element is explicitly defined in a macro
>   instance (where the macro is used), I define an additional macro attribute
>   (local property in the code) which allows to find out in the macro body
>   whether the attribute or element was explicitly used/specified.
>   When an 'foo' attribute is used, I define '@foo?' with value of true.
>   When an 'bar' element is used, I define 'bar?' with value of true
>   My macro bodies/impls then do things or not (or differently) based on
>   this info. For example:
> 
>     <bm:macrodef name="my-copy">
>      ...
>      <attribute name="tos" default="/dev/null" />
>      <sequential>
>        ...
>        <bm:sequential ifTrue="@{@tos?}">
>          <copy file="@{tos}" tofile="..." />
>        </bm:sequential>
>      </sequential>
>    </bm:macrodef>
>    <bm:macrodef name="my-module-image">
>      ...
>      <element name="sources" optional="true" />
>      <sequential>
>        ...
>        <bm:sequential ifTrue="@{@sources?}">
>          <zip destfile="@{todir}/sdk/src.zip">
>            <sources />
>          </zip>
>        </bm:sequential>
>      </sequential>
>    </bm:macrodef>
> 
>2) Allow defining an macro element 'default value'. Instead of the default
>   being inside the <macrodef> <element>, its inside the macro <sequential>
>   where the element is used. I did it this way because the implementation
>   was easier, and it makes it easy to read the macro impl, although it
>   could be confusing to some I guess?!
>   If a macro element is not explicitly specified in the macro instance,
>   and the element is optional, then the 'default value' from the macro
>   definition is used. If specified, the macro instance value is used as
>   usual otherwise. For example:
> 
>    <bm:macrodef name="my-register">
>      ...
>      <element name="patterns" optional="true" />
>      <sequential>
>        <ds:register ...>
>          ...
>          <fileset dir="@{dir}">
>            <patterns>
>              <include name="**/*.class" />
>              <exclude name="**/test/*Test.class" />
>            </patterns>
>          </fileset>
>        </ds:register>
>      </sequential>
>    </bm:macrodef>
> 
>    The macro above defaults the patterns element to 1 include + 1 exclude.
> 
>3) When coming up with elements a macro could contain, I often end up
>   wanting to contain a classpath macro element that I want to pass in
>   to <java> or another task taking a classpath. If I can't use the single
>   implicit element for some reason, I then have to do something ugly:
> 
>   <macrodef name="ugly">
>     ...
>     <element name="my-classpath" optional="true" />
>     <sequential>
>       ...
>       <java ...>
>         <my-classpath />
>       </java>
>     </sequential>
>   </macrodef>
> 
>  and I'm forced to use:
> 
>  <ugly>
>    <my-classpath>
>      <classpath refid="classpath" />
>    </my-classpath>
>  </ugly>
> 
>  If I throw in element defaults from (2), the macro becomes:
> 
>   <macrodef name="ugly">
>     ...
>     <element name="my-classpath" optional="true" />
>     <sequential>
>       ...
>       <java ...>
>         <my-classpath>
>           <classpath refid="classpath" />
>         </my-classpath>
>       </java>
>     </sequential>
>   </macrodef>
> 
>  To work around this, I added a new useContentOnly attribute to <element>,
>  which defaults to true for BC, but when false, allows to pass in the element
>  itself as-is, as defined in the macro definition or instance. I can now do
> 
>   <macrodef name="nicer">
>     ...
>     <element name="classpath" optional="true" useContentOnly="false" />
>     <sequential>
>       ...
>       <java ...>
>         <classpath refid="classpath" />
>       </java>
>     </sequential>
>   </macrodef>
> 
>  and I can use it as
> 
>  <nicer />
> 
>  or
> 
>  <nicer>
>    <classpath refid="alt.classpath" />
>  </nicer>
> 
>  or 
> 
>  <nicer>
>    <classpath>
>      <pathelement location="..." />
>      <path refid="classpath" />
>    </classpath>
>  </nicer>
> 
>  With (2) + (3), you can take some ant code composed of 3 tasks for example,
>  put it in a macro, and define an optional element for each task with
>  useContentOnly="false", and have the macro user be able to override only
>  one of the macro's task.
> 
>  To be truly complete, we'd also need a way to refer to the default content
>  of the element to reuse it in the macro instance itself (i.e super).
>  I haven't done that.
> 
>4) Finally, the last thing I did was to allow using the macro attributes
>   in the macro instance, to benefit from the default values computed by
>   the macro. Currently, if one defines:
> 
>   <macrodef name="macrosub">
>     <attribute name="primary" default="foo" />
>     <attribute name="secondary" default="@{primary}bar" />
>     <element name="nested-elements" optional="true" implicit="true" />
>     <sequential>
>       <nested-elements />
>     </sequential>
>   </macrodef>
> 
>   and does:
> 
>   <macrosub>
>     <echo>secondary = @{secondary}</echo>
>   </macrosub>
> 
>   One will not get secondary = foobar, because the macro instance does
>   not have access to the macro 'local properties', which includes the
>   computed default attributes. I consider 'secondary' to be part of the
>   macro API, and thus logic that it can be used in the macro instance.
>   Implementation wise, it means using copy() more often.
> 
>My changes are not extensive, and are mostly in MacroInstance#copy and
>the addition of MacroDef.TemplateElement#setUseContentOnly.
>I'd appreciate some feedback on whether these new features are desirable.
>I believe there would be zero BC issues. Thanks, --DD
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
>For additional commands, e-mail: dev-help@ant.apache.org
>
>
>
>  
>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Mime
View raw message