hpath-0.11.0: Support for well-typed paths

Copyright© 2015–2016 FP Complete 2016 Julian Ospald
LicenseBSD 3 clause
MaintainerJulian Ospald <hasufell@posteo.de>
Stabilityexperimental
Portabilityportable
Safe HaskellNone
LanguageHaskell2010

HPath

Contents

Description

Support for well-typed paths.

Synopsis

Types

data Abs Source #

An absolute path.

data Path b Source #

The main Path type.

The type variable b is either:

  • Abs -- absolute path
  • Rel -- relative path

Internally is a ByteString. The path is guaranteed to be normalised and contain no trailing Path separators, except for the / root path.

There are no duplicate path separators //, no .., no ./, no ~/, etc.

Instances
Eq (Path b) Source #

ByteString equality.

The following property holds:

show x == show y ≡ x == y
Instance details

Defined in HPath.Internal

Methods

(==) :: Path b -> Path b -> Bool #

(/=) :: Path b -> Path b -> Bool #

Ord (Path b) Source #

ByteString ordering.

The following property holds:

show x `compare` show y ≡ x `compare` y
Instance details

Defined in HPath.Internal

Methods

compare :: Path b -> Path b -> Ordering #

(<) :: Path b -> Path b -> Bool #

(<=) :: Path b -> Path b -> Bool #

(>) :: Path b -> Path b -> Bool #

(>=) :: Path b -> Path b -> Bool #

max :: Path b -> Path b -> Path b #

min :: Path b -> Path b -> Path b #

Show (Path b) Source #

Same as toFilePath.

The following property holds:

x == y ≡ show x == show y
Instance details

Defined in HPath.Internal

Methods

showsPrec :: Int -> Path b -> ShowS #

show :: Path b -> String #

showList :: [Path b] -> ShowS #

Lift (Path a) Source # 
Instance details

Defined in HPath

Methods

lift :: Path a -> Q Exp #

NFData (Path b) Source # 
Instance details

Defined in HPath.Internal

Methods

rnf :: Path b -> () #

data Rel Source #

A relative path; one without a root.

PatternSynonyms/ViewPatterns

pattern Path :: ByteString -> Path a Source #

Path Construction

parseAbs :: MonadThrow m => ByteString -> m (Path Abs) Source #

Get a location for an absolute path. Produces a normalised path.

Throws: PathParseException

>>> parseAbs "/abc"          :: Maybe (Path Abs)
Just "/abc"
>>> parseAbs "/"             :: Maybe (Path Abs)
Just "/"
>>> parseAbs "/abc/def"      :: Maybe (Path Abs)
Just "/abc/def"
>>> parseAbs "/abc/def/.///" :: Maybe (Path Abs)
Just "/abc/def"
>>> parseAbs "abc"           :: Maybe (Path Abs)
Nothing
>>> parseAbs ""              :: Maybe (Path Abs)
Nothing
>>> parseAbs "/abc/../foo"   :: Maybe (Path Abs)
Nothing

parseRel :: MonadThrow m => ByteString -> m (Path Rel) Source #

Get a location for a relative path. Produces a normalised path.

Note that filepath may contain any number of ./ but may not consist solely of ./. It also may not contain a single .. anywhere.

Throws: PathParseException

>>> parseRel "abc"        :: Maybe (Path Rel)
Just "abc"
>>> parseRel "def/"       :: Maybe (Path Rel)
Just "def"
>>> parseRel "abc/def"    :: Maybe (Path Rel)
Just "abc/def"
>>> parseRel "abc/def/."  :: Maybe (Path Rel)
Just "abc/def"
>>> parseRel "/abc"       :: Maybe (Path Rel)
Nothing
>>> parseRel ""           :: Maybe (Path Rel)
Nothing
>>> parseRel "abc/../foo" :: Maybe (Path Rel)
Nothing
>>> parseRel "."          :: Maybe (Path Rel)
Nothing
>>> parseRel ".."         :: Maybe (Path Rel)
Nothing

parseAny :: MonadThrow m => ByteString -> m (Either (Path Abs) (Path Rel)) Source #

Parses a path, whether it's relative or absolute. Will lose information on whether it's relative or absolute. If you need to know, reparse it.

Filenames must not contain slashes. Excludes . and '..'.

Throws: PathParseException

>>> parseAny "/abc"       :: Maybe (Either (Path Abs) (Path Rel))
Just (Left "/abc")
>>> parseAny "..."        :: Maybe (Either (Path Abs) (Path Rel))
Just (Right "...")
>>> parseAny "abc/def"    :: Maybe (Either (Path Abs) (Path Rel))
Just (Right "abc/def")
>>> parseAny "abc/def/."  :: Maybe (Either (Path Abs) (Path Rel))
Just (Right "abc/def")
>>> parseAny "/abc"       :: Maybe (Either (Path Abs) (Path Rel))
Just (Left "/abc")
>>> parseAny ""           :: Maybe (Either (Path Abs) (Path Rel))
Nothing
>>> parseAny "abc/../foo" :: Maybe (Either (Path Abs) (Path Rel))
Nothing
>>> parseAny "."          :: Maybe (Either (Path Abs) (Path Rel))
Nothing
>>> parseAny ".."         :: Maybe (Either (Path Abs) (Path Rel))
Nothing

