white_gecko
white_gecko

Reputation: 5086

Check if path is a directory path (it might not exist)

In ruby I can check with Pathname("/some/path/").directory? if a path actually is a directory. This will only work if the directory actually exists.

How can I check if Pathname("/some/path/") is a path for a directory even if it does not exist? It must be platform independent, so I cant just check for a trailing slash.

Upvotes: 0

Views: 916

Answers (1)

Todd A. Jacobs
Todd A. Jacobs

Reputation: 84373

TL;DR

If the Pathname isn't on the filesystem already, it's just a name. Its type (e.g. file or directory) isn't fixed until you create a filesystem object with it. So, I recommend either unambiguously constructing each directory Pathname with a trailing separator, or using the Pathname to create the file or directory with the relevant methods for its intended type.

Testing Pathname Objects with Trailing Directory Separator

If you're using the Pathname module, the Pathname doesn't have to exist to be used. In such cases, it's useful to note that the Ruby engine converts forward slashes into backslashes when on Windows, so the following constructed pathnames should work on Windows, Linux, MacOS, and Unix:


Pathname('/some/path/').to_s.end_with? ?/
#=> true

Pathname('C:/some/path/').to_s.end_with? ?/
#=> true

However, if your Pathname is constructed manually or programmatically without being read in from the filesystem or using File#join, you may need to use a character class to check for both *nix and Windows trailing separators. For example:

require 'pathname'

%w[ /some/path/ C:\\some\\path\\ ].map do |path|
  Pathname(path).to_s.match? %r![/\\]\z!
end
#=> [true, true]

Using Method to Set Filesystem Object Type

If you construct a path without a trailing directory separator but the directory doesn't actually exist in the filesystem, then you can't determine just from the name whether it's supposed to be a file or directory. A Pathname is really just a special type of String object. The documentation explicitly states (emphasis mine):

Pathname represents the name of a file or directory on the filesystem, but not the file itself.

That being the case, your best bet is to modify your Pathname constructor to ensure that you're building names with trailing separators in the first place. If you can't or won't do that, you will have to leave it up to your filesystem writing code to explicitly call an appropriate method explicitly on the expected filesystem object. For example:

require 'pathname'
require 'fileutils'

path = Pathname '/tmp/foo'

# ensure file or directory doesn't already exist
path.rmtree

# use path as file
FileUtils.touch path
path.file?
#=> true

# remove path before next test
path.unlink

# use path as directory
path.mkpath
path.directory?
#=> true

As you can see, a Pathname without a trailing (back)slash can be used for both files and directories, depending on how you use it.

Upvotes: 2

Related Questions