packages feed

hpath 0.12.0 → 0.12.1

raw patch · 4 files changed

+152/−124 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ HPath: basename' :: Path Rel -> Path Rel

Files

CHANGELOG view
@@ -1,3 +1,7 @@+0.12.1+	* Fix bug in "stripDir" and "isParentOf"+	* add total basename' variant for relative dirs+	* Improve documentation 0.12.0 	* Type-safe quasi-quoters wrt [MR #39](https://github.com/hasufell/hpath/pull/39) 	* Allow "." as relative dir wrt #36
hpath.cabal view
@@ -1,5 +1,5 @@ name:                hpath-version:             0.12.0+version:             0.12.1 synopsis:            Support for well-typed paths description:         Support for well-typed paths, utilizing ByteString under the hood. license:             BSD3
src/HPath.hs view
@@ -23,8 +23,8 @@ module HPath   (   -- * Types-   Abs-  ,Path+   Path+  ,Abs   ,Rel   ,PathParseException   ,PathException@@ -46,6 +46,7 @@   -- * Path Operations   ,(</>)   ,basename+  ,basename'   ,dirname   ,getAllParents   ,getAllComponents@@ -64,7 +65,6 @@   )   where -import           Control.Applicative ((<|>)) import           Control.Exception (Exception) import           Control.Monad.Catch (MonadThrow(..)) #if MIN_VERSION_bytestring(0,10,8)@@ -128,20 +128,20 @@ -- -- 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+-- >>> parseAbs "/abc"+-- "/abc"+-- >>> parseAbs "/"+-- "/"+-- >>> parseAbs "/abc/def"+-- "/abc/def"+-- >>> parseAbs "/abc/def/.///"+-- "/abc/def"+-- >>> parseAbs "abc"+-- *** Exception: InvalidAbs "abc"+-- >>> parseAbs ""+-- *** Exception: InvalidAbs ""+-- >>> parseAbs "/abc/../foo"+-- *** Exception: InvalidAbs "/abc/../foo" parseAbs :: MonadThrow m          => ByteString -> m (Path Abs) parseAbs filepath =@@ -155,33 +155,33 @@ -- | Get a location for a relative path. Produces a normalised -- path. ----- Note that @filepath@ may contain any number of @./@.--- It also may not contain a single @..@ anywhere.+-- Note that @filepath@ may contain any number of @./@,+-- but not 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)--- Just "."--- >>> parseRel "././././."  :: Maybe (Path Rel)--- Just "."--- >>> parseRel "./..."      :: Maybe (Path Rel)--- Just "..."--- >>> parseRel ".."         :: Maybe (Path Rel)--- Nothing+-- >>> parseRel "abc"+-- "abc"+-- >>> parseRel "def/"+-- "def"+-- >>> parseRel "abc/def"+-- "abc/def"+-- >>> parseRel "abc/def/."+-- "abc/def"+-- >>> parseRel "/abc"+-- *** Exception: InvalidRel "/abc"+-- >>> parseRel ""+-- *** Exception: InvalidRel ""+-- >>> parseRel "abc/../foo"+-- *** Exception: InvalidRel "abc/../foo"+-- >>> parseRel "."+-- "."+-- >>> parseRel "././././."+-- "."+-- >>> parseRel "./..."+-- "..."+-- >>> parseRel ".."+-- *** Exception: InvalidRel ".." parseRel :: MonadThrow m          => ByteString -> m (Path Rel) parseRel filepath =@@ -196,28 +196,26 @@  -- | Parses a path, whether it's relative or absolute. ----- 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))--- Just (Right ".")--- >>> parseAny ".."         :: Maybe (Either (Path Abs) (Path Rel))--- Nothing+-- >>> parseAny "/abc"+-- Left "/abc"+-- >>> parseAny "..."+-- Right "..."+-- >>> parseAny "abc/def"+-- Right "abc/def"+-- >>> parseAny "abc/def/."+-- Right "abc/def"+-- >>> parseAny "/abc"+-- Left "/abc"+-- >>> parseAny ""+-- *** Exception: InvalidRel ""+-- >>> parseAny "abc/../foo"+-- *** Exception: InvalidRel "abc/../foo"+-- >>> parseAny "."+-- Right "."+-- >>> parseAny ".."+-- *** Exception: InvalidRel ".." parseAny :: MonadThrow m => ByteString -> m (Either (Path Abs) (Path Rel)) parseAny filepath = case parseAbs filepath of   Just p -> pure $ Left p@@ -226,9 +224,11 @@     Nothing       -> throwM (InvalidRel filepath)  +-- | The @"/"@ root path. rootPath :: Path Abs rootPath = (MkPath (BS.singleton _slash)) +-- | The @"."@ pwd path. pwdPath :: Path Rel pwdPath = (MkPath (BS.singleton _period)) @@ -264,17 +264,15 @@ -- because this library is IO-agnostic and makes no assumptions about -- file types. ----- >>> (MkPath "/")        </> (MkPath "file"     :: Path Rel)+-- >>> [abs|/|] </> [rel|file|] -- "/file"--- >>> (MkPath "/path/to") </> (MkPath "file"     :: Path Rel)+-- >>> [abs|/path/to|] </> [rel|file|] -- "/path/to/file"--- >>> (MkPath "/")        </> (MkPath "file/lal" :: Path Rel)+-- >>> [abs|/|] </> [rel|file/lal|] -- "/file/lal"--- >>> (MkPath "/")        </> (MkPath "file/"    :: Path Rel)--- "/file"--- >>> (MkPath "/")        </> (MkPath "."        :: Path Rel)+-- >>> [abs|/|] </> [rel|.|] -- "/"--- >>> (MkPath ".")        </> (MkPath "."        :: Path Rel)+-- >>> [rel|.|] </> [rel|.|] -- "." (</>) :: Path b -> Path Rel -> Path b (</>) (MkPath a) (MkPath b) =@@ -286,37 +284,37 @@ -- -- 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)--- Just "."--- >>> (MkPath "/lal/lad/fad") `stripDir` (MkPath "/lal/lad")     :: Maybe (Path Rel)--- Nothing--- >>> (MkPath "/abs")         `stripDir` (MkPath "/lal/lad")     :: Maybe (Path Rel)--- Nothing--- >>> (MkPath "fad")          `stripDir` (MkPath "fad")          :: Maybe (Path Rel)--- Just "."-stripDir :: MonadThrow m-         => Path b -> Path b -> m (Path Rel)-stripDir (MkPath p) (MkPath l) =-  case stripPrefix p' l <|> stripPrefix p l of-    Nothing -> throwM (Couldn'tStripPrefixTPS p' l)-    Just ok -> if BS.null ok-                 then return (MkPath $ BS.singleton _period)-                 else return (MkPath ok)-  where-    p' = addTrailingPathSeparator p+-- >>> [abs|/lal/lad|]     `stripDir` [abs|/lal/lad/fad|]+-- "fad"+-- >>> [rel|lal/lad|]      `stripDir` [rel|lal/lad/fad|]+-- "fad"+-- >>> [abs|/|]            `stripDir` [abs|/|]+-- "."+-- >>> [abs|/lal/lad/fad|] `stripDir` [abs|/lal/lad|]+-- *** Exception: Couldn'tStripPrefixTPS "/lal/lad/fad" "/lal/lad"+-- >>> [abs|/abs|]         `stripDir` [abs|/lal/lad|]+-- *** Exception: Couldn'tStripPrefixTPS "/abs" "/lal/lad"+-- >>> [rel|fad|]          `stripDir` [rel|fad|]+-- "."+-- >>> [rel|.|]            `stripDir` [rel|.|]+-- "."+-- >>> [rel|.|]            `stripDir` [rel|.foo|]+-- *** Exception: Couldn'tStripPrefixTPS "." ".foo"+stripDir :: MonadThrow m => Path b -> Path b -> m (Path Rel)+stripDir (MkPath p) (MkPath l)+  | p == l = return pwdPath+  | otherwise = case stripPrefix (addTrailingPathSeparator p) l of+    Nothing -> throwM (Couldn'tStripPrefixTPS p l)+    Just ok -> return (MkPath ok)   -- |Get all parents of a path. ----- >>> getAllParents (MkPath "/abs/def/dod")+-- >>> getAllParents [abs|/abs/def/dod|] -- ["/abs/def","/abs","/"]--- >>> getAllParents (MkPath "/foo")+-- >>> getAllParents [abs|/foo|] -- ["/"]--- >>> getAllParents (MkPath "/")+-- >>> getAllParents [abs|/|] -- [] getAllParents :: Path Abs -> [Path Abs] getAllParents (MkPath p)@@ -328,19 +326,21 @@  -- | Gets all path components. ----- >>> getAllComponents (MkPath "abs/def/dod")+-- >>> getAllComponents [rel|abs/def/dod|] -- ["abs","def","dod"]--- >>> getAllComponents (MkPath "abs")+-- >>> getAllComponents [rel|abs|] -- ["abs"]+-- >>> getAllComponents [rel|.|]+-- ["."] getAllComponents :: Path Rel -> [Path Rel] getAllComponents (MkPath p) = fmap MkPath . splitDirectories $ p   -- | Gets all path components after the "/" root directory. ----- >>> getAllComponentsAfterRoot (MkPath "/abs/def/dod")+-- >>> getAllComponentsAfterRoot [abs|/abs/def/dod|] -- ["abs","def","dod"]--- >>> getAllComponentsAfterRoot (MkPath "/abs")+-- >>> getAllComponentsAfterRoot [abs|/abs|] -- ["abs"] getAllComponentsAfterRoot :: Path Abs -> [Path Rel] getAllComponentsAfterRoot p = getAllComponents (fromJust $ stripDir rootPath p)@@ -348,9 +348,9 @@  -- | Extract the directory name of a path. ----- >>> dirname (MkPath "/abc/def/dod")+-- >>> dirname [abs|/abc/def/dod|] -- "/abc/def"--- >>> dirname (MkPath "/")+-- >>> dirname [abs|/|] -- "/" dirname :: Path Abs -> Path Abs dirname (MkPath fp) = MkPath (takeDirectory fp)@@ -364,16 +364,16 @@ -- -- 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)--- Just "."--- >>> basename (MkPath "/")            :: Maybe (Path Rel)--- Nothing+-- >>> basename [abs|/abc/def/dod|]+-- "dod"+-- >>> basename [rel|abc/def/dod|]+-- "dod"+-- >>> basename [rel|dod|]+-- "dod"+-- >>> basename [rel|.|]+-- "."+-- >>> basename [abs|/|]+-- *** Exception: RootDirHasNoBasename basename :: MonadThrow m => Path b -> m (Path Rel) basename (MkPath l)   | not (isAbsolute rl) = return $ MkPath rl@@ -381,6 +381,20 @@   where     rl = last . splitPath $ l +-- | Extract the file part of a relative path.+--+-- The following properties hold:+--+-- @basename' (p \<\/> a) == basename' a@+--+-- >>> basename' [rel|abc/def/dod|]+-- "dod"+-- >>> basename' [rel|dod|]+-- "dod"+-- >>> basename' [rel|.|]+-- "."+basename' :: Path Rel -> Path Rel+basename' (MkPath l) = MkPath . last . splitPath $ l   --------------------------------------------------------------------------------@@ -389,16 +403,18 @@ -- | 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")+-- >>> [abs|/lal/lad|]     `isParentOf` [abs|/lal/lad/fad|] -- True--- >>> (MkPath "lal/lad")      `isParentOf` (MkPath "lal/lad/fad")+-- >>> [rel|lal/lad|]      `isParentOf` [rel|lal/lad/fad|] -- True--- >>> (MkPath "/")            `isParentOf` (MkPath "/")+-- >>> [abs|/|]            `isParentOf` [abs|/|] -- False--- >>> (MkPath "/lal/lad/fad") `isParentOf` (MkPath "/lal/lad")+-- >>> [abs|/lal/lad/fad|] `isParentOf` [abs|/lal/lad|] -- False--- >>> (MkPath "fad")          `isParentOf` (MkPath "fad")+-- >>> [rel|fad|]          `isParentOf` [rel|fad|] -- False+-- >>> [rel|.|]            `isParentOf` [rel|.foo|]+-- False isParentOf :: Path b -> Path b -> Bool isParentOf p l = case stripDir p l :: Maybe (Path Rel) of   Nothing -> False@@ -409,18 +425,18 @@  -- | Check whether the given Path is the root "/" path. ----- >>> isRootPath (MkPath "/lal/lad")+-- >>> isRootPath [abs|/lal/lad|] -- False--- >>> isRootPath (MkPath "/")+-- >>> isRootPath [abs|/|] -- True isRootPath :: Path Abs -> Bool isRootPath = (== rootPath)  -- | Check whether the given Path is the pwd "." path. ----- >>> isPwdPath (MkPath "/lal/lad")+-- >>> isPwdPath [rel|lal/lad|] -- False--- >>> isPwdPath (MkPath ".")+-- >>> isPwdPath [rel|.|] -- True isPwdPath :: Path Rel -> Bool isPwdPath = (== pwdPath)
src/HPath/Internal.hs view
@@ -14,15 +14,23 @@ -- -- The type variable 'b' is either: -----   * Abs -- absolute path---   * Rel -- relative path+--   * 'HPath.Abs' -- absolute path (starting with a @"/"@)+--   * 'HPath.Rel' -- relative path (not starting with a @"/"@) ----- Internally is a ByteString. The path is guaranteed to+-- Internally it is a ByteString. The path is guaranteed to -- be normalised and contain no trailing Path separators,--- except for the '/' root path.+-- except for the @"/"@ root path. -- -- There are no duplicate path separators--- @\/\/@, no @..@, no @.\/@, no @~\/@, etc.+-- @"\/\/"@, no @".."@, no @".\/"@, etc.+-- +-- Two special paths exist:+--+--  * @"/"@ -- the 'HPath.rootPath' (absolute)+--  * @"."@ -- the 'HPath.pwdPath' (relative)+--+-- The constructor is not exposed. Instead, use the smart constructors+-- 'HPath.parseAbs', 'HPath.parseRel' and 'HPath.parseAny'. data Path b = MkPath ByteString   deriving (Typeable)