Hints... they are an important part of life.
Consider dropping a hint for a long-sought after birthday gift. Hinting to someone that you like them, or hints for the latest console game to help you achieve maximum death rampage on "Killer Chocolate Bunnies from Mars".
Bottom line, hints are helpful.
Enter 'THE PROBLEM'
Never more so has the need for hints been as important as in the world and lives of developers. We write awesome frameworks, intense code and sweet apps.
I was in a situation the other day working on a legacy app for someone to resolve some issues and add new functionality. The ColdFusion developer/s who had originally built the particular features for the application had written as much as they could in components to increase modularity and promote reusable code. Kudos.
The one thing that was constantly drummed in to me from day one as a ColdFusion developer was to always think about reusability. Why develop two or three functions with marginally different functionality if you can take a step back and restructure one method to work for all eventualities? It cleans up your code base, simplifies development and debugging, and makes for happy monkehs.
I digress.. ploughing through lines of someone else's code to debug or amend code can be taxing at the best of times (depending of current levels of caffeine intake). This particular task was made much harder to manage as absolutely no methods in the component(s) had been hinted. In a lot of cases, only the name of the method had been provided; no other attributes
IMAGINE THE WHITESPACE!!
There was the occasional comment here and there for good measure and to log minor edits, but nothing of any consequence that would aid understanding of the code and requirements.
Bring in the hunter
This got me thinking of a solution, or at least an idea to help avoid the solution in the future. With the awesome ability to create extensions for ColdFusion Builder, I quickly knocked up (by which I mean developed, not impregnated) an extension that would read the meta data of a selected component, and search within it for any instances of a method with a blank, incomplete or missing HINT attribute.
The ColdFusion Hint Checker extension was born.
Here's how it works
[kml_flashembed publishmethod="static" fversion="8.0.0" movie="/assets/uploads/2010/06/HintCheckerExtensionDemo.swf" targetclass="flashmovie"]
If you had Flash player, you'd be watching an awesome demo video right about now.
Why use it?
Now, this didn't help me in my particular predicament; after all, none of the original developers were available to quiz and maim over the missing information. I could have added in my best guesses for the functionality, but that wouldn't have helped future devs looking at the code. So who could benefit from the application?
Perhaps you are developing and releasing open-source applications or CFC wrappers to the community. You ideally want to ensure that hints are provided so people can quickly understand what each method does.
Maybe you are a development manager or in charge of a team of developers. Perhaps you want to run a quick check on the ColdFusion components developed by your team to check for correct documentation. After all, if your team are going to be sharing code and reusing code written by others, make sure they hint it, and use this to track down any slackers. :)
Perhaps you are just anal about code and like to ensure everything is correctly hinted. You're not alone.
Here's what it does
ColdFusion provides developers with an easy 'straight-out-of-the-box' way to obtain information about a component, through the use of the getComponentMetaData() and getMetaData() functions.
Here's an output screenshot of the getComponentMetaData() function reading in my test.cfc file.
You instantly have a visual representation of the component, it's attributes, extensions, path and (most importantly in this scenario) an array of all functions, each function declared as a struct of information.
It is this array, and the structs within that we are able to easily read and double-check the existence of the HINT attribute (by searching for the existence of a key named 'hint' within the structs).
In the following example, we're reading the meta data from a CFC file, looping over the array and performing our checks on the HINT attributes. Nice and easy.
<!--- Get the metaData information from the CFC file ---> <cfset arrayMeta = getComponentMetaData('test') /> <!--- Set up the array to contain results from the check ---> <cfset arrResults =  /> <!--- Perform the loop if the CFC contains methods. Here, we are checking for the existence and the length of the array containing the functions. ---> <cfif IsDefined("arrayMeta.functions") AND ArrayLen(arrayMeta.functions)> <!--- Loop over the array ---> <cfloop from="1" to="#ArrayLen(arrayMeta.functions)#" index="intCount"> <!--- Check each struct within the array item for an empty or missing HINT attribute ---> <cfif NOT structKeyExists(arrayMeta.functions[intCount], "hint") OR arrayMeta.functions[intCount].hint EQ ''> <cfset strMessage = '<strong> ' & arrayMeta.functions[intCount].name & '</strong> method has either an empty or missing HINT attribute! Sort it out!' /> <!--- Append the message ot the results array ---> <cfset arrayPrepend(arrResults, strMessage) /> </cfif> </cfloop> </cfif> <!--- Dump the result array to see what we have uncovered ---> <cfdump var="#arrResults#" label="Results from the hint checker." />
The resulting output from the code will produce an array like this:
This is an over-simplified version of the code contained within the extension, but you can see how easy it is to read information from the component and perform the hint check task.
The extension itself provides a little more information to the user and has a slightly prettier interface. Slightly.
What's your line?
It would be fine and dandy to just output the problem messages to the user, but it's not overly helpful. If there was a problem, you would want to know on which line the problem exists so you can quickly navigate to the correct location in your IDE and fix it.
In an effort to help the user experience and provide slightly more useful information, the plugin also returns the line number of the argument of method with the 'offensive' hint attribute.
This has been made incredibly easy thanks to the ability to loop over a file line by line, introduced in ColdFusion 8.
In this basic example, the cfloop accepts the full path to the file in the file attribute, and will output each line:
<cfloop file="c:\full\path\to\file.txt" index="currentLine"> #currentLine#<br /> </cfloop>
As we want to obtain the current line of a specific method or argument name, we need to run a findNoCase() function on every line to see if we get a match. Once found, the method will return the populated string variable containing the line number of the requested method or argument.
In the getLineNumber method used in the extension, two arguments are required; the full path to the component (for the cfloop) and the name of the method or argument to search for.
<cffunction name="getLineNumber" access="private" output="false" returntype="String" hint="I find the current line number of the function/method in question."> <cfargument name="componentPath" required="true" type="String" hint="I am the path to the component that you want to check." /> <cfargument name="functionName" required="true" type="String" hint="I am the name of the function that you wish to retrieve the line number of." /> <cfset var strLineNum = '' /> <cfset var strFunctionName = arguments.functionName /> <cfset var i = 1 /> <!--- loop over the file, sent through as a full path via the arguments scope ---> <cfloop file="#arguments.componentPath#" index="line"> <!--- loop line-by-line until the method/argument name has been matched ---> <cfif findNoCase(strFunctionName, line, 1)> <cfset strLineNum = i /> </cfif> <cfset i++ /> </cfloop> <cfreturn strLineNum /> </cffunction>
Where can I get it?
The ColdFusion Builder extensions is available to download from RIAforge.org, here: http://hintchecker.riaforge.org/