Description
It has already been proposed in other discussions to add a Path
type which essentially holds a filesystem path and turns current static methods of File
into an object oriented interface.
The benefits of this approach are:
- type safe encapsulation
- one dedicated place for path operations
- clear separation:
File
andDir
handle file system access,Path
performs only syntactic operations.
Prominent implementations of this type are Java's java.nio.file.Path
(API docs, tutorial) and Python's pathlib
(API docs).
Pathlib actually comes in two flavours: pure paths provide only syntactical operations while conrete paths also do IO operations. IMHO it makes more sense to keep that separated like the Java approach.
Paths are implemented differently depending on operating system. Namely, we need to respect POSIX paths (like /foo/bar/baz
) as well as windows paths (like C:\foo\bar\baz
). The major difference are the primary directory separator (/
vs. \
) and designators for absolute paths ( /foo
vs C:\foo
).
Pythons pathlib
offers two classes for this, PurePosixPath
and PureWindowsPath
, Java's Path
by default use the variant supported by the default file system but you can use different providers (Path
is just an interface).
I don't think this needs to be implemented in separate types but it would certainly be nice to not be limited to the system's native path model. This could be achieved by an ivar flag. But it's debateable if this is worth it, the most common use case by far will be working with native paths.
The following methods would migrate from File
to Path
.
File.basename(path) => Path#basename
File.basename(path, suffix) => Path#basename(suffix)
File.dirname(path) => Path#dirname
File.expand_path(path, dir) => Path#epxand_path(dir)
File.extname(filename) => Path#extname
File.join(*paths) => Path#resolve(*paths), Path#<<(path)
Proposed additionals instance methods for Path
:
#<=>(Path | String) : Int
#== (String) : Bool
#[](Int) : Path # access path member by index
#[](Int, Int) : Path # access path members by index
#[](Range) : Path # access path members by index
#absolute? : Bool
#ends_with?(Path | String) : Bool
#normalize : Path # remove `./` and `foo/..` segments
#parent : Path?
#root : Path?
#relative_to(Path | String) : Path
#resolve_sibling(Path | String) : Path
#starts_with(Path | String) : Bool
#to_s : String
#to_uri : URI
The type could probably also include Enumerable(Path)
.
All methods currently accepting a path as String
would now expect Path | String
argument.