Max Howell 9aa91c649e Merge pull request #26 from mxcl/codecov
Increase code coverage
2019-01-31 12:25:41 -05:00
2019-01-31 09:58:46 -05:00
2019-01-31 12:15:31 -05:00
2019-01-31 12:15:31 -05:00
2019-01-25 20:46:37 -05:00
2019-01-31 08:37:14 -05:00
2019-01-17 17:12:54 -05:00
2019-01-17 17:12:54 -05:00
2019-01-28 12:04:47 -05:00

Path.swift badge-platforms badge-languages Build Status

A file-system pathing library focused on developer experience and robust end results.

import Path

// convenient static members
let home = Path.home

// pleasant joining syntax
let docs = Path.home/"Documents"

// paths are *always* absolute thus avoiding common bugs
let path = Path(userInput) ?? Path.cwd/userInput

// elegant, chainable syntax
try Path.home.join("foo").mkdir().join("bar").touch().chmod(0o555)

// sensible considerations
try Path.home.join("bar").mkdir()
try Path.home.join("bar").mkdir()  // doesnt throw ∵ we already have the desired result

// easy file-management
let bar = try Path.root.join("foo").copy(to: Path.root/"bar")
print(bar)         // => /bar
print(bar.isFile)  // => true

// careful API considerations so as to avoid common bugs
let foo = try Path.root.join("foo").copy(into: Path.root.join("bar").mkdir())
print(foo)         // => /bar/foo
print(foo.isFile)  // => true

// we support dynamic members (_use_sparingly_):
let prefs = Path.home.Library.Preferences  // => /Users/mxcl/Library/Preferences

// a practical example: installing a helper executable
try Bundle.resources.join("helper").copy(into: Path.home.join(".local/bin").mkdir(.p)).chmod(0o500)

We emphasize safety and correctness, just like Swift, and also (again like Swift), we provide a thoughtful and comprehensive (yet concise) API.

Support mxcl

Hi, Im Max Howell and I have written a lot of open source software, and probably you already use some of it (Homebrew anyone?). I work full-time on open source and its hard; currently I earn less than minimum wage. Please help me continue my work, I appreciate it x

Other donation/tipping options

Handbook

Our online API documentation is automatically updated for new releases.

Codable

We support Codable as you would expect:

try JSONEncoder().encode([Path.home, Path.home/"foo"])
[
    "/Users/mxcl",
    "/Users/mxcl/foo",
]

However, often you want to encode relative paths:

let encoder = JSONEncoder()
encoder.userInfo[.relativePath] = Path.home
encoder.encode([Path.home, Path.home/"foo"])
[
    "",
    "foo",
]

Note make sure you decode with this key set also, otherwise we fatal (unless the paths are absolute obv.)

let decoder = JSONDecoder()
decoder.userInfo[.relativePath] = Path.home
decoder.decode(from: data)

Dynamic members

We support @dynamicMemberLookup:

let ls = Path.root.usr.bin.ls  // => /usr/bin/ls

This is less commonly useful than you would think, hence our documentation does not use it. Usually you are joining variables or other String arguments or trying to describe files (and files usually have extensions). However when you need it, its lovely.

Initializing from user-input

The Path initializer returns nil unless fed an absolute path; thus to initialize from user-input that may contain a relative path use this form:

let path = Path(userInput) ?? Path.cwd/userInput

This is explicit, not hiding anything that code-review may miss and preventing common bugs like accidentally creating Path objects from strings you did not expect to be relative.

Our initializer is nameless to be consistent with the equivalent operation for converting strings to Int, Float etc. in the standard library.

Extensions

We have some extensions to Apple APIs:

let bashProfile = try String(contentsOf: Path.home/".bash_profile")
let history = try Data(contentsOf: Path.home/".history")

bashProfile += "\n\nfoo"

try bashProfile.write(to: Path.home/".bash_profile")

try Bundle.main.resources.join("foo").copy(to: .home)

Directory listings

We provide ls(), called because it behaves like the Terminal ls function, the name thus implies its behavior, ie. that it is not recursive.

for entry in Path.home.ls() {
    print(entry.path)
    print(entry.kind)  // .directory or .file
}

for entry in Path.home.ls() where entry.kind == .file {
    //…
}

for entry in Path.home.ls() where entry.path.mtime > yesterday {
    //…
}

let dirs = Path.home.ls().directories

let files = Path.home.ls().files

let swiftFiles = Path.home.ls().files(withExtension: "swift")

Rules & Caveats

Paths are just string representations, there might not be a real file there.

Path.home/"b"      // => /Users/mxcl/b

// joining multiple strings works as youd expect
Path.home/"b"/"c"  // => /Users/mxcl/b/c

// joining multiple parts at a time is fine
Path.home/"b/c"    // => /Users/mxcl/b/c

// joining with absolute paths omits prefixed slash
Path.home/"/b"     // => /Users/mxcl/b

// of course, feel free to join variables:
let b = "b"
let c = "c"
Path.home/b/c      // => /Users/mxcl/b/c

// tilde is not special here
Path.root/"~b"     // => /~b
Path.root/"~/b"    // => /~/b

// but is here
Path("~/foo")!     // => /Users/mxcl/foo

// this does not work though
Path("~foo")       // => nil

Path.swift has the general policty that if the desired end result preexists, then its a noop:

  • If you try to delete a file, but the file doesn't exist, we do nothing.
  • If you try to make a directory and it already exists, we do nothing.

However notably if you try to copy or move a file with specifying overwrite and the file already exists at the destination and is identical, we dont check for that as the check was deemed too expensive to be worthwhile.

Installation

SwiftPM:

package.append(.package(url: "https://github.com/mxcl/Path.swift", from: "0.5.0"))

CocoaPods:

pod 'Path.swift', '~> 0.5'

Carthage:

Waiting on: @Carthage#1945.

Please note

We are pre 1.0, thus we can change the API as we like, and we will (to the pursuit of getting it right)! We will tag 1.0 as soon as possible.

Get push notifications for new releases

https://codebasesaga.com/canopy/

Alternatives

Description
Delightful, robust, cross-platform and chainable file-pathing functions.
Readme 367 KiB
Languages
Swift 100%