The simplicity of Lucee

16 April 2015

Four years ago I listed various new features in ColdFusion 9 which helped simplify my code, as compared to the previous version 8.

Having recently migrated from CF9 to Lucee, I thought I'd repeat the exercise. So here are some of the features of Lucee which I'm finding help make my code simpler to write and understand.

(Note: I know many of the following are available in more recent versions of Adobe ColdFusion. Simplicity is relative, and the comparison here is between Lucee 4.5 and ACF 9.0.1).

Query loops in script

ColdFusion 9


for( i=1; i LTE myQuery.recordcount; i++ ){
  WriteOutput( myQuery.ID[ i ] & "<br/>" );
}

Lucee


for( row in myQuery ){
  Echo( row.ID & "<br/>" );
}

Built-in Functions

DateTimeFormat()

ColdFusion 9


date = Now();
WriteOutput( DateFormat( date,"dddd, d mmmm yyy" ) & ", " & TimeFormat( date,"HH:mm:ss" ) );

Lucee


date = Now();
Echo( DateTimeFormat( date,"EEEE, d mmmm yyy, HH:nn:ss" ) );

Note that the full day of the week name (e.g. Wednesday) mask is EEEE in Lucee and not dddd, which seems to return the day of the month with leading zeros.

Update 25 April 2015: The minute mask is different from TimeFormat() and should be nn not mm as originally posted.

Echo()

See examples above. To be honest, I was briefly resistent to the PHP-esqueness. WriteOuput() is more descriptive, but this a function I use a lot when testing and for frequently used code, brevity may trump clarity when it comes to simplification.

Dump()

ColdFusion 9

WriteDump( server );

Lucee

Dump( server );

IsEmpty()

ColdFusion 9


myString = "";
WriteDump( !Len( myString ) ); //-> TRUE

Lucee


myString = "";
Dump( IsEmpty( myString ) ); //-> TRUE

NullValue()

ColdFusion 9

myNull = JavaCast( "Null","" );

Lucee

myNull = NullValue();

GetCanonicalPath()

This function comes in handy when building file paths dynamically from several parts which may or may not be relative or have leading/trailing slashes. For example, we might need to build the path C:\a\2\tests\test.txt as:


path = "C:\a\1\";
path &= "../2/";
path &= "/tests/";
path &= "test.txt";
WriteDump( path );

This outputs the rather messy C:\a\1\../2//tests/test.txt .

In Lucee we can clean this up:

Dump( GetCanonicalPath( path ) );

Which outputs: C:\a\2\tests\test.txt.

My only reservation about this function is that it reverses forward-slashes on Windows. Other OSes use forward slashes and since they work fine on Windows too that should be the default, not back-slashes, to keep things platform-agnostic.

DirectoryCopy()

No more intermediate zipping!

ColdFusion 9


<cfscript>
sourcePath = ExpandPath( "./test" );
destinationPath = ExpandPath( "./testCopy" );
tempZipPath = "ram:///#CreateUUID()#.zip";
if( !DirectoryExists( destinationPath ) )
	DirectoryCreate( destinationPath );
</cfscript>
<cfzip
	action="zip"
	source="#sourcePath#"
	file="#tempZipPath#"
	recurse="true"
	storepath="true"/>
<cfzip
	action="unzip"
	file="#tempZipPath#"
	destination="#destinationPath#"
	storePath="yes"
	overwrite="yes"/>
<cffile action="delete" file="#tempZipPath#">

Lucee


sourcePath = ExpandPath( "./test" );
destinationPath = ExpandPath( "./testCopy" );
DirectoryCopy( sourcePath,destinationPath,true,"",true );

Note the final optional argument of DirectoryCopy() causes the destination path to be created if it doesn't exist.

Miscellaneous

Null coalescing (Elvis) operator

As I was refactoring the old Railo Spreadsheet extension into my Lucee Spreadsheet Library, the perfect job for the Elvis operator came up.

A struct of spreadsheet "info" needed to be transferred from POI to CFML but without any java nulls where a value didn't exist. The old code tackled each value as follows:


value = coreProps.getCreator();
info.author = IsNull( value )? "":value;

With the help of Elvis this could be shrunk to:


info.author = coreProps.getCreator()?:"";

Member functions

The IsEmpty() example above is not written the way I'd actually use it. Instead I'd call the function as if the empty string variable were an object and IsEmpty() one of its methods:


myString = "";
Dump( myString.IsEmpty() );// ->TRUE

Not all functions support this type of "Member functionality", so it's important to check the documentation and test.

The one I find I'm using and appreciating most so far replaces StructKeyExists(), which I've always disliked having to type:

ColdFusion 9

WriteDump( StructKeyExists( myStruct,"myKey" ) );

Lucee

Dump( myStruct.KeyExists( "myKey" ) );

Tags in script

Although I still believe tags have their place in certain limited cases, I've preferred using cfscript where its capability has allowed ever since it was introduced in ColdFusion 4.0.

Questions have been raised about the way "tags in script" have been implemented, but just being able finally to use the following in particular without dropping out of script and into tags, or down to unsupported Java methods, is a delight.

  • <cfcontent>
  • <cfcookie>
  • <cfexecute>
  • <cfheader>
  • <cfpdf>
  • <cfsetting>

Server wide pageEncoding

Finally, ever since I became aware of encodings/charsets and their impact many years ago, I've been putting the following at the top of each and every ".cfm" and ".cfc" file I create to ensure any "special" characters I might type—such as £—are displayed correctly.

<cfprocessingdirective pageencoding="utf-8"/>

With Lucee this is no longer necessary as the "template charset" can be specified globally in the admin, either at the server or individual "web context" level.

Posted by Julian on . Updated

Comments

  • Formatting comments: See this list of formatting tags you can use in your comments.
  • Want to paste code? Enclose within <pre><code> tags for syntax higlighting and better formatting and if possible use script. If your code includes "self-closing" tags, such as <cfargument>, you must add an explicit closing tag, otherwise it is likely to be mangled by the Disqus parser.
Back to the top