04 Tag Usage - oldgreydog/CodeGenerator GitHub Wiki
The flow control tags can be used anywhere, including nested inside other flow control tags (or themselves, for that matter). For a more in-depth look at each of the tags, please refer to the javadocs. Here are examples of the flow control tags:
<%foreach node=column%>
...
<%endfor%>
Note: any number of elseif
tags can be used inside an if
tag.
<%if <%type%> = Integer %>
...
<%elseif <%type%> = Long %>
...
<%else%>
...
<%endif%>
first
blocks can technically be nested inside themselves, but it wouldn't make any sense to do so.
<%first%>
...
<%else%>
...
<%endfirst%>
The text
tag is special. You can have text inside or outside of flow control blocks, but you can not have flow control blocks inside a text
tag. A text
tag can have anything from a single character in it up to any number of lines. There are also certain special tags that can appear inside a text
tag. Here's the text
tag:
<%text%>
...
<%endtext%>
Here are the tags that be inside a text
block. Note that the one common aspect of all of these tags is that none of them have closing tags like the flow control tags.
The config variable is a unique tag type because it looks like all the other tags because it uses the opening and closing delimiters, but the name inside the delimiters is the name of a value from the config values file. That also means that the other tag names are reserved and cannot be used as config value names. Here's an example:
<%className%>
These are the other tags that can appear inside a text
block:
<%customCode key=LoadAll<%className%>CacheCode commentCharacters=// %>
<%firstLetterToLowerCase member = <%className%> %>
<%tabMarker%>
<%tabStop stopType = "stop" offset = "40" %>
<%typeConvert targetLanguage = "java" sourceType = <%type%> groupID = "builtin" %>
Note that, as you can see in the examples, since the config variable and typeConvert
tags (and technically the firstLetterToLowerCase
tag) evaluate to strings, they can be used in the values of other tag's attributes (usually the if
/elseif
tags).
There are two tags left. The first is the tabSettings
tag. If a template uses either tabMarker
or tabStop
, then you have to have a tabSettings
that appears first to define the tab length and whether the tabs will be output as spaces or tabs. Here is an example:
<%tabSettings tabLength = "4" outputType = "tabs" %>
And the last tag is the decrement counter tag. It looks like this:
<%--counter%>
This is a special tag to use in conjunction with a first
block inside a foreach
block. There will be times when you need to build a delimited list of values (such as a parameter list), but one or more of the first items in the list may need to be skipped. When that happens, you need to use the --counter
tag to bump the loop counter back one each time you skip so that when you do get to the first item you want to add to the list, then the first
block will work correctly.
Custom code blocks let you designate spots in the output where users can enter custom code that will be protected the next time the generator is run on top of those files. Here again is the tag example from above:
<%customCode key=LoadAll<%className%>CacheCode commentCharacters=// %>
The commentCharacters
attribute lets you specify the single-line comment symble(s) that are appropriate for the language being generated. The key
attribute is the critical one to get right though. When you run the generator on top of existing files, it parses each existing file that it finds before it generates on top of it to see if it has custom code in it. Each time it finds a custom code block, it uses the key to store the text found in that block in a map. When the generator is then generating the new version of the file, each time a customCode
handler is evaluated, it builds the key and then uses it to search in the map of custom code pulled from the old file. If it finds it, then it inserts that custom code back into the new file.
!!!NOTE!!! Generated files are not in any way "holy", untouchable objects. You can change any part of them, custom code block or not. However, if you change code outside a custom code block, you can never regenerate on top of them again. If you do, you will blow away those changes. For this reason, I have always generated to a location separate from my project tree and then used BeyondCompare to merge the changes into the project. If you also merge any custom code blocks back to the generation tree, then the only differences you have to merge around are the new ones from the new generation and the customized code in the project. While that simplifies the merge as much as possible, having to merge still makes things more of a pain in the rear. But if you customize outside of custom code blocks, then it's your only option.