Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with:

How To Unformat Your Code (Like A Pro)

By Ben Nadel on
Tags: ColdFusion

At this past CFUNITED, big Dan Vega told me about a little project he wanted to show in the Demo Derby. The conversation went a little something like this (in meaning, not word for word):

Ben, I love using your code; but I hate that it takes me 30 minutes to remove all of your freaking formatting. So, I'm trying to create a ColdFusion Builder (CFBuilder) extension for the demo derby that will allow people to remove all of your formatting with a single click!

I heard this and I thought it was just hilarious! Unfortunately, Dan wasn't able to finish the project in time and, I think, ultimately was having some problems with the regular expressions that would be required. Since I love regular expressions, and I think it's just a funny concept, I figured I would jump in and see what I could do. Plus, you have to admit that there's some delicious irony over using someone's code to help destroy it.

Over yesterday and today, I created the "Obsessive" ColdFusion component which has one key method, unformat(), that takes the obsessively formatted code that you want to unformat and returns the newly non-formatted string.

Obsessive.cfc

  • <cfcomponent
  • output="false"
  • hint="I am a component written by Ben Nadel to help people remove Ben's own meticulous formatting from his code - some kids just aren't cool enough ;)">
  •  
  •  
  • <cffunction
  • name="init"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I initialize this component.">
  •  
  • <!--- I am the code that being unformatted. --->
  • <cfset this.setCode( "" ) />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="createMatcher"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I create a pattern matcher based on the given regular expression and store it as the internal matcher.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="pattern"
  • type="string"
  • required="true"
  • hint="I am the regular expression pattern."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var local = {} />
  •  
  • <!--- Compile the regular expression for the tag. --->
  • <cfset local.pattern = createObject(
  • "java",
  • "java.util.regex.Pattern"
  • ).compile(
  • javaCast( "string", arguments.pattern )
  • ) />
  •  
  • <!---
  • Create a pattern matcher for the given pattern and
  • the current code.
  • --->
  • <cfset local.matcher = local.pattern.matcher(
  • this.getCode()
  • ) />
  •  
  • <!--- Store the current matcher. --->
  • <cfset this.setMatcher( local.matcher ) />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="findMatch"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I call find on the current matcher.">
  •  
  • <!--- Check to see if the next match was found. --->
  • <cfif this.getMatcher().find()>
  •  
  • <!--- The next match was found. --->
  • <cfreturn true />
  •  
  • <cfelse>
  •  
  • <!---
  • The next match was not found. At this point, we
  • want to append any existing code into the buffer
  • and then comit the buffer back into the code.
  • --->
  •  
  • <!--- Append the tail. --->
  • <cfset this.getMatcher().appendTail( this.getBuffer() ) />
  •  
  • <!--- Commit the buffer into the code. --->
  • <cfset this.setCode( this.getBuffer().toString() ) />
  •  
  • <!--- Return false. --->
  • <cfreturn false />
  •  
  • </cfif>
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="getBuffer"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return the current string buffer being used in conjunction with the current regular expression pattern matcher.">
  •  
  • <!--- Return the buffer. --->
  • <cfreturn variables.buffer />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="getCode"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="I return the code.">
  •  
  • <!--- Return this current code state. --->
  • <cfreturn variables.code />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="getMatch"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="I get the current match.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="group"
  • type="string"
  • required="false"
  • default="0"
  • hint="I am the group being returned - default to zero, which is the entire match."
  • />
  •  
  • <!---
  • Return the current match from the active
  • pattern matcher.
  • --->
  • <cfreturn this.getMatcher().group(
  • javaCast( "int", arguments.group )
  • ) />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="getMatcher"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I return the current regular expression pattern matcher.">
  •  
  • <!--- Return the current matcher. --->
  • <cfreturn variables.matcher />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="initBuffer"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I create a new string buffer to be used with the current regular expression pattern matcher.">
  •  
  • <!--- Store a new buffer. --->
  • <cfset variables.buffer = createObject(
  • "java",
  • "java.lang.StringBuffer"
  • ).init()
  • />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="removeMatches"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I remove all of the matches.">
  •  
  • <!--- Loop over all the matches. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!---
  • Replace the current match with the empty string.
  • This will remove it from the code.
  • --->
  • <cfset this.replaceMatch( "" ) />
  •  
  • </cfloop>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="removeSpacing"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I remove certain spacing from the code.">
  •  
  • <!--- Define the local scope. --->
  • <cfset var local = {} />
  •  
  • <!--- Create the pattern for the spacing. --->
  • <cfsavecontent variable="local.regex">(?ixm)
  •  
  • (
  • <(cfcomponent)
  • ([^>"]|"([^"]|"")*")*
  • >
  • .*
  • (\r\n?|\n)
  • )
  •  
  • (^(\p{Blank})*$(\r\n?|\n))+
  •  
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Replace the post-tag empty lines. --->
  • <cfset this.replaceMatch(
  • this.getMatch( 1 ) &
  • (chr( 13 ) & chr( 10 ))
  • ) />
  •  
  • </cfloop>
  •  
  • <!--- --------------------------------------------- --->
  •  
  • <!--- Create the pattern for the spacing. --->
  • <cfsavecontent variable="local.regex">(?ixm)
  •  
  • (
  • <(cf(function|argument))
  • ([^>"]|"([^"]|"")*")*
  • >
  • .*
  • (\r\n?|\n)
  • )
  •  
  • (^(\p{Blank})*$(\r\n?|\n))+
  •  
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Replace the post-tag empty lines. --->
  • <cfset this.replaceMatch(
  • this.getMatch( 1 )
  • ) />
  •  
  • </cfloop>
  •  
  • <!--- --------------------------------------------- --->
  •  
  • <!--- Create the pattern for the spacing. --->
  • <cfsavecontent variable="local.regex">(?ixm)
  •  
  • (
  • </(cffunction)>
  • .*
  • (\r\n?|\n)
  • )
  •  
  • (^(\p{Blank})*$(\r\n?|\n))+
  •  
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Replace the post-tag empty lines. --->
  • <cfset this.replaceMatch(
  • this.getMatch( 1 ) &
  • (chr( 13 ) & chr( 10 ))
  • ) />
  •  
  • </cfloop>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="replaceMatch"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I replace the given string in leu of the current match.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="value"
  • type="string"
  • required="true"
  • hint="I am the value being replaced in."
  • />
  •  
  • <!--- Replace the current string. --->
  • <cfset this.getMatcher().appendReplacement(
  • this.getBuffer(),
  • reReplace(
  • arguments.value,
  • "([\\\$])",
  • "\\\1",
  • "all"
  • )
  • )/>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="setCode"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I store the given code as part of the object state.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="code"
  • type="string"
  • required="true"
  • hint="I am the code being stored."
  • />
  •  
  • <!--- Store the code. --->
  • <cfset variables.code = arguments.code />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="setMatcher"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I store the given matcher as the internal matcher.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="matcher"
  • type="any"
  • required="true"
  • hint="I am the matcher being stored."
  • />
  •  
  • <!--- Store the matcher. --->
  • <cfset variables.matcher = arguments.matcher />
  •  
  • <!---
  • Whenever we store a new matcher, we want to re-init
  • the buffer since this matcher will be used with a
  • replacement mechanism.
  • --->
  • <cfset this.initBuffer() />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="unformat"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="I unformat the given code (removing Ben's code meticulous code formatting).">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="code"
  • type="string"
  • required="true"
  • hint="I am the code being unformatted."
  • />
  •  
  • <!--- Set the code, unformat it, and return it. --->
  • <cfreturn this
  • .setCode( arguments.code )
  • .unformatCFTag( "CFArgument" )
  • .unformatCFTag( "CFCookie" )
  • .unformatCFTag( "CFComponent" )
  • .unformatCFTag( "CFContent" )
  • .unformatCFTag( "CFDirectory" )
  • .unformatCFTag( "CFFunction" )
  • .unformatCFTag( "CFHeader" )
  • .unformatCFTag( "CFHttp" )
  • .unformatCFTag( "CFHttpParam" )
  • .unformatCFTag( "CFIF" )
  • .unformatCFTag( "CFImage" )
  • .unformatCFTag( "CFLocation" )
  • .unformatCFTag( "CFLock" )
  • .unformatCFTag( "CFLoop" )
  • .unformatCFTag( "CFMail" )
  • .unformatCFTag( "CFMailParam" )
  • .unformatCFTag( "CFParam" )
  • .unformatCFTag( "CFReturn" )
  • .unformatCFTag( "CFSet" )
  • .unformatCFTag( "CFSetting" )
  • .unformatCFTag( "CFZip" )
  • .unformatCFTag( "CFZipParam" )
  • .unformatComments()
  • .removeSpacing()
  • .getCode()
  • />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="unformatCFTag"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I unformat the ColdFusion tag with the given name.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="tagName"
  • type="string"
  • required="true"
  • hint="I am the name of the tag being unformatted."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var local = {} />
  •  
  • <!--- Create the pattern for the tag. --->
  • <cfsavecontent variable="local.regex">(?ix)
  • <cfoutput>
  •  
  • <#arguments.tagName#
  • ([^>"]|"([^"]|"")*")*
  • >
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Remove the line breaks. --->
  • <cfset local.replace = reReplace(
  • this.getMatch(),
  • "[\s\t]*[\r\n]+[\s\t]*",
  • " ",
  • "all"
  • ) />
  •  
  • <!--- Remove any spaces before periods. --->
  • <cfset local.replace = reReplace(
  • local.replace,
  • " \.",
  • ".",
  • "all"
  • ) />
  •  
  • <!--- Replace match.. --->
  • <cfset this.replaceMatch( local.replace ) />
  •  
  • </cfloop>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="unformatComments"
  • access="public"
  • returntype="any"
  • output="false"
  • hint="I unformat the comments.">
  •  
  • <!--- Define the local scope. --->
  • <cfset var local = {} />
  •  
  • <!--- Get all multiline comments. --->
  • <cfset this.createMatcher(
  • "(?s)<!---(((?!--->).)+)--->"
  • ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Unwrap the comments. --->
  • <cfset this.replaceMatch(
  • "<!---" &
  • reReplace(
  • this.getMatch( 1 ),
  • "[ \t]*(\r\n?|\n)[ \t]*",
  • " ",
  • "all"
  • ) &
  • "--->"
  • ) />
  •  
  • </cfloop>
  •  
  • <!--- --------------------------------------------- --->
  •  
  • <!--- We want to remove any "Define" comments. --->
  • <cfset this.createMatcher(
  • "(?s)(<!---) Define(((?!--->).)+)(--->)"
  • ) />
  •  
  • <!--- Remove matches. --->
  • <cfset this.removeMatches() />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • </cfcomponent>

This ColdFusion component is targeted towards tag-based CFML, so it won't work on HTML at the moment. But, that functionality could easily be added. To see this action, I figured I would turn the Obsessive.cfc lose on itself, like some sort of freaky mobius strip of code (where's M.C. Escher when you need a drawing of a piece of code devouring itself?).

  • <!--- Read in the objsessive component as a test. --->
  • <cfset code = fileRead( expandPath( "./Obsessive.cfc" ) ) />
  •  
  • <!--- Create an instance of the obsessive unformatter. --->
  • <cfset objsessive = createObject( "component", "Obsessive" )
  • .init()
  • />
  •  
  • <!---
  • Remove all of the meticulous formatting, thought, and theory
  • that Ben Nadel has poured into writing his code.
  • --->
  • <cfset unformattedCode = objsessive.unformat( code ) />
  •  
  • <!--- Output the unformatted code. --->
  • <cfoutput>
  •  
  • <pre>#htmlEditFormat( unformattedCode )#</pre>
  •  
  • </cfoutput>

After we run the code, and remove all of the obsessively thorough design, here is the resultant source code:

Obsessive.cfc (Unformatted Like A Pro!)

  • <cfcomponent output="false" hint="I am a component written by Ben Nadel to help people remove Ben's own meticulous formatting from his code - some kids just aren't cool enough ;)">
  •  
  • <cffunction name="init" access="public" returntype="any" output="false" hint="I initialize this component.">
  • <!--- I am the code that being unformatted. --->
  • <cfset this.setCode( "" ) />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="createMatcher" access="public" returntype="any" output="false" hint="I create a pattern matcher based on the given regular expression and store it as the internal matcher.">
  • <cfargument name="pattern" type="string" required="true" hint="I am the regular expression pattern." />
  • <cfset var local = {} />
  •  
  • <!--- Compile the regular expression for the tag. --->
  • <cfset local.pattern = createObject( "java", "java.util.regex.Pattern" ).compile( javaCast( "string", arguments.pattern ) ) />
  •  
  • <!--- Create a pattern matcher for the given pattern and the current code. --->
  • <cfset local.matcher = local.pattern.matcher( this.getCode() ) />
  •  
  • <!--- Store the current matcher. --->
  • <cfset this.setMatcher( local.matcher ) />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="findMatch" access="public" returntype="boolean" output="false" hint="I call find on the current matcher.">
  • <!--- Check to see if the next match was found. --->
  • <cfif this.getMatcher().find()>
  •  
  • <!--- The next match was found. --->
  • <cfreturn true />
  •  
  • <cfelse>
  •  
  • <!--- The next match was not found. At this point, we want to append any existing code into the buffer and then comit the buffer back into the code. --->
  •  
  • <!--- Append the tail. --->
  • <cfset this.getMatcher().appendTail( this.getBuffer() ) />
  •  
  • <!--- Commit the buffer into the code. --->
  • <cfset this.setCode( this.getBuffer().toString() ) />
  •  
  • <!--- Return false. --->
  • <cfreturn false />
  •  
  • </cfif>
  • </cffunction>
  •  
  • <cffunction name="getBuffer" access="public" returntype="any" output="false" hint="I return the current string buffer being used in conjunction with the current regular expression pattern matcher.">
  • <!--- Return the buffer. --->
  • <cfreturn variables.buffer />
  • </cffunction>
  •  
  • <cffunction name="getCode" access="public" returntype="string" output="false" hint="I return the code.">
  • <!--- Return this current code state. --->
  • <cfreturn variables.code />
  • </cffunction>
  •  
  • <cffunction name="getMatch" access="public" returntype="string" output="false" hint="I get the current match.">
  • <cfargument name="group" type="string" required="false" default="0" hint="I am the group being returned - default to zero, which is the entire match." />
  • <!--- Return the current match from the active pattern matcher. --->
  • <cfreturn this.getMatcher().group( javaCast( "int", arguments.group ) ) />
  • </cffunction>
  •  
  • <cffunction name="getMatcher" access="public" returntype="any" output="false" hint="I return the current regular expression pattern matcher.">
  • <!--- Return the current matcher. --->
  • <cfreturn variables.matcher />
  • </cffunction>
  •  
  • <cffunction name="initBuffer" access="public" returntype="any" output="false" hint="I create a new string buffer to be used with the current regular expression pattern matcher.">
  • <!--- Store a new buffer. --->
  • <cfset variables.buffer = createObject( "java", "java.lang.StringBuffer" ).init() />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn />
  • </cffunction>
  •  
  • <cffunction name="removeMatches" access="public" returntype="any" output="false" hint="I remove all of the matches.">
  • <!--- Loop over all the matches. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Replace the current match with the empty string. This will remove it from the code. --->
  • <cfset this.replaceMatch( "" ) />
  •  
  • </cfloop>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="removeSpacing" access="public" returntype="any" output="false" hint="I remove certain spacing from the code.">
  • <cfset var local = {} />
  •  
  • <!--- Create the pattern for the spacing. --->
  • <cfsavecontent variable="local.regex">(?ixm)
  •  
  • (
  • <(cfcomponent)
  • ([^>"]|"([^"]|"")*")*
  • >
  • .*
  • (\r\n?|\n)
  • )
  •  
  • (^(\p{Blank})*$(\r\n?|\n))+
  •  
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Replace the post-tag empty lines. --->
  • <cfset this.replaceMatch( this.getMatch( 1 ) & (chr( 13 ) & chr( 10 )) ) />
  •  
  • </cfloop>
  •  
  • <!--- --------------------------------------------- --->
  •  
  • <!--- Create the pattern for the spacing. --->
  • <cfsavecontent variable="local.regex">(?ixm)
  •  
  • (
  • <(cf(function|argument))
  • ([^>"]|"([^"]|"")*")*
  • >
  • .*
  • (\r\n?|\n)
  • )
  •  
  • (^(\p{Blank})*$(\r\n?|\n))+
  •  
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Replace the post-tag empty lines. --->
  • <cfset this.replaceMatch( this.getMatch( 1 ) ) />
  •  
  • </cfloop>
  •  
  • <!--- --------------------------------------------- --->
  •  
  • <!--- Create the pattern for the spacing. --->
  • <cfsavecontent variable="local.regex">(?ixm)
  •  
  • (
  • </(cffunction)>
  • .*
  • (\r\n?|\n)
  • )
  •  
  • (^(\p{Blank})*$(\r\n?|\n))+
  •  
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Replace the post-tag empty lines. --->
  • <cfset this.replaceMatch( this.getMatch( 1 ) & (chr( 13 ) & chr( 10 )) ) />
  •  
  • </cfloop>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="replaceMatch" access="public" returntype="any" output="false" hint="I replace the given string in leu of the current match.">
  • <cfargument name="value" type="string" required="true" hint="I am the value being replaced in." />
  • <!--- Replace the current string. --->
  • <cfset this.getMatcher().appendReplacement( this.getBuffer(), reReplace( arguments.value, "([\\\$])", "\\\1", "all" ) )/>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="setCode" access="public" returntype="any" output="false" hint="I store the given code as part of the object state.">
  • <cfargument name="code" type="string" required="true" hint="I am the code being stored." />
  • <!--- Store the code. --->
  • <cfset variables.code = arguments.code />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="setMatcher" access="public" returntype="any" output="false" hint="I store the given matcher as the internal matcher.">
  • <cfargument name="matcher" type="any" required="true" hint="I am the matcher being stored." />
  • <!--- Store the matcher. --->
  • <cfset variables.matcher = arguments.matcher />
  •  
  • <!--- Whenever we store a new matcher, we want to re-init the buffer since this matcher will be used with a replacement mechanism. --->
  • <cfset this.initBuffer() />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="unformat" access="public" returntype="string" output="false" hint="I unformat the given code (removing Ben's code meticulous code formatting).">
  • <cfargument name="code" type="string" required="true" hint="I am the code being unformatted." />
  • <!--- Set the code, unformat it, and return it. --->
  • <cfreturn this.setCode( arguments.code ).unformatCFTag( "CFArgument" ).unformatCFTag( "CFCookie" ).unformatCFTag( "CFComponent" ).unformatCFTag( "CFContent" ).unformatCFTag( "CFDirectory" ).unformatCFTag( "CFFunction" ).unformatCFTag( "CFHeader" ).unformatCFTag( "CFHttp" ).unformatCFTag( "CFHttpParam" ).unformatCFTag( "CFIF" ).unformatCFTag( "CFImage" ).unformatCFTag( "CFLocation" ).unformatCFTag( "CFLock" ).unformatCFTag( "CFLoop" ).unformatCFTag( "CFMail" ).unformatCFTag( "CFMailParam" ).unformatCFTag( "CFParam" ).unformatCFTag( "CFReturn" ).unformatCFTag( "CFSet" ).unformatCFTag( "CFSetting" ).unformatCFTag( "CFZip" ).unformatCFTag( "CFZipParam" ).unformatComments().removeSpacing().getCode() />
  • </cffunction>
  •  
  • <cffunction name="unformatCFTag" access="public" returntype="any" output="false" hint="I unformat the ColdFusion tag with the given name.">
  • <cfargument name="tagName" type="string" required="true" hint="I am the name of the tag being unformatted." />
  • <cfset var local = {} />
  •  
  • <!--- Create the pattern for the tag. --->
  • <cfsavecontent variable="local.regex">(?ix)
  • <cfoutput>
  •  
  • <#arguments.tagName#
  • ([^>"]|"([^"]|"")*")*
  • >
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • <!--- Create a new matcher. --->
  • <cfset this.createMatcher( local.regex ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Remove the line breaks. --->
  • <cfset local.replace = reReplace( this.getMatch(), "[\s\t]*[\r\n]+[\s\t]*", " ", "all" ) />
  •  
  • <!--- Remove any spaces before periods. --->
  • <cfset local.replace = reReplace( local.replace, " \.", ".", "all" ) />
  •  
  • <!--- Replace match.. --->
  • <cfset this.replaceMatch( local.replace ) />
  •  
  • </cfloop>
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • <cffunction name="unformatComments" access="public" returntype="any" output="false" hint="I unformat the comments.">
  • <cfset var local = {} />
  •  
  • <!--- Get all multiline comments. --->
  • <cfset this.createMatcher( "(?s)<!---(((?!--->).)+)--->" ) />
  •  
  • <!--- Loop over each of the match. --->
  • <cfloop condition="this.findMatch()">
  •  
  • <!--- Unwrap the comments. --->
  • <cfset this.replaceMatch( "<!---" & reReplace( this.getMatch( 1 ), "[ \t]*(\r\n?|\n)[ \t]*", " ", "all" ) & "--->" ) />
  •  
  • </cfloop>
  •  
  • <!--- --------------------------------------------- --->
  •  
  • <!--- We want to remove any "Define" comments. --->
  • <cfset this.createMatcher( "(?s)(<!---) Define(((?!--->).)+)(--->)" ) />
  •  
  • <!--- Remove matches. --->
  • <cfset this.removeMatches() />
  •  
  • <!--- Return this component reference. --->
  • <cfreturn this />
  • </cffunction>
  •  
  • </cfcomponent>

So there you go! From what I have tested, it seems to work pretty well. I leave it up to big Dan now to take this and turn it into a CFBuilder extension ;)

Tweet This Interesting post by @BenNadel - How To Unformat Your Code (Like A Pro) Thanks my man — you rock the party that rocks the body!


Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Now that's really funny because my favorite thing about your code is the formatting since it makes it that much easier to read!!!

Reply to this Comment

@Jean,

Awesome - I'm glad you like. I'm so used to writing and thinking in that way, that I have a hard time reading code until I've given it the once-over.

Reply to this Comment

The fact that you developed a function to unformat your own code, is just priceless.

You should include this as an option for your code snippets or an option to download the file in a unformatted way. Just created another service for users!

Reply to this Comment

Hmmm maybe now you should see if there is a way to take someone else's code and turn it into your style of coding... hmmm That could be hard not knowing what their style is but that would be a fun challenge. <grin>

Reply to this Comment

@Michael,

Thanks :)

@Nathan,

Hmmm, interesting idea. My first instinct would be to say that it would be hard because I don't know how valid the code is... but it's not like I'm parsing it as XML; I wonder how hard it would be.

Reply to this Comment

Funny stuff. I second Michael's suggestion for a link to download the deobsessified version of your code :)

Reply to this Comment

I thought this was a fun little project until I saw:
# <!---
# Remove all of the meticulous formatting, thought, and theory
# that Ben Nadel has poured into writing his code.
# --->

Now I feel like this is the straw that broke Ben's spirit. :(

;)

Reply to this Comment

Ben great job, I happen to like your coding style and find it very easy to understand and follow.

@Nathan,

I totally agree, I (like the rest of you I assume) am pretty meticulous when it comes to code formatting and making it easy to read and follow the logic. There's nothing I dislike more about my job than when I get someone else's code and I have to spend time re-formatting it so that I can make sense of the logic. An "Obsessive Format" to clean up the unformatted would be fantastic.

Reply to this Comment

The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, but I found that if you implement code folding in CF Builder you then open up a CFC and get a bunch of lines that look like this

<cffunction...

<cffunction...

<cffunction...

Ack!

A feasible alternative to code folding, fortunately, is the Outline View, so technically not all would be lost. The vertical scrolling of all the code did start to get a bit painful though, but that's mainly cause I had a bunch of cfargument and cfqueryparam tags for some functions. So I guess what I'm trying to say here is, I'll never be quite like Ben! But that's okay, right? :)

Regardless of my trip-up with this approach, I think your code formatting is PERFECT for your blog post. I'm not a huge fan of "scroll" overflows within code blocks, and it gets annoying when you have long statements going from left to right anyway. Keep it up, bro.

One question. Is your code coloring dynamic or do you manually fill in all the span tags? I'm guessing it is the former as you have downloadable code snippets and duplicating all those code samples would be a bear.

Reply to this Comment

LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else's comments :)

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.