Rip's Domain

UDFs: How do you orgainze them?

Posted in ColdFusion by rip747 on June 13, 2007

Who doesn’t like user defined functions (UDFs)? If you have done any programming, chances are that you have used them extensively. The biggest problem that people have with them is how to include and organize them in your application.

What I’ve found that most people do is create a Utils.cfc or UDFs.cfc and cut and paste their UDFs that they want to use into the component as demostrated below:

<!— UDFs.cfc —>
<cfcomponent output=”false”>

<cffunction name=”init” access=”public” returntype=”Any” output=”false”>
<cfreturn this>
</cffunction>

<cffunction name=”myUDF1″ access=”public” returntype=”Any” output=”false”>
</cffunction>

<cffunction name=”myUDF2″ access=”public” returntype=”Any” output=”false”>
</cffunction>

</cfcomponent>

Once you have all the UDFs that your application will be using pasted into your component, you will need to make the UDFs available to your application. Almost everyone I’ve seen does this loading by the component into the application scope. The following line is placed into the onApplicationStart() if your using Application.cfc or by just adding it into the Application.cfm if you’re using that:

<cfset application.functions = CreateObject(“component”, “udfs”).init()>

Whichever one your using, Application.cfc or Application.cfm, the results are the same; all your UDFs are available to your application and you can use them freely throughout. The only difference is what variable name you use. I use application.functions, some use application.utils or application.udfs; doesn’t matter, again, the results are the same.

There is one problem that I have with this approach though, it’s cumbersome and the UDFs component will get huge. The problem with having such a huge component file is editing it becomes a nightmare since scrolling through thousand of lines of code is very fun and also I’ve noticed that CFEclipse bogs down on huge files. Sure code collapse does provide some relief but there has to be a better way.

What I wanted was to just have one file for each UDFs I was using and a way for my application to load them automatically. Reason behind this was so that if I needed to edit myUDF1, I could just open the file myUDF1.cfm and edit what I needed. I also wanted to be able to grab UDFs from CFLib.org and just drop them into my application without having to edit anything. If I ever needed to remove a UDF from my application, it would be as easy as deleting the UDF file and reinitializing my application.

To accomplish what I wanted, I modified my UDFs.cfc to 11 lines of code:

<!— UDFs.cfc —>
<cfcomponent output=”false”>

<cfset variables.udfdir = GetDirectoryFromPath(GetCurrentTemplatePath()) & “udfs”>
<cfset variables.q = “”>

<cffunction name=”init” access=”public” returntype=”Any” output=”false”>
<cfreturn this>
</cffunction>

<cfdirectory action=”list” directory=”#variables.udfdir#” filter=”*.cfm” name=”variables.q”>

<cfoutput query=”variables.q”>
<cfinclude template=”udfs#name#”>
</cfoutput>

</cfcomponent>

So what exactly is going on?

In a nutshell, here’s what’s happening. I have a directory called udfs in the same directory that I have my UDFs.cfc. This is the directory that I put all of my UDF CFM files. What the UDFs.cfc does is scan this directory when it is called and automatically includes each CFM file it finds. Thus it automatically loads any UDFs in the UDFs folder into itself.

So my goal is reached! I have each UDF in it’s own file so I don’t have to scroll through a huge component file to find it. I can now open and edit it easily. By just looking at the directory, I know what UDFs my application is using. I can automatically add a UDF from CFLib.org by just saving the text from browser into a file in the directory. Plus if I no longer need to use the UDF in my application, I simply delete the file from the directory and it’s removed from my application during the next reinit. All this is done without having to touch the main UDFs.cfc file.

Below is an example of what one of the UDF CFM files looks like. The file is called fullLeft.cfm and resides in the UDFs directory.

<!— fullLeft —>
<cffunction name=”fullLeft” access=”public” displayname=”fullLeft” returntype=”string” output=”false”>
<cfargument name=”str” type=”string” required=”true”>
<cfargument name=”count” type=”numeric” required=”true”>
<cfif not refind(“[[:space:]]”, arguments.str) or (arguments.count gte len(arguments.str))>
<cfreturn Left(arguments.str, arguments.count)>
<cfelseif reFind(“[[:space:]]”,mid(arguments.str,arguments.count+1,1))>
<cfreturn left(arguments.str,arguments.count)>
<cfelse>
<cfif count-refind(“[[:space:]]”, reverse(mid(arguments.str,1,arguments.count)))>
<cfreturn Left(arguments.str, (arguments.count-refind(“[[:space:]]”, reverse(mid(str,1,arguments.count)))))>
<cfelse>
<cfreturn left(arguments.str,1)>
</cfif>
</cfif>
</cffunction>

7 Responses

Subscribe to comments with RSS.

  1. Adam Tuttle said, on June 13, 2007 at 12:40 pm

    Very clever! I’ll have to start doing that myself!

  2. Boyan said, on June 14, 2007 at 12:07 pm

    Good tip! I’ll be using it. Thanks

  3. Ben Rogers said, on June 14, 2007 at 1:10 pm

    We store UDFs in libraries. A library is just a cfm file in a folder called, creatively enough, libraries. Then, when we need a UDF, we import it.

    To import, we call a custom tag. We tell the custom tag which functions we want from which libraries. We also tell the library where to drop the functions. We can put them in the variables scope, in a custom struct, etc. UDFs can even be loaded into the function local scope. This avoids pollution of the CFC instance and public scopes.

    There are a couple issues with this approach. First, there are dependency issues. A UDF may call another UDF. This also gets hairy if the UDFs are not loaded into the variables scope. There are ways to resolve these issues, but we generally don’t bother since they are few and far between.

    -ben

  4. rip747 said, on June 14, 2007 at 4:16 pm

    @Ben,

    Personally I view UDFs as functions that are self contained and aren’t depended on other UDFs. Really for those kinds of UDFs I would make them part of my model. Again this is my opinion.

  5. rip747 said, on June 14, 2007 at 4:18 pm

    @Adam, Boyan
    🙂

  6. Michael Sharman said, on June 14, 2007 at 7:25 pm

    Nice one Tony, very clean approach. Would also be good for source control per UDF.

    I love this stuff🙂

  7. Marco Antonio said, on July 27, 2007 at 7:55 am

    In our applications we just need to extend utils.cfc in cfc’s. This could be a good approach thinking about persistent variables in cfc’s is not a best practice.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: