Skip to content

Add Path type #5550

Closed
Closed
@straight-shoota

Description

@straight-shoota

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 and Dir 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions