Skip to content
Snippets Groups Projects
Unverified Commit 3634ceee authored by Yorick Peterse's avatar Yorick Peterse
Browse files

Add Pathname.join, .absolute?, and .relative?

Pathname.join can be used to join a Path and a Path/String toether.
Pathname.absolute? and Pathname.relative? can be used to check if a Path
is absolute or relative respectively.
parent 7b7165ef
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -29,6 +29,7 @@ import std::string
import std::array
import std::iterator
import std::array::extensions::(self as _)
import std::range
import std::map::(Map as _Map)
import std::inspect
import std::byte_array
Loading
Loading
Loading
Loading
@@ -43,11 +43,18 @@ import std::fs::raw
import std::io::(Error as IOError, Size)
import std::operators::Equal
import std::os
import std::string_buffer::StringBuffer
import std::time::SystemTime
 
# The primary separator of path components.
let SEPARATOR = os.windows?.if(true: { '\\' }, false: { '/' })
 
# The byte range for lowercase Windows drive letters (a..z)
let WINDOWS_LOWER_DRIVE_LETTERS = 97..122
# The byte range for uppercase Windows drive letters (A..Z)
let WINDOWS_UPPER_DRIVE_LETTERS = 65..90
# A path to a file or directory.
#
# A `Path` can be used to retrieve information about a path to a file or
Loading
Loading
@@ -134,6 +141,88 @@ object Path {
def accessed_at !! IOError -> SystemTime {
try raw.accessed_at(@path)
}
# Returns `True` if this `Path` is an absolute path.
#
# # Examples
#
# Checking if a `Path` is absolute:
#
# import std::fs::path::Path
#
# Path.new('foo').absolute? # => False
# Path.new('/foo').absolute? # => True
def absolute? -> Boolean {
@path.starts_with?(SEPARATOR).if_true {
return True
}
os.windows?.if_false {
return False
}
let first_byte = @path.byte(index: 0)
WINDOWS_LOWER_DRIVE_LETTERS.cover?(first_byte)
.or { WINDOWS_UPPER_DRIVE_LETTERS.cover?(first_byte) }
.and {
# 58 is the byte for ":"
@path.byte(index: 1) == 58
}
.and {
# 92 is the byte for "\"
@path.byte(index: 2) == 92
}
}
# Returns `True` if this `Path` is a relative path.
#
# # Examples
#
# Checking if a `Path` is relative:
#
# import std::fs::path::Path
#
# Path.new('foo').relative? # => True
# Path.new('../').relative? # => True
# Path.new('/foo').relative? # => False
def relative? -> Boolean {
absolute?.not
}
# Joins `self` and the given path together to form a new `Path`.
#
# # Examples
#
# Joining a `Path` with a `String`:
#
# import std::fs::path::Path
#
# Path.new('foo/bar').join('baz').to_string # => 'foo/bar/baz'
#
# Joining a `Path` with another `Path`:
#
# import std::fs::path::Path
#
# Path.new('foo/bar').join(Path.new('bar')).to_string # => 'foo/bar/baz'
def join(path: ToString) -> Path {
let path_str = path.to_string
let join_with = Path.new(path_str)
join_with.absolute?.if_true {
return join_with
}
let buffer = StringBuffer.new(@path)
@path.ends_with?(SEPARATOR).if_false {
buffer.push(SEPARATOR)
}
buffer.push(path_str)
Path.new(buffer.to_string)
}
}
 
impl Equal for Path {
Loading
Loading
import std::env
import std::fs::path::Path
import std::fs::path::(Path, SEPARATOR)
import std::os
import std::test
import std::test::assert
import std::time::SystemTime
import test::features
import test::fixtures::(INVALID_TIME, VALID_DIRECTORY, VALID_FILE)
 
let WINDOWS_DRIVES = Array.new(
'a:\\', 'b:\\', 'c:\\', 'd:\\', 'e:\\', 'f:\\', 'g:\\', 'h:\\', 'i:\\',
'j:\\', 'k:\\', 'l:\\', 'm:\\', 'n:\\', 'o:\\', 'p:\\', 'q:\\', 'r:\\',
's:\\', 't:\\', 'u:\\', 'v:\\', 'w:\\', 'x:\\', 'y:\\', 'z:\\',
'A:\\', 'B:\\', 'C:\\', 'D:\\', 'E:\\', 'F:\\', 'G:\\', 'H:\\', 'I:\\',
'J:\\', 'K:\\', 'L:\\', 'M:\\', 'N:\\', 'O:\\', 'P:\\', 'Q:\\', 'R:\\',
'S:\\', 'T:\\', 'U:\\', 'V:\\', 'W:\\', 'X:\\', 'Y:\\', 'Z:\\',
)
test.group('std::fs::Path.file?') do (g) {
g.test('Checking if a Path points to a file') {
assert.true(VALID_FILE.file?)
Loading
Loading
@@ -82,3 +92,97 @@ features.access_time?.if_true {
}
}
}
test.group('std::fs::path::Path.absolute?') do (g) {
g.test('Checking if a Path is absolute') {
assert.false(Path.new('foo').absolute?)
assert.false(Path.new('..').absolute?)
assert.true(Path.new(SEPARATOR + 'foo').absolute?)
}
os.windows?.if_true {
g.test('Checking if a Path with a Windows drive letter is absolute') {
WINDOWS_DRIVES.each do (drive) {
assert.true(Path.new(drive + 'foo').absolute?)
}
}
}
}
test.group('std::fs::path::Path.relative?') do (g) {
g.test('Checking if a Path is relative') {
assert.true(Path.new('foo').relative?)
assert.true(Path.new('..').relative?)
assert.false(Path.new(SEPARATOR + 'foo').relative?)
}
os.windows?.if_true {
g.test('Checking if a Path with a Windows drive letter is relative') {
WINDOWS_DRIVES.each do (drive) {
assert.false(Path.new(drive + 'foo').relative?)
}
}
}
}
test.group('std::fs::path::Path.join') do (g) {
g.test('Joining a Path with a relative path as a String') {
let path = Path.new('foo')
let expected = os.windows?.if(
true: { Path.new('foo\\bar') },
false: { Path.new('foo/bar') }
)
assert.equal(path.join('bar'), expected)
}
g.test('Joining a Path with an absolute path as a String') {
let path = Path.new('foo')
let absolute = os.windows?.if(
true: { '\\bar' },
false: { '/bar' }
)
assert.equal(path.join(absolute), Path.new(absolute))
}
os.windows?.if_true {
g.test('Joining a Path with an absolute path including a drive letter') {
let path = Path.new('foo')
WINDOWS_DRIVES.each do (drive) {
assert.equal(path.join(drive + 'foo'), Path.new(drive + 'foo'))
}
}
}
g.test('Joining a Path with a relative path as a Path') {
let path = Path.new('foo')
let expected = os.windows?.if(
true: { Path.new('foo\\bar') },
false: { Path.new('foo/bar') }
)
assert.equal(path.join(Path.new('bar')), expected)
}
g.test('Joining a Path with an absolute path as a Path') {
let path = Path.new('foo')
let absolute = os.windows?.if(
true: { Path.new('\\bar') },
false: { Path.new('/bar') }
)
assert.equal(path.join(absolute), absolute)
}
g.test('Joining a Path with a trailing field separator') {
let path = Path.new('foo' + SEPARATOR)
let expected = os.windows?.if(
true: { Path.new('foo\\bar') },
false: { Path.new('foo/bar') }
)
assert.equal(path.join('bar'), expected)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment