To ease my befuddlement, I wrote a test for the Closures library. The use case for the below example is summing a column that contains non-numeric values. You can recreate the test by following these steps:

You now have 100 rows of data and every 5th row contains the string 'Not Applicable'.

The goal of this is to sum the column 'Amount' and output the result. The closure has an internal scope and can keep the running total. The function body used to create the closure is rather simplistic and takes two arguments, Mode and valueToTotal. The logic of the function simply adds the valueToTotal to the running total. Passing a mode of 'Display' will output the current total.

<!--- We need an internal scope to hold the total so lets make sure one exists before we access it ---> <cfif NOT structKeyExists( variables, "total") > <cfset variables.total = 0 /> </cfif>

<cfif arguments.mode IS "Display"> <!--- Are we trying to display the running total amount ---> <cfreturn val( variables.total ) /> <cfelse><!--- No, we are passing in a value to total ---> <!--- add the value and account for strings by converting to 0 ---> <cfset variables.total = variables.total + val( arguments.valueToTotal ) /> <!--- pass back the original value ---> <cfreturn arguments.valueToTotal /> </cfif>

</cffunction>

<!--- add the closure to a new variable called total. We use total to reference the closure ---><cfset total = cf.new(runningTotal) />1<!--- Create the ClosureFactory --->2<cfset cf = createObject("component","org.corfield.closure.ClosureFactory") />34<!--- Create the runningTotal function --->5<cffunction name="runningTotal" >6<cfargument name="mode" type="string" required="true"/>7<cfargument name="valueToTotal" type="string" default="" />89<!--- We need an internal scope to hold the total so lets make sure one exists before we access it --->10<cfif NOT structKeyExists( variables, "total") >11<cfset variables.total = 0 />12</cfif>1314<cfif arguments.mode IS "Display"><!--- Are we trying to display the running total amount --->15<cfreturn val( variables.total ) />16<cfelse><!--- No, we are passing in a value to total --->17<!--- add the value and account for strings by converting to 0 --->18<cfset variables.total = variables.total + val( arguments.valueToTotal ) />19<!--- pass back the original value --->20<cfreturn arguments.valueToTotal />21</cfif>2223</cffunction>2425<!--- add the closure to a new variable called total. We use total to reference the closure --->26<cfset total = cf.new(runningTotal) />

Now, we write all the records from the Invoice table to the screen. Note the use of the closure to output the amount. We also call the same closure method with a different mode to output the Grand Total.

ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org<!--- Now query the Database for all the records ---><cfquery name="getInvoice" datasource="test"> SELECT InvoiceID, CreateDate, Amount FROM Invoice</cfquery>

<cfoutput> <cfloop query="getInvoice"> <!--- output the date and the amount using the closure call ---> #DateFormat(CreateDate, "mm/dd/yyyy")# #total.call(mode='sum',valueToTotal=Amount)#<br /> </cfloop><!--- Now output the value of the running total ---> <strong>Grand Total: #total.call(mode='Display')#</strong><br /> </cfoutput>1<!--- Now query the Database for all the records --->2<cfquery name="getInvoice" datasource="test">3SELECT InvoiceID, CreateDate, Amount4FROM Invoice5</cfquery>67<cfoutput>8<cfloop query="getInvoice">9<!--- output the date and the amount using the closure call --->10 #DateFormat(CreateDate, "mm/dd/yyyy")# #total.call(mode='sum',valueToTotal=Amount)#<br />11</cfloop>12<!--- Now output the value of the running total --->13<strong>Grand Total: #total.call(mode='Display')#</strong><br />14</cfoutput>

The grand total was calculated using the formula in the closure. It would be trivial to bind additional values to the function if we wished to complicate the formula, perhaps to add a markup value or a discount value.

This code works, you can see that. I still have plenty to learn about closures so please comment if you have thoughts or criticisms.

Update:

Sean recommends another method to create the closure which is much more succinct, using more features of the ClosureLibrary. To use:

Remove the runningTotal function definition. Then replace the <cfset total = cf.new(runningTotal) > with the following snippet: