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. ;)
Comments are closed.