Aarrgghh!!

Automating Documentation Part 2

This is a follow up to the post Automating Documentation. Jim Priest wanted to see example code, and I'm happy to oblige.

For this example, I am sharing the code for documenting "steps" in Squidhead. Steps are operations that do one thing, like generate stored procs, or ant scripts, or email developers. They are powered by cfm templates in a specific folder. Once there they can be referenced through in the project's config file. The documentation for them is included in the download for Squidhead, and can be viewed online (Squdihead - Steps).

So after the jump, here is the code for creating this documentation.

So first thing I do is setup a few parameters.

<cfset stepsXMLfile = "#expandPath('.')#/stepsXML.xml" />
<cfset
outputfile="w:\inetpub\wwwroot\squidhead2\docs\steps.cfm" />

<cfdirectory action="list" recurse="false" directory="#expandPath('../../steps')#" name="steps" type="file" />

Then I conditionally build the file in case I deleted it.

<h2>Building XML</h2>
<cfif
not FileExists(stepsXMLfile)>

<p>Transforming Steps to XML.</p>

<cfxml variable="XMLOutput">
<steps>
<cfoutput query="steps">
<#ListFirst(name, '.')#>
<documentation />
<requires />
</#ListFirst(name, '.')#>
</cfoutput
</steps>
</cfxml>

<p>Writing to Disk.</p>

<cffile action="write" file="#stepsXMLfile#" output="#XMLOutput#">

<cfelse>

<p>Already Built.</p>

</cfif>

Then I go through and check to see if each file has a documentation node:

<h2>Checking XML</h2>

<cffile action="read" file="#stepsXMLfile#" variable="rawFile" />
<cfset
stepsXML = XMLParse(rawfile) />
<cfset
changed = FALSE />

<cfoutput>
<cfloop
query="steps">
<cfset stepName = ListFirst(name, '.')/>

<cfif not structKeyExists(stepsXML.steps, stepName)>

<p>Adding #stepName#</p>
<cfset changed = TRUE />
<cfset stepsXML.steps[stepName] = XmlElemNew(stepsXML,stepName) />
<cfset stepsXML.steps[stepName]['documentation'] = XmlElemNew(stepsXML,"documentation") />
<cfset stepsXML.steps[stepName]['requires'] = XmlElemNew(stepsXML,"requires") />

</cfif>

</cfloop>

</cfoutput>

<cfif changed>
    <cffile action="write" file="#stepsXMLfile#" output="#stepsXML#" />
</cfif>

Next I go through and mark any documentation that is not filled in as a problem and through a 500 error. This will cause ANT to stop running.

<cfset incomplete = FALSE />
<cfset
stepArray = StructKeyArray(stepsXML['steps']) />

<h2>Checking Documentation</h2>

<cfoutput>
<cfloop
index="i" from="1" to="#ArrayLen(stepArray)#">

<cfif StructKeyExists(stepsXML['steps'][stepArray[i]], "documentation") AND

len(stepsXML['steps'][stepArray[i]]['documentation']['XMLText']) lt 1>

<p>Documentation for step #stepArray[i]# is not filled in. </p>

<cfset incomplete = TRUE />

</cfif>

</cfloop>
</cfoutput>

<cfif incomplete>

<cfheader statuscode="500" />

</cfif>

I finish by writing the XML back out to disk as HTML. I'm sure this can be done through XSLT, but I don't bother.

<h2>Building HTML Reference.</h2>

<cfsaveContent variable="stepReference">

<h2>Step Reference</h2>

<cfinclude template="stepsDocs.cfm" />
<cfset
stepArray = StructKeyArray(stepsXML['steps']) />
<cfset
ArraySort(stepArray,'textNoCase' )>

<h2>Step Details</h2>

<cfoutput>
<dl>

<cfloop index="i" from="1" to="#ArrayLen(stepArray)#">

<dt>#stepArray[i]#</dt>
<dd>#stepXML['steps'][stepArray[i]]['documentation']['XMLText']#</dd>
<cfif len(stepXML['steps'][stepArray[i]]['documentation']['XMLText']) gt 0>

<dd class="requires">Requires: #stepXML['steps'][stepArray[i]]['requires']['XMLText']#</dd>
</cfif>

</cfloop>

</cfoutput>

</dl>

</cfsavecontent>

<cffile action="write" file="#outputfile#" output="#stepReference#" />

Then to call through ANT, I just add this line to a task in my ANT build file:

<get src="${project.url}/tools/stepDocumenter/" dest="${project.logPath}/tools/stepDocumenter.html" />

I then include these dynamic steps in a static document that includes some background on what steps are and what not.


February 8, 2008 Posted by Terrence Ryan at 12:09 PM

ColdFusion, Squidhead, Web Development,



Comments

Thanks for the followup! I'm going to tinker with this just as soon as I finish up my current project!


Posted by: Jim Priest at February 8, 2008 12:57 PM

very informative, thanks


Posted by: halloween costumes at August 25, 2008 6:22 PM

Posted by Who at September 2, 2010 2:28 PM

Post a comment











Remember personal info?