Path Conversion

fromAbs :: Path Abs -> ByteString Source #

Convert an absolute Path to a ByteString type.

fromRel :: Path Rel -> ByteString Source #

Convert a relative Path to a ByteString type.

toFilePath :: Path b -> ByteString Source #

Convert any Path to a ByteString type.

Path Operations

(</>) :: Path b -> Path Rel -> Path b Source #

Append two paths.

The second argument must always be a relative path, which ensures that undefinable things like `"abc" <> "/def"` cannot happen.

Technically, the first argument can be a path that points to a non-directory, because this library is IO-agnostic and makes no assumptions about file types.

>>> (MkPath "/")        </> (MkPath "file"     :: Path Rel)
"/file"
>>> (MkPath "/path/to") </> (MkPath "file"     :: Path Rel)
"/path/to/file"
>>> (MkPath "/")        </> (MkPath "file/lal" :: Path Rel)
"/file/lal"
>>> (MkPath "/")        </> (MkPath "file"    :: Path Rel)
"/file"

basename :: MonadThrow m => Path b -> m (Path Rel) Source #

Extract the file part of a path.

The following properties hold:

basename (p </> a) == basename a

Throws: PathException if given the root path "/"

>>> basename (MkPath "/abc/def/dod") :: Maybe (Path Rel)
Just "dod"
>>> basename (MkPath "abc/def/dod")  :: Maybe (Path Rel)
Just "dod"
>>> basename (MkPath "dod")          :: Maybe (Path Rel)
Just "dod"
>>> basename (MkPath "/")            :: Maybe (Path Rel)
Nothing

dirname :: Path Abs -> Path Abs Source #

Extract the directory name of a path.

>>> dirname (MkPath "/abc/def/dod")
"/abc/def"
>>> dirname (MkPath "/")
"/"

getAllParents :: Path Abs -> [Path Abs] Source #

Get all parents of a path.

>>> getAllParents (MkPath "/abs/def/dod")
["/abs/def","/abs","/"]
>>> getAllParents (MkPath "/foo")
["/"]
>>> getAllParents (MkPath "/")
[]

getAllComponents :: Path Rel -> [Path Rel] Source #

Gets all path components.

>>> getAllComponents (MkPath "abs/def/dod")
["abs","def","dod"]
>>> getAllComponents (MkPath "abs")
["abs"]

getAllComponentsAfterRoot :: Path Abs -> [Path Rel] Source #

Gets all path components after the "/" root directory.

>>> getAllComponentsAfterRoot (MkPath "/abs/def/dod")
["abs","def","dod"]
>>> getAllComponentsAfterRoot (MkPath "/abs")
["abs"]

stripDir :: MonadThrow m => Path b -> Path b -> m (Path Rel) Source #

Strip directory from path, making it relative to that directory. Throws Couldn'tStripPrefixDir if directory is not a parent of the path.

The bases must match.

>>> (MkPath "/lal/lad")     `stripDir` (MkPath "/lal/lad/fad") :: Maybe (Path Rel)
Just "fad"
>>> (MkPath "lal/lad")      `stripDir` (MkPath "lal/lad/fad")  :: Maybe (Path Rel)
Just "fad"
>>> (MkPath "/")            `stripDir` (MkPath "/")            :: Maybe (Path Rel)
Nothing
>>> (MkPath "/lal/lad/fad") `stripDir` (MkPath "/lal/lad")     :: Maybe (Path Rel)
Nothing
>>> (MkPath "fad")          `stripDir` (MkPath "fad")          :: Maybe (Path Rel)
Nothing

Path Examination

isParentOf :: Path b -> Path b -> Bool Source #

Is p a parent of the given location? Implemented in terms of stripDir. The bases must match.

>>> (MkPath "/lal/lad")     `isParentOf` (MkPath "/lal/lad/fad")
True
>>> (MkPath "lal/lad")      `isParentOf` (MkPath "lal/lad/fad")
True
>>> (MkPath "/")            `isParentOf` (MkPath "/")
False
>>> (MkPath "/lal/lad/fad") `isParentOf` (MkPath "/lal/lad")
False
>>> (MkPath "fad")          `isParentOf` (MkPath "fad")
False

isRootPath :: Path Abs -> Bool Source #

Check whether the given Path is the root "/" path.

>>> isRootPath (MkPath "/lal/lad")
False
>>> isRootPath (MkPath "/")
True

Path IO helpers

Quasiquoters

abs :: QuasiQuoter Source #

Quasiquote an absolute Path. This accepts Unicode Chars and will encode as UTF-8.

>>> [abs|/etc/profile|] :: Path Abs
"/etc/profile"
>>> [abs|/|] :: Path Abs
"/"
>>> [abs|/|] :: Path Abs
"/\239\131\144"

rel :: QuasiQuoter Source #

Quasiquote a relative Path. This accepts Unicode Chars and will encode as UTF-8.

>>> [rel|etc|] :: Path Rel
"etc"
>>> [rel|bar/baz|] :: Path Rel
"bar/baz"
>>> [rel||] :: Path Rel
"\239\131\144"

Orphan instances

Lift (Path a) Source # 
Instance details

Methods

lift :: Path a -> Q Exp #