foundation-0.0.2: Foundation/VFS/Path.hs
-- |
-- Module : Foundation.VFS.Path
-- License : BSD-style
-- Maintainer : foundation
-- Stability : experimental
-- Portability : portable
--
{-# LANGUAGE FlexibleContexts #-}
module Foundation.VFS.Path
(
-- * Path class
Path(..)
, parent
, filename
, prefix
, suffix
) where
import Foundation.Internal.Base
-- $setup
-- >>> import Foundation.Internal.Base
-- >>> import Foundation.VFS.FilePath
-- >>> import Foundation.VFS.Path
-- | Path type class
--
-- defines the Path associated types and basic functions to implement related
-- to the path manipulation
--
-- # TODO, add missing enhancement:
--
-- @
-- splitExtension :: PathEnt path -> (PathEnt path, PathEnt path)
-- addExtension :: PathEnt path -> PathEnt path -> PathEnt path
-- (<.>) :: path -> PathEnt path -> path
-- (-<.>) :: path -> PathEnt path -> path
-- @
--
class Path path where
-- | the associated PathEntity of the given `path`
-- this type is the minimal element contained in the Path
-- a Path is not a collection but it is possible to see this
-- associated type equivalent to the `Foundation.Collection.Element` type family
type PathEnt path
-- | the associated prefix of the given `path`
--
-- in the case of a `Foundation.VFS.FilePath`, it is a void (i.e. `()`)
-- in the case of a `Foundation.VFS.URI`, it is the schema, host, port...
type PathPrefix path
-- | the associated suffix of the given path
--
-- in the case of the `Foundation.VFS.FilePath`, it is a void (i.e. `()`)
-- in the case of the `Foundation.VFS.URI`, it is a the query, the fragment
type PathSuffix path
-- | join a path entity to a given path
(</>) :: path -> PathEnt path -> path
-- | split the path into the associated elements
splitPath :: path -> ( PathPrefix path
, [PathEnt path]
, PathSuffix path
)
-- | build the path from the associated elements
buildPath :: ( PathPrefix path
, [PathEnt path]
, PathSuffix path
)
-> path
-- | parent is only going to drop the filename.
--
-- if you actually want to reference to the parent directory, simply uses:
--
-- @
-- parent "." /= "." </> ".."
-- @
--
-- >>> parent ("foo.hs" :: FilePath)
-- .
--
-- >>> parent ("foo/bar/baz.hs" :: FilePath)
-- foo/bar
parent :: Path path => path -> path
parent path = buildPath (p, init ps, s)
where
(p, ps, s) = splitPath path
-- | get the filename of the given path
--
-- If there is no filename, you will receive the 'mempty' of the 'PathEnt'
--
-- >>> filename ("foo.hs" :: FilePath)
-- foo.hs
--
-- >>> filename ("foo/bar/baz.hs" :: FilePath)
-- baz.hs
filename :: (Path path, Monoid (PathEnt path)) => path -> PathEnt path
filename path = case ps of
[] -> mempty
_ -> last ps
where
(_, ps , _) = splitPath path
-- TODO: this might be better in Sequential ?
init :: [a] -> [a]
init [] = []
init [_] = []
init (x:xs) = x : init xs
-- TODO: this might be better in Sequential ?
last :: [a] -> a
last [] = undefined
last [x] = x
last (_:xs) = last xs
-- | get the path prefix information
--
-- >>> prefix ("/home/tab" :: FilePath)
-- Absolute
--
-- >>> prefix ("home/tab" :: FilePath)
-- Relative
--
-- or for URI (TODO, not yet accurate)
--
-- @
-- prefix "http://github.com/vincenthz/hs-foundation?w=1"
-- == URISchema http Nothing Nothing "github.com" Nothing
-- @
prefix :: Path path => path -> PathPrefix path
prefix p = pre
where
(pre, _, _) = splitPath p
-- | get the path suffix information
--
-- >>> suffix ("/home/tab" :: FilePath)
-- ()
--
-- or for URI (TODO, not yet accurate)
--
-- @
-- suffix "http://github.com/vincenthz/hs-foundation?w=1"
-- == URISuffix (["w", "1"], Nothing)
-- @
suffix :: Path path => path -> PathSuffix path
suffix p = suf
where
(_, _, suf) = splitPath p