within 0.0.2.0 → 0.1.0.0
raw patch · 4 files changed
+119/−77 lines, 4 filesdep +comonaddep +freePVP ok
version bump matches the API change (PVP)
Dependencies added: comonad, free
API changes (from Hackage documentation)
- Within: Within :: (Path a Dir, Path Rel t) -> Within a t
- Within: blinkAndMapT :: MonadThrow m => Path b Dir -> (Path Rel s -> m (Path Rel t)) -> Within a s -> m (Within b t)
- Within: blinkWithin :: Path b Dir -> Within a t -> Within b t
- Within: instance Data.Hashable.Class.Hashable (Within.Within a t)
- Within: instance GHC.Classes.Eq (Within.Within a t)
- Within: instance GHC.Classes.Ord (Within.Within a t)
- Within: instance GHC.Generics.Generic (Within.Within a t)
- Within: instance GHC.Show.Show (Within.Within a t)
- Within: mapWithin :: (Path Rel s -> Path Rel t) -> Within a s -> Within a t
- Within: mapWithinT :: MonadThrow m => (Path Rel s -> m (Path Rel t)) -> Within a s -> m (Within a t)
- Within: moveAndMapT :: MonadThrow m => (Path a Dir -> m (Path b Dir)) -> (Path Rel s -> m (Path Rel t)) -> Within a s -> m (Within b t)
- Within: moveWithin :: (Path a Dir -> Path b Dir) -> Within a t -> Within b t
- Within: moveWithinT :: MonadThrow m => (Path a Dir -> m (Path b Dir)) -> Within a t -> m (Within b t)
- Within: newtype Within a t
- Within: toWithin :: Path a Dir -> Path Rel t -> Within a t
- Within: whatLiesWithin :: Within a t -> Path Rel t
+ Within: WithinT :: EnvT (Path b Dir) w a -> WithinT b w a
+ Within: blinkAndMap :: Functor w => Path b Dir -> (s -> t) -> WithinT a w s -> WithinT b w t
+ Within: blinkAndMapM :: (Monad m, Traversable w) => Path b Dir -> (s -> m t) -> WithinT a w s -> m (WithinT b w t)
+ Within: blinkLocalDir :: Path b Dir -> WithinT a w t -> WithinT b w t
+ Within: instance Control.Comonad.Comonad w => Control.Comonad.Comonad (Within.WithinT b w)
+ Within: instance Control.Comonad.Comonad w => Control.Comonad.Env.Class.ComonadEnv (Path.Internal.Path b Path.Posix.Dir) (Within.WithinT b w)
+ Within: instance Control.Comonad.Trans.Class.ComonadTrans (Within.WithinT b)
+ Within: instance Data.Foldable.Foldable w => Data.Foldable.Foldable (Within.WithinT b w)
+ Within: instance Data.Hashable.Class.Hashable t => Data.Hashable.Class.Hashable (Within.Within b t)
+ Within: instance Data.Traversable.Traversable w => Data.Traversable.Traversable (Within.WithinT b w)
+ Within: instance GHC.Base.Functor w => GHC.Base.Functor (Within.WithinT b w)
+ Within: instance GHC.Classes.Eq t => GHC.Classes.Eq (Within.Within b t)
+ Within: instance GHC.Show.Show t => GHC.Show.Show (Within.Within b t)
+ Within: localDir :: (Path b Dir -> Path c Dir) -> WithinT b w a -> WithinT c w a
+ Within: localDirAndMapM :: (Monad m, Traversable w) => (Path b Dir -> m (Path c Dir)) -> (s -> m t) -> WithinT b w s -> m (WithinT c w t)
+ Within: localDirM :: Monad m => (Path b Dir -> m (Path c Dir)) -> WithinT b w a -> m (WithinT c w a)
+ Within: newtype WithinT b w a
+ Within: type Within b a = WithinT b Identity a
- Within: asWithin :: MonadThrow m => Path a t -> Path a Dir -> m (Within a t)
+ Within: asWithin :: MonadThrow m => Path a t -> Path a Dir -> m (Within a (Path Rel t))
- Within: fromWithin :: Within a t -> Path a t
+ Within: fromWithin :: Within a (Path Rel t) -> Path a t
- Within: within :: Path Rel t -> Path a Dir -> Within a t
+ Within: within :: a -> Path b Dir -> Within b a
Files
- ChangeLog.md +6/−0
- README.md +25/−5
- src/Within.hs +82/−68
- within.cabal +6/−4
ChangeLog.md view
@@ -1,5 +1,11 @@ # Changelog for within +## v0.1.0.0++Change approach to `ComonadEnv` style newtype. `Within` can now store an arbitrary+inner type whilst maintaining the convenience functions in the special case where+the inner type is a `Path`.+ ## v0.0.2.0 * Add `Hashable` and `Ord` instances for `Within`.
README.md view
@@ -1,8 +1,28 @@ # Within -`Within` is a type for simply scoping well-typed paths. A `Within a t` is-just a `Path Rel t` inside a `Path a Dir`. This is useful for when you want-to keep track of a filepath within a parent folder and need the extra degree-of articulation.+`Within` is a type for simply scoping well-typed paths. A `Within b a` is+simply an `Env` comonad with the environment specialised to `Path b Dir`. This+is useful for when you want to keep track of things that live within a parent+folder and need the extra degree of articulation. You can construct a value `a`+living within a `Path b Dir` using the `within` infix operator. -Early release, subject to change.+```{.haskell}+5 `within` $(mkRelDir "foo")+```++There are also convenience functions for dealing with the special case where+the inner type is a `Path Rel File`, which represents a path to a file within a+directory. This does not need to be an immediate child of the directory, and+does not have to exist. You can assert that you can assert that an existing+path lies in a directory by using `asWithin`, which throws if the directory is+not a proper prefix of the `Path`.++```{.haskell}+$(mkRelFile "foo/a.txt") `asWithin` $(mkRelDir "foo") -- fine+$(mkRelFile "a.txt") `asWithin` $(mkRelDir "foo") -- throws NotAProperPrefix Exception+```++You can also use `fromWithin` to get from a `Within a (Path Rel t)` to a `Path a t`.++There are also `Eq`, `Show` and `Hashable` instances when the extract target is of+that class.
src/Within.hs view
@@ -1,87 +1,101 @@-{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Within (- Within(..)-, fromWithin-, toWithin-, within+ WithinT(..)+, Within(..)+, localDir+, localDirM , asWithin-, whatLiesWithin-, mapWithin-, mapWithinT-, moveWithin-, moveWithinT-, blinkWithin-, moveAndMapT-, blinkAndMapT+, within+, fromWithin+, blinkLocalDir+, blinkAndMap+, blinkAndMapM+, localDirAndMapM ) where -import Control.Monad.Catch-import Data.Typeable-import Data.Hashable-import GHC.Generics-import Path+import Control.Applicative+import Control.Comonad+import Control.Comonad.Env+import Control.Monad+import Control.Monad.Catch+import Data.Functor.Identity+import Data.Hashable+import Data.Typeable+import GHC.Generics+import Path --- | The `Within` type represents a relative `Path` inside a directory `Path`.--- The two halves can be manipulated independently.-newtype Within a t = Within (Path a Dir, Path Rel t)- deriving (Typeable, Generic, Eq, Show)+-- | Transform the environment of an `EnvT` via some monadic operation. This didn't seem to+-- exist anywhere but it used for some internal operations.+localM :: Monad m => (e -> m e') -> EnvT e w a -> m (EnvT e' w a)+localM f (EnvT e wa) = f e >>= \e' -> return $ EnvT e' wa -instance Hashable (Within a t) where- hashWithSalt n w = hashWithSalt n (fromWithin w)+-- | The Within Type, newtype wrapper around `EnvT` specialised to a `Path b Dir` environment.+newtype WithinT b w a = WithinT (EnvT (Path b Dir) w a)+ deriving (Functor, Foldable, Traversable) -instance Ord (Within a t) where- compare (Within (x, y)) (Within (x',y')) = compare x x' <> compare y y'+type Within b a = WithinT b Identity a --- | Convert a `Within` to a `Path` by joining it with a path separator.-fromWithin :: Within a t -> Path a t-fromWithin (Within (x,y)) = x </> y+instance Comonad w => Comonad (WithinT b w) where+ extract (WithinT w) = extract w+ duplicate (WithinT w) = WithinT (extend WithinT w) --- | Convert a directory `Path` and a relative `Path` to a `Within`-toWithin :: Path a Dir -> Path Rel t -> Within a t-toWithin = flip within+instance Comonad w => ComonadEnv (Path b Dir) (WithinT b w) where+ ask (WithinT w) = ask w --- | Infix version of `toWithin`, e.g "file.txt \`within\` myDir"-within :: Path Rel t -> Path a Dir -> Within a t-within y x = Within (x,y)+instance ComonadTrans (WithinT b) where+ lower (WithinT w) = lower w --- | Attempts to convert a `Path` to a `Within` by treating it as if it were--- within the second argument. Used infix as "myParentDir\/foo\/file.txt \`asWithin\` myParentDir"-asWithin :: MonadThrow m => Path a t -> Path a Dir -> m (Within a t)-asWithin x y = stripProperPrefix y x >>= \z -> return (Within (y, z))+-- | Change the parent directory of a `Within` value.+localDir :: (Path b Dir -> Path c Dir) -> WithinT b w a -> WithinT c w a+localDir f (WithinT w) = WithinT (local f w) --- | Extracts the inner path.-whatLiesWithin :: Within a t -> Path Rel t-whatLiesWithin (Within (_,y)) = y+-- | Change the parent directory of a `Within` value, monadic verison.+localDirM :: Monad m => (Path b Dir -> m (Path c Dir)) -> WithinT b w a -> m (WithinT c w a)+localDirM f (WithinT (EnvT e wa)) = f e >>= \e' -> return $ WithinT $ EnvT e' wa --- | Map the inner part of the `Within` value to a new `Path`.-mapWithin :: (Path Rel s -> Path Rel t) -> Within a s -> Within a t-mapWithin f (Within (x,y)) = Within (x, f y)+-- | Treat a `Path` as if it lies within another directory and returns a `Within` value.+-- Used infix like+--+-- >>> $(mkRelFile "foo/a.txt") `asWithin` $(mkRelDir "foo")+--+asWithin :: MonadThrow m => Path a t -> Path a Dir -> m (Within a (Path Rel t))+asWithin x y = stripProperPrefix y x >>= \z -> return (WithinT (EnvT y (Identity z))) --- | Map the inner part of the `Within` value to a new `Path` with an operation that may throw.-mapWithinT :: MonadThrow m => (Path Rel s -> m (Path Rel t)) -> Within a s -> m (Within a t)-mapWithinT f (Within (x,y)) = f y >>= \z -> return (Within (x, z))+-- | Put a value inside a directory.+--+-- >>> $(mkRelFile "a.txt") `within` $(mkRelDir "foo")+within :: a -> Path b Dir -> Within b a+within x y = WithinT (EnvT y (Identity x)) --- | Switch the outer part of a `Within` value to a new directory immediately.-blinkWithin :: Path b Dir -> Within a t -> Within b t-blinkWithin = moveWithin . const+-- | Turns a `Within` containing a path into a single path.+fromWithin :: Within a (Path Rel t) -> Path a t+fromWithin = liftA2 (</>) ask extract --- | Map the outer part of a `Within` value via a function that changes the directory.-moveWithin :: (Path a Dir -> Path b Dir) -> Within a t -> Within b t-moveWithin f (Within (x,y)) = Within (f x, y)+instance Eq t => Eq (Within b t) where+ WithinT (EnvT e (Identity a)) == WithinT (EnvT e' (Identity a')) = e == e' && a == a' --- | Map the outer part of a `Within` value via a function that changes the directory with an operation that may throw.-moveWithinT :: MonadThrow m => (Path a Dir -> m (Path b Dir)) -> Within a t -> m (Within b t)-moveWithinT f (Within (x,y)) = f x >>= \z -> return (Within (z,y))+instance Hashable t => Hashable (Within b t) where+ hashWithSalt n (WithinT (EnvT e (Identity a))) = n `hashWithSalt` e `hashWithSalt` a --- | `blinkWithin` and `mapWithinT` simultaneously.-blinkAndMapT :: MonadThrow m => Path b Dir -> (Path Rel s -> m (Path Rel t)) -> Within a s -> m (Within b t)-blinkAndMapT k g (Within (_,y)) = do- y' <- g y- return $ Within (k, y')+instance Show t => Show (Within b t) where+ show (WithinT (EnvT e a)) = show e ++ "/" ++ show a --- | `moveWithinT` and `mapWithinT` simultaneously.-moveAndMapT :: MonadThrow m => (Path a Dir -> m (Path b Dir)) -> (Path Rel s -> m (Path Rel t)) -> Within a s -> m (Within b t)-moveAndMapT f g (Within (x,y)) = do- x' <- f x- y' <- g y- return $ Within (x', y')+-- | Switch the outer part of a `Within` value to a new directory, synonym for localDir . const+blinkLocalDir :: Path b Dir -> WithinT a w t -> WithinT b w t+blinkLocalDir = localDir . const++-- | Switch the outer part of a `Within` value to a new directory and map the inner at the same time.+blinkAndMap :: Functor w => Path b Dir -> (s -> t) -> WithinT a w s -> WithinT b w t+blinkAndMap k g = blinkLocalDir k . fmap g++-- | Switch the outer part of a `Within` value to a new directory and mapM the inner at the same time.+blinkAndMapM :: (Monad m, Traversable w) => Path b Dir -> (s -> m t) -> WithinT a w s -> m (WithinT b w t)+blinkAndMapM k g = mapM g . blinkLocalDir k++-- | mapM the outer and inner part of a `Within` value at the same time.+localDirAndMapM :: (Monad m, Traversable w) => (Path b Dir -> m (Path c Dir)) -> (s -> m t) -> WithinT b w s -> m (WithinT c w t)+localDirAndMapM f g = localDirM f <=< mapM g
within.cabal view
@@ -4,12 +4,12 @@ -- -- see: https://github.com/sol/hpack ----- hash: 004fe9914c61fa868f90faa3426e02ca5cd16bee28f31fe937952e591450cbe1+-- hash: e6c160a7690f01c363fdf8c27b7042b52b5854b49d157968cc37dcc201eb3885 name: within-version: 0.0.2.0-synopsis: A path within another path.-description: Simple type for representing a well-typed path within another path. Useful for when you need to jump between directories and change filenames independently. Uses the path library.+version: 0.1.0.0+synopsis: A value within another path.+description: Simple newtype for representing a value within a well-typed directory. Useful for when you need to jump between directories and change filenames independently. Uses the path library. category: Filesystem author: Daniel Firth maintainer: dan.firth@homotopic.tech@@ -30,7 +30,9 @@ src build-depends: base >=4.7 && <5+ , comonad , exceptions+ , free , hashable , path default-language: Haskell2010