Using the Foundry CF Path Module

So as I announced in my last entry, I’ve been working on something called Foundry for CF. Foundry’s aim is to provide a platform for modular CF applications and utilities.

It is not a framework used for building a full blown web application. It doesn’t have ORM, databases, controllers, views, etc. It serves a different purpose.

But I’m not going to talk about Foundry today, I’m going to talk about 1 piece of Foundry, the Path module.

Now, Most of us have used ColdFusion’s nice and convenient cfdirectory, cffile, and path functions. These are great, and perfect for what they do and what most people need them for. But they aren’t infinitely useful for building paths, and manipulating hyphothetical path structures that may or may not exist. They are meant to work with the file system directly (generally).

If you’re familiar with NodeJS, you will be right at home here and this will be redundant information to you… but my goal for the basics of Foundry was to port the majority of Node’s core modules over to CF Components. The main reason I started this was to learn more about Node, JavaScript, AND ColdFusion’s newer scripting abilities with closures and function expressions. But also because it’s damn neat to be able to almost line for line port over useful code from the ever so hopping Node community.

Almost lost sight of the topic again… sorry…

The Path.cfc component of Foundry Core is a direct port of the Node module to CF.
This module is incredibly useful and is used in like 90% of all Node modules so therefor it was a natural fit in Foundry.

Path.cfc is fairly self explanitory for the most part, it deals with… well paths.
But not PHYSICAL paths that exist on the drive, but paths that could or may exist.

Let’s start with a few examples…

Path.resolve()

Let’s say you would like to step up 3 directories of a given path string.
Ideally, in a terminal, you would take your current directory and type “cd ../../../” and instantly be taken to that directory.

In ColdFusion, you could do this with something like so:

#GetDirectoryFromPath(GetDirectoryFromPath(GetDirectoryFromPath(GetCurrentTemplatePat())#

This definitely would work… but… not very elegant or clean.

With Foundry Path module, you would just type:

//given the path /Users/rountrjf/Projects/my_cool_app/
<cfset myPath = Path.resolve("/Users/rountrjf/Projects/my_cool_app/test/what/hotness,'../../../') />
<cfoutput>#myPath#</cfoutput> <!--- output: /Users/rountrjf/Projects/my_cool_app/ --->

Now, you might say… well I could have done that by just typing expandPath('/').
That’s true, but that only works for your current CF context and will only return the root of that context.

Path.cfc works with ANY PATH string, it’s aim is not to make or manipulate paths relative to any physical path, as stated before, it manipulates path strings.

Foundry is meant to do more than attach to your existing web applications, it’s meant to be a workhorse for building useful things that don’t always end up in a tag. It’s meant for doing heavy lifting and help you approach the problems of the next generation of CF.

<cfset myPath = Path.resolve('/Users/rountrjf/Projects/my_cool_app/test/what/hotness','../images/','../../','../controllers') />

This one is much harder to mentally wrap your head around outside of context of a terminal window but if you walk through it from left to right, you can resolve it…

So we start in the hotness directory, and we type cd ../images/
That places us in the images directory within the what directory. So /test/what/images.

From there, we cd ../../ which would take us out of images, and up 2 directories which would put us /test/ again.

Then we do a cd ../controllers which would take us out of test and up a directory, then into the controllers directory.

Our final resolved path should be /Users/rountrjf/Projects/my_cool_app/controllers.

That’s just the resolve function, and whether or not you find it applicable in your development will determine if you’re still thinking in the typical CF mindset of building streamlined web apps with a front end public purpose, versus a workhorse to help you develop useful extensions to CF.

Path.relative()

This is quite the opposite of Path.resolve().
Path.resolve() always returns an absolute path where relative’s goal is to give you a relative path.

Let’s say you need to determine what steps it would take to get to a path from another path… given the example above, let’s try this out…

<!--- grab the path module --->
<cfset path = new foundry.core.path() />

<!--- use it --->
<cfset myRelativePath = Path.relative('/Users/rountrjf/Projects/my_cool_app/test/what/hotness','/Users/rountrjf/Projects/my_cool_app/controllers') />

This statement will return the relative path to the controllers directory based on the first path provided in argument[1].

So let’s say we’re in /test/what/hotness and we want to know the steps it takes to get to controllers. The response would be ../../../controllers since controllers is in the my_cool_app/ directory

Easy, but not something you use everyday in regular CF apps probably until you start thinking about building other things with CF.

There are 7 functions in the Path.cfc and these are 2 of big ones.

Path.join()

Join is a very useful function.

It’s about the equivalent of the following:

<cfset myPaths = [
   '/Users\rountrjf\',
   '/Projects',
   '\my_cool_app',
   '/test',
   '..'
] />

<cfset joinedPaths = arrayToList(myPaths,'/') />

Except for the fact that it actually cleans it all up and makes it valid based on your file system (windows or posix).

The result of the above example would be roughly /Users\rountrjf\//Projects/\my_cool_app/..//test

But if you use Path.join():

<cfset joinedPaths = Path.join('/Users\rountrjf\','/Projects','\my_cool_app','/test','..') />

//or on windows
<cfset joinedPaths = Path.join('c:','Users/rountrjf\','/Projects','\my_cool_app','/test','..') />

This would return /Users/rountrjf/Projects/my_cool_app on posix, or on Windows provided you added a C: or something in front, you would get C:\Users\rountrjf\Projects\my_cool_app

It’s sort of like path.resolve, except it doesn’t need a from path, it simply joins all your paths by a separator and normalizes the output based on the current operating system it’s running on. (ie. / for posix and \ for windows).

Also, it ignores non-string arguments.
If you just had a jumbled struct of mixed paths + arrays mixed in, it would ignore the arrays and join the paths.

The rest…

The rest of them are much simpler in nature…
I’ll have you checkout the rest via Foundry documentation for more information.
Or, the node documentation too! It all applies.

Path module documentation for Foundry:
https://github.com/foundrycf/foundry/blob/master/doc/path.markdown

Leave a Reply

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax