The XML syntax used by Fusebox since the 4.0 version allows for conditional expressions like these:
<if condition="x GT 4"> <true> <set name="y" value="7" /> </true> <false> <set name="y" value="3" /> </false> </if> <if condition="name EQ 'barney'"> <true> <set name="session.isSuperUser" value="true" /> </true> </if>
In the latter case, the <true> tags are basically irrelevant, because they provide the same containership and semantic as the <if> tag itself. Fusebox 5.0 and older allowed you to omit the <true> tags in this case:
<if condition="name EQ 'barney'"> <set name="session.isSuperUser" value="true" /> </if>
This only makes sense if you don't have a <false> block, because if you have both blocks, then the <if> tag doesn't provide the correct containership.
Fusebox 5.5, however, made the <true> tag required even for the simple case. This is unfortunate, I think, because it adds needless verbosity, and from digging around in the code, I suspect that it was primarily driven by implementation limitations, rather than user requests.
As part of migrating an app from 5.0 to 5.5.1, I really didn't want to have to go back and add all those extra tags, nor deal with the extra verbosity when maintaining the application down the road. So I wrote a small patch for the core files that will allow an implicit <true> tag in the 5.0 style when using the 5.5.1 cores:
Index: fuseboxVerb.cfc
===================================================================
--- fuseboxVerb.cfc (revision 778)
+++ fuseboxVerb.cfc (working copy)
@@ -33,20 +33,26 @@
<cfset variables.action = arguments.action />
<cfset variables.attributes = arguments.attributes />
+ <cfset variables.factory = factory />
<!--- we will create our children below --->
<cfset variables.verb = listLast(arguments.customVerb,".:") />
- <cfset variables.children = structNew() />
-
- <cfset variables.factory = factory />
- <cfset variables.nChildren = arrayLen(arguments.children) />
-
- <cfloop from="1" to="#variables.nChildren#" index="i">
- <cfset verb = arguments.children[i].xmlName />
- <cfset variables.children[i] = factory.create(verb,
- variables.action,
- arguments.children[i].xmlAttributes,
- arguments.children[i].xmlChildren) />
- </cfloop>
+
+ <cfif isStruct(arguments.children)>
+ <!--- This is an IR manipulation so we already have domain objects for children, rather than XML nodes. --->
+ <cfset variables.children = arguments.children />
+ <cfset variables.nChildren = structCount(variables.children) />
+ <cfelse>
+ <cfset variables.children = structNew() />
+ <cfset variables.nChildren = arrayLen(arguments.children) />
+
+ <cfloop from="1" to="#variables.nChildren#" index="i">
+ <cfset verb = arguments.children[i].xmlName />
+ <cfset variables.children[i] = factory.create(verb,
+ variables.action,
+ arguments.children[i].xmlAttributes,
+ arguments.children[i].xmlChildren) />
+ </cfloop>
+ </cfif>
<cfset variables.fb41style = listLen(arguments.customVerb,".") eq 2 />
<cfif variables.fb41style>
Index: verbs/if.cfm
===================================================================
--- verbs/if.cfm (revision 778)
+++ verbs/if.cfm (working copy)
@@ -35,13 +35,9 @@
// at most one <true>, at most one <false>, nothing else:
fb_.hasTrue = false;
fb_.hasFalse = false;
+ fb_.verbInfo.hasOther = false;
for (fb_.i = 1; fb_.i lte fb_.verbInfo.nChildren; fb_.i = fb_.i + 1) {
- if (fb_.verbInfo.children[fb_.i].getNamespace() is not "") {
- fb_throw("fusebox.badGrammar.illegalVerb",
- "Illegal verb",
- "An 'if' may contain only 'true' and 'false' verbs in fuseaction #fb_.verbInfo.circuit#.#fb_.verbInfo.fuseaction#.");
- }
- switch (fb_.verbInfo.children[fb_.i].getVerb()) {
+ switch (fb_.verbInfo.children[fb_.i].getNamespace() & fb_.verbInfo.children[fb_.i].getVerb()) {
case "true":
if (fb_.hasTrue) {
fb_throw("fusebox.badGrammar.illegalVerb",
@@ -61,10 +57,41 @@
}
break;
default:
+ fb_.verbInfo.hasOther = true;
+ break;
+ }
+ }
+ if (fb_.verbInfo.hasOther) {
+ if (fb_.hasTrue OR fb_.hasFalse OR fb_.verbInfo.action.getCircuit().getApplication().strictMode) {
fb_throw("fusebox.badGrammar.illegalVerb",
"Illegal verb",
"An 'if' may contain only 'true' and 'false' verbs in fuseaction #fb_.verbInfo.circuit#.#fb_.verbInfo.fuseaction#.");
- break;
+ } else {
+ // only non-true/false and not strict mode, so wrap an implicit true around the children
+ // we have to do some acrobatics around the 'children' references
+ fb_.children = structNew();
+ for (fb_.i = 1; fb_.i lte fb_.verbInfo.nChildren; fb_.i = fb_.i + 1) {
+ fb_.children[fb_.i] = fb_.verbInfo.children[fb_.i];
+ }
+ structClear(fb_.verbInfo.children);
+ fb_.factory = fb_.verbInfo.action.getCircuit().getApplication().getFuseactionFactory();
+ fb_.implicitTrue = fb_.factory.create(
+ "true",
+ fb_.verbInfo.action,
+ structNew(),
+ fb_.children
+ );
+ fb_.verbInfo.children[1] = fb_.implicitTrue;
+ // now null out the remaining children
+ for (fb_.i = 2; fb_.i lte fb_.verbInfo.nChildren; fb_.i = fb_.i + 1) {
+ fb_.verbInfo.children[fb_.i] = fb_.factory.create(
+ "noop",
+ fb_.verbInfo.action,
+ structNew(),
+ arrayNew(1)
+ );
+ }
+ fb_.hasTrue = true;
}
}
Index: verbs/noop.cfm
===================================================================
--- verbs/noop.cfm (revision 0)
+++ verbs/noop.cfm (revision 0)
@@ -0,0 +1 @@
+<cfset fb_appendLine('<!--- no op: #fb_.verbInfo.executionMode# --->') />
The implementation is kind of hacky because the XML compiler lacks a IR transformation step, so I had to fake one. And that was further complicated by the parallelism in the internal datastructures, necessitating the creation of a "noop" verb to use as a placeholder in certain situation. More specifically, there isn't a way to add or remove verbs from the parse tree, only to change verbs, and implementing the functionality within that constraint required some "creative" programming. ;)
