foundation-0.0.1: 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
-- | 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 `FilePath`, it is a void (i.e. `()`)
-- in the case of an `URI`, it is the schema, host, port...
type PathPrefix path
-- | the associated suffix of the given path
--
-- in the case of the `FilePath`, it is a void (i.e. `()`)
-- in the case of the `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 :: 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 :: (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" == ()
-- ```
--
-- 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" == ()
-- ```
--
-- 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