File Paths in Crystal

The Path module in Crystal provides functions to parse and construct file paths in a way that is portable between operating systems; dir/file on Linux vs. dir\file on Windows, for example.

require "path"

# Join should be used to construct paths in a portable way.
# It takes any number of arguments and constructs a hierarchical path from them.
p = Path["dir1", "dir2", "filename"].to_s
puts "p: #{p}"

# You should always use Path[] instead of concatenating /s or \s manually.
# In addition to providing portability, Path[] will also normalize paths
# by removing superfluous separators and directory changes.
puts Path["dir1//", "filename"].to_s
puts Path["dir1/../dir1", "filename"].to_s

# dirname and basename can be used to split a path to the
# directory and the file.
puts "Dir(p): #{Path[p].dirname}"
puts "Base(p): #{Path[p].basename}"

# We can check whether a path is absolute.
puts Path["dir/file"].absolute?
puts Path["/dir/file"].absolute?

filename = "config.json"

# Some file names have extensions following a dot.
# We can split the extension out of such names with extname.
ext = Path[filename].extension
puts ext

# To find the file's name with the extension removed,
# use Path[filename].stem.
puts Path[filename].stem

# relative_to finds a relative path between a base and a target.
# It returns nil if the target cannot be made relative to base.
rel = Path["a/b/t/file"].relative_to?("a/b")
puts rel

rel = Path["a/c/t/file"].relative_to?("a/b")
puts rel

To run the program, save it as file_paths.cr and use the crystal command:

$ crystal file_paths.cr
p: dir1/dir2/filename
dir1/filename
dir1/filename
Dir(p): dir1/dir2
Base(p): filename
false
true
.json
config
t/file

The Crystal Path module provides similar functionality to Go’s filepath package. It allows for portable path manipulation across different operating systems. The Path[] method is used to construct paths, similar to filepath.Join in Go. Methods like dirname, basename, absolute?, extension, and stem correspond to similar functions in Go’s filepath package.

The relative_to? method in Crystal is analogous to filepath.Rel in Go, but it returns nil instead of an error when a relative path cannot be constructed.

Note that Crystal’s Path module doesn’t have a direct equivalent to Go’s filepath.Split. However, you can achieve the same result by using dirname and basename separately.