paint-brush
Mistakes I've made treating file paths as stringsby@philnash
209 reads

Mistakes I've made treating file paths as strings

by Phil NashMarch 10th, 2020
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Developer evangelist for Twilio and Authy. I love writing JavaScript and Ruby. I was trying to create a glob of paths with the line:. console.log('🍻)' When working with Node.js the `path` module is your friend. Use `path.join` whenever you have to join two paths. Concatenating two pathnames or a pathname and a string will add the separator (as someone pointed out in a comment on my commit) but concatenating two strings will not.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Mistakes I've made treating file paths as strings
Phil Nash HackerNoon profile picture

Some things you do as a developer can work for you for years, then turn around and bite you when you were least expecting. These are the things that you wish another developer had told you early in your career so you never had to make the mistakes. This post is about one of those things and if you’re reading this, consider it me telling you.

File paths look like strings. You have a number of directories and maybe a file name with an extension at the end. You separate the directories and files with a `

/
` character and the result looks like `
/path/to/file
`. So you can treat them like strings, joining them or concatenating them until you pass them to another file method that is used to read from or write to the file. These were my thoughts from just a few months ago. Here’s where I was wrong.

Don’t forget Windows

If you develop on a Mac, like I have the privilege of doing, or Linux then you might have read the above paragraph and not noticed anything wrong. If develop on Windows you probably sighed into your cup of coffee as you read the `

/
` character.

It’s all too easy to forget when you work with a Mac and deploy to Linux environments, like I have done for years, that Windows uses backslashes. It’s all too painful to find out you’ve made that mistake when you work on a command line tool that needs to run on both types of platform. create-twilio-function is one such command line tool that had to go through a number of changes from things like:

mkdir(path + '/' + dirName);

to

const path = require('path');
mkdir(path.join(pathName, dirName));

so that it would work properly on Windows.

To Windows users, I’m sorry. To everyone else, when working with Node.js the `path` module is your friend. Use `path.join` whenever you have to join two paths. And check out other utilities like `path.relative`, which returns a relative path from one path to another, and `path.normalize`, which returns a path resolving segments like `.` or `..`.

Pay no attention to `path.sep`, which returns a `

/
` or a `
\
` depending on the system you’re working on, just use `path.join`.

Paths behave differently to strings

To my second mistake, this time working in Ruby. This one was slightly more subtle and evaded my tests. You see, you can use the `

Pathname
` class to create fragments of paths and then concatenate them. For example:

require "pathname"
path1 = Pathname.new("path")
path2 = Pathname.new("to")
path1 + path2
# => #<Pathname:path/to>

As you can see `

Pathname
` objects have a `
+
` operator that concatenates the paths, much like `
+
` concatenates strings. In fact, it also works with a mix of strings and paths:

require "pathname"
path1 = Pathname.new("path")
path2 = "to"
path1 + path2
# => #<Pathname:path/to>

This all seems well and good, except it doesn’t work the other way around.

require "pathname"
path1 = "to"
path2 = Pathname.new("path")
path1 + path2
# => TypeError (no implicit conversion of Pathname into String)

A nice error like that means we’ve done something wrong, that was not the problem I had though. No, the issue I had stemmed from expecting to concatenate a pathname and a string and instead concatenating two strings. This manifested itself in my Rubygem `jekyll-gzip`. You see, I was trying to create a glob of paths with the line:

files = Dir.glob(dir + "**/*{#{extensions}}")

It turned out under some circumstances `

dir
` was actually a string instead of a pathname and it didn’t include a separator. So the glob was looking for `
"dirname **/*{#{extensions}}"
` when I really wanted it to look for `
"dirname/** /*{#{extensions}}"
`. Concatenating two pathnames or a pathname and a string will add the separator (as someone pointed out in a comment on my commit), but concatenating two strings will not. This meant that the gem happily went looking for the wrong pathname, found no files and then proceeded to successfully do nothing. Replacing the entire line with:

files = Dir.glob(File.join(dir, "**", "*{#{extensions}}"))

fixed the issue. In this case `File.join` is the method to use to avoid surprises with strings.

Always use the built in path tools

Whether you’re working in Node.js, Ruby, or any other language do not be tempted to treat file paths as strings. They behave differently on different platforms and mixing paths and strings together can cause hard to debug errors.

Use your standard library and save yourself the hassle.

Previously published at https://philna.sh/blog/2020/03/04/mistakes-treating-paths-as-strings/