find-conduit 0.4.0 → 0.4.1
raw patch · 4 files changed
+279/−120 lines, 4 filesdep +directorydep +doctestdep +eitherdep ~basedep ~semigroupsPVP ok
version bump matches the API change (PVP)
Dependencies added: directory, doctest, either, filepath
Dependency ranges changed: base, semigroups
API changes (from Hackage documentation)
+ Data.Cond: CondEitherT :: (StateT a (EitherT (Maybe (Maybe (CondEitherT a m b))) m) (b, Maybe (Maybe (CondEitherT a m b)))) -> CondEitherT a m b
+ Data.Cond: CondT :: StateT a m (Result a m b) -> CondT a m b
+ Data.Cond: and_ :: Monad m => [CondT a m b] -> CondT a m ()
+ Data.Cond: apply :: Monad m => (a -> m (Maybe b)) -> CondT a m b
+ Data.Cond: applyCond :: a -> Cond a b -> ((Maybe b, Maybe (Cond a b)), a)
+ Data.Cond: applyCondT :: Monad m => a -> CondT a m b -> m ((Maybe b, Maybe (CondT a m b)), a)
+ Data.Cond: consider :: Monad m => (a -> m (Maybe (b, a))) -> CondT a m b
+ Data.Cond: fromCondT :: Monad m => CondT a m b -> CondEitherT a m b
+ Data.Cond: getCondT :: CondT a m b -> StateT a m (Result a m b)
+ Data.Cond: guardM :: Monad m => m Bool -> CondT a m ()
+ Data.Cond: guardM_ :: Monad m => (a -> m Bool) -> CondT a m ()
+ Data.Cond: guard_ :: Monad m => (a -> Bool) -> CondT a m ()
+ Data.Cond: if_ :: Monad m => CondT a m r -> CondT a m b -> CondT a m b -> CondT a m b
+ Data.Cond: ignore :: Monad m => CondT a m b
+ Data.Cond: instance (Monad m, Monoid b) => Monoid (CondT a m b)
+ Data.Cond: instance (Monad m, Semigroup b) => Semigroup (CondT a m b)
+ Data.Cond: instance MFunctor (CondT a)
+ Data.Cond: instance MFunctor (Result a)
+ Data.Cond: instance Monad m => Alternative (CondT a m)
+ Data.Cond: instance Monad m => Applicative (CondT a m)
+ Data.Cond: instance Monad m => Functor (CondT a m)
+ Data.Cond: instance Monad m => Functor (Result a m)
+ Data.Cond: instance Monad m => Monad (CondT a m)
+ Data.Cond: instance Monad m => MonadPlus (CondT a m)
+ Data.Cond: instance Monad m => MonadReader a (CondT a m)
+ Data.Cond: instance Monad m => MonadState a (CondT a m)
+ Data.Cond: instance MonadBase b m => MonadBase b (CondT a m)
+ Data.Cond: instance MonadBaseControl b m => MonadBaseControl b (CondT r m)
+ Data.Cond: instance MonadCatch m => MonadCatch (CondT a m)
+ Data.Cond: instance MonadIO m => MonadIO (CondT a m)
+ Data.Cond: instance MonadThrow m => MonadThrow (CondT a m)
+ Data.Cond: instance MonadTrans (CondT a)
+ Data.Cond: instance Monoid b => Monoid (Result a m b)
+ Data.Cond: instance Semigroup (Result a m b)
+ Data.Cond: instance Show (CondT a m b)
+ Data.Cond: instance Show b => Show (Result a m b)
+ Data.Cond: matches :: Monad m => CondT a m b -> CondT a m Bool
+ Data.Cond: newtype CondEitherT a m b
+ Data.Cond: newtype CondT a m b
+ Data.Cond: norecurse :: Monad m => CondT a m ()
+ Data.Cond: not_ :: Monad m => CondT a m b -> CondT a m ()
+ Data.Cond: or_ :: Monad m => [CondT a m b] -> CondT a m b
+ Data.Cond: prune :: Monad m => CondT a m b
+ Data.Cond: recurse :: Monad m => CondT a m b -> CondT a m b
+ Data.Cond: runCond :: Cond a b -> a -> Maybe b
+ Data.Cond: runCondT :: Monad m => CondT a m b -> a -> m (Maybe b)
+ Data.Cond: test :: Monad m => a -> CondT a m b -> m Bool
+ Data.Cond: toCondT :: Monad m => CondEitherT a m b -> CondT a m b
+ Data.Cond: type Cond a = CondT a Identity
+ Data.Cond: unless_ :: Monad m => CondT a m r -> CondT a m () -> CondT a m ()
+ Data.Cond: when_ :: Monad m => CondT a m r -> CondT a m () -> CondT a m ()
Files
- Data/Cond.hs +220/−105
- Data/Conduit/Find.hs +12/−11
- find-conduit.cabal +17/−4
- test/doctest.hs +30/−0
Data/Cond.hs view
@@ -7,11 +7,24 @@ module Data.Cond ( CondT(..), Cond- , runCondT, applyCondT, runCond, applyCond++ -- * Executing CondT+ , runCondT, runCond, applyCondT, applyCond++ -- * Promotions , guardM, guard_, guardM_, apply, consider++ -- * Boolean logic , matches, if_, when_, unless_, or_, and_, not_++ -- * Basic conditionals , ignore, norecurse, prune- , test, recurse++ -- * Helper functions+ , recurse, test++ -- * Isomorphism with a stateful EitherT+ , CondEitherT(..), fromCondT, toCondT ) where import Control.Applicative@@ -24,6 +37,7 @@ import Control.Monad.State.Class import Control.Monad.Trans import Control.Monad.Trans.Control+import Control.Monad.Trans.Either import Control.Monad.Trans.State (StateT(..), withStateT, evalStateT) import Data.Foldable import Data.Functor.Identity@@ -71,6 +85,7 @@ _ <> Keep b = Keep b Keep _ <> KeepAndRecurse b _ = Keep b _ <> KeepAndRecurse b m = KeepAndRecurse b m+ {-# INLINE (<>) #-} instance Monoid b => Monoid (Result a m b) where mempty = KeepAndRecurse mempty Nothing@@ -78,58 +93,80 @@ mappend = (<>) {-# INLINE mappend #-} +getResult :: Result a m b -> (Maybe b, Maybe (CondT a m b))+getResult Ignore = (Nothing, Nothing)+getResult (Keep b) = (Just b, Nothing)+getResult (RecurseOnly c) = (Nothing, c)+getResult (KeepAndRecurse b c) = (Just b, c)++setRecursion :: CondT a m b -> Result a m b -> Result a m b+setRecursion _ Ignore = Ignore+setRecursion _ (Keep b) = Keep b+setRecursion c (RecurseOnly _) = RecurseOnly (Just c)+setRecursion c (KeepAndRecurse b _) = KeepAndRecurse b (Just c)+ accept' :: b -> Result a m b accept' = flip KeepAndRecurse Nothing recurse' :: Result a m b recurse' = RecurseOnly Nothing -toResult :: Monad m => Maybe a -> forall r. Result r m a-toResult Nothing = recurse'-toResult (Just a) = accept' a+-- | Convert from a 'Maybe' value to its corresponding 'Result'.+--+-- >>> maybeToResult Nothing :: Result () Identity ()+-- RecurseOnly+-- >>> maybeToResult (Just ()) :: Result () Identity ()+-- KeepAndRecurse ()+maybeToResult :: Monad m => Maybe a -> Result r m a+maybeToResult Nothing = recurse'+maybeToResult (Just a) = accept' a -fromResult :: Monad m => forall r. Result r m a -> Maybe a-fromResult Ignore = Nothing-fromResult (Keep a) = Just a-fromResult (RecurseOnly _) = Nothing-fromResult (KeepAndRecurse a _) = Just a+maybeFromResult :: Monad m => Result r m a -> Maybe a+maybeFromResult Ignore = Nothing+maybeFromResult (Keep a) = Just a+maybeFromResult (RecurseOnly _) = Nothing+maybeFromResult (KeepAndRecurse a _) = Just a --- | 'CondT' is an enhanced form @StateT a (MaybeT m) b@, which uses the--- 'Result' type instead of 'Maybe' to additional express whether recursion--- should be performed on the current state. This is used to form--- predicates to guide recursive unfolds.+-- | 'CondT' is a kind of @StateT a (MaybeT m) b@, which uses a special+-- 'Result' type instead of 'Maybe' to express whether recursion should be+-- performed from the item under consideration. This is used to build+-- predicates that can guide recursive traversals. ----- Several different types may be promoted to 'CondT':+-- Several different types may be promoted to 'CondT': ----- [@Bool@] guard--- [@m Bool@] guardM--- [@a -> Bool@] guard_--- [@a -> m Bool@] guardM_--- [@a -> m (Maybe b)@] apply--- [@a -> m (Maybe (b, a))@] consider+-- [@Bool@] Using 'guard' ----- Here is a trivial example:+-- [@m Bool@] Using 'guardM' ----- @--- flip runCondT 42 $ do--- guard_ even--- liftIO $ putStrLn "42 must be even to reach here"+-- [@a -> Bool@] Using 'guard_' ----- guard_ odd <|> guard_ even--- guard_ even &&: guard_ (== 42)--- guard_ ((== 0) . (`mod` 6))+-- [@a -> m Bool@] Using 'guardM_'+--+-- [@a -> m (Maybe b)@] Using 'apply'+--+-- [@a -> m (Maybe (b, a))@] Using 'consider'+--+-- Here is a trivial example:+-- -- @+-- flip runCondT 42 $ do+-- guard_ even+-- liftIO $ putStrLn "42 must be even to reach here"+-- guard_ odd \<|\> guard_ even+-- guard_ (== 42)+-- @ ----- 'CondT' is typically invoked using 'runCondT', in which case it maps 'a'--- to 'Maybe b'. It can also be run with 'applyCondT', which does case--- analysis on the final 'Result' type, specifying how recursion should be--- performed from the given 'a' value. This is useful when applying--- Conduits to structural traversals, and was the motivation behind this--- type.+-- If 'CondT' is executed using 'runCondT', it return a @Maybe b@ if the+-- predicate matched. It can also be run with 'applyCondT', which does case+-- analysis on the 'Result', specifying how recursion should be performed from+-- the given 'a' value. newtype CondT a m b = CondT { getCondT :: StateT a m (Result a m b) } type Cond a = CondT a Identity +instance Show (CondT a m b) where+ show _ = "CondT"+ instance (Monad m, Semigroup b) => Semigroup (CondT a m b) where (<>) = liftM2 (<>) {-# INLINE (<>) #-}@@ -238,55 +275,49 @@ instance MFunctor (CondT a) where hoist nat (CondT m) = CondT $ hoist nat (liftM (hoist nat) m) {-# INLINE hoist #-}-+ runCondT :: Monad m => CondT a m b -> a -> m (Maybe b)-runCondT (CondT f) a = fromResult `liftM` evalStateT f a+runCondT (CondT f) a = maybeFromResult `liftM` evalStateT f a {-# INLINE runCondT #-} runCond :: Cond a b -> a -> Maybe b runCond = (runIdentity .) . runCondT {-# INLINE runCond #-} --- | Case analysis of applying a condition to an input value. Note that--- function provided should recurse, calling applyCondT again, if the given--- condition is Just, should it wish to. Not result value is accumulated by--- this function, meaning you should use 'WriterT' if you wish to do so--- (unlike the pure variant, 'applyCond', which must accumulate a value to--- have any meaning).+-- | Case analysis of applying a condition to an input value. The result is a+-- pair whose first part is a pair of Maybes specifying if the input matched+-- and if recursion is expected from this value, and whose second part is+-- the (possibly) mutated input value. applyCondT :: Monad m => a -> CondT a m b- -> (a -> Maybe b -> Maybe (CondT a m b) -> m ())- -> m ()-applyCondT a c k = do- (r, a') <- runStateT (getCondT c) a- case r of- Ignore -> k a' Nothing Nothing- Keep b -> k a' (Just b) Nothing- RecurseOnly c' -> k a' Nothing (Just (fromMaybe c c'))- KeepAndRecurse b c' -> k a' (Just b) (Just (fromMaybe c c'))+ -> m ((Maybe b, Maybe (CondT a m b)), a)+applyCondT a cond = do+ -- Apply a condition to the input value, determining the result and the+ -- mutated value.+ (r, a') <- runStateT (getCondT cond) a --- | Case analysis of applying a pure condition to an input value. Note that--- the user is responsible for recursively calling this function if the--- resulting condition is a Just value. Each step of the recursion must--- return a Monoid so that a final result may be collected.-applyCond :: Monoid c- => a- -> Cond a b- -> (a -> Maybe b -> Maybe (Cond a b) -> c)- -> c-applyCond a c k = case runIdentity (runStateT (getCondT c) a) of- (Ignore, a') -> k a' Nothing Nothing- (Keep b, a') -> k a' (Just b) Nothing- (RecurseOnly c', a') -> k a' Nothing (Just (fromMaybe c c'))- (KeepAndRecurse b c', a') -> k a' (Just b) (Just (fromMaybe c c'))+ -- Convert from the 'Result' to a pair of Maybes: one to specify if the+ -- predicate succeeded, and the other to specify if recursion should be+ -- performed. If there is no sub-recursion specified, return 'cond'.+ return (fmap (Just . fromMaybe cond) (getResult r), a')+{-# INLINE applyCondT #-} +-- | Case analysis of applying a pure condition to an input value. The result+-- is a pair whose first part is a pair of Maybes specifying if the input+-- matched and if recursion is expected from this value, and whose second+-- part is the (possibly) mutated input value.+applyCond :: a -> Cond a b -> ((Maybe b, Maybe (Cond a b)), a)+applyCond a cond = first (fmap (Just . fromMaybe cond) . getResult)+ (runIdentity (runStateT (getCondT cond) a))+{-# INLINE applyCond #-}+ guardM :: Monad m => m Bool -> CondT a m () guardM m = lift m >>= guard {-# INLINE guardM #-} guard_ :: Monad m => (a -> Bool) -> CondT a m ()-guard_ f = ask >>= guard . f+guard_ f = asks f >>= guard {-# INLINE guard_ #-} guardM_ :: Monad m => (a -> m Bool) -> CondT a m ()@@ -294,82 +325,129 @@ {-# INLINE guardM_ #-} apply :: Monad m => (a -> m (Maybe b)) -> CondT a m b-apply f = CondT $ get >>= liftM toResult . lift . f+apply f = CondT $ get >>= liftM maybeToResult . lift . f {-# INLINE apply #-} consider :: Monad m => (a -> m (Maybe (b, a))) -> CondT a m b consider f = CondT $ do- a <- get- mres <- lift $ f a+ mres <- lift . f =<< get case mres of Nothing -> return Ignore Just (b, a') -> put a' >> return (accept' b) {-# INLINE consider #-}-++-- | Return True or False depending on whether the given condition matches or+-- not. This differs from simply stating the condition in that it itself+-- always succeeds.+--+-- >>> flip runCond "foo.hs" $ matches (guard =<< asks (== "foo.hs"))+-- Just True+-- >>> flip runCond "foo.hs" $ matches (guard =<< asks (== "foo.hi"))+-- Just False matches :: Monad m => CondT a m b -> CondT a m Bool matches = fmap isJust . optional {-# INLINE matches #-} -if_ :: Monad m => CondT a m b -> CondT a m c -> CondT a m c -> CondT a m c-if_ c x y = CondT $ do- r <- getCondT c- getCondT $ case r of- Ignore -> y- Keep _ -> x- RecurseOnly _ -> y- KeepAndRecurse _ _ -> x+-- | A variant of ifM which branches on whether the condition succeeds or not.+-- Note that @if_ x@ is equivalent to @ifM (matches x)@, and is provided+-- solely for convenience.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad = guard_ (== "foo.hi") :: Cond String ()+-- >>> flip runCond "foo.hs" $ if_ good (return "Success") (return "Failure")+-- Just "Success"+-- >>> flip runCond "foo.hs" $ if_ bad (return "Success") (return "Failure")+-- Just "Failure"+if_ :: Monad m => CondT a m r -> CondT a m b -> CondT a m b -> CondT a m b+if_ c x y =+ CondT $ getCondT . maybe y (const x) . maybeFromResult =<< getCondT c {-# INLINE if_ #-} -when_ :: Monad m => CondT a m b -> CondT a m () -> CondT a m ()-when_ c x = if_ c x (return ())+-- | 'when_' is just like 'when', except that it executes the body if the+-- condition passes, rather than based on a Bool value.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad = guard_ (== "foo.hi") :: Cond String ()+-- >>> flip runCond "foo.hs" $ when_ good ignore+-- Nothing+-- >>> flip runCond "foo.hs" $ when_ bad ignore+-- Just ()+when_ :: Monad m => CondT a m r -> CondT a m () -> CondT a m ()+when_ c x = if_ c (void x) (return ()) {-# INLINE when_ #-} -unless_ :: Monad m => CondT a m b -> CondT a m () -> CondT a m ()-unless_ c = if_ c (return ())+-- | 'when_' is just like 'when', except that it executes the body if the+-- condition fails, rather than based on a Bool value.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad = guard_ (== "foo.hi") :: Cond String ()+-- >>> flip runCond "foo.hs" $ unless_ bad ignore+-- Nothing+-- >>> flip runCond "foo.hs" $ unless_ good ignore+-- Just ()+unless_ :: Monad m => CondT a m r -> CondT a m () -> CondT a m ()+unless_ c = if_ c (return ()) . void {-# INLINE unless_ #-} -- | Check whether at least one of the given conditions is true. This is a -- synonym for 'Data.Foldable.asum'.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad = guard_ (== "foo.hi") :: Cond String ()+-- >>> flip runCond "foo.hs" $ or_ [bad, good]+-- Just ()+-- >>> flip runCond "foo.hs" $ or_ [bad]+-- Nothing or_ :: Monad m => [CondT a m b] -> CondT a m b or_ = asum {-# INLINE or_ #-} -- | Check that all of the given conditions are true. This is a synonym for -- 'Data.Foldable.sequence_'.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad = guard_ (== "foo.hi") :: Cond String ()+-- >>> flip runCond "foo.hs" $ and_ [bad, good]+-- Nothing+-- >>> flip runCond "foo.hs" $ and_ [good]+-- Just () and_ :: Monad m => [CondT a m b] -> CondT a m () and_ = sequence_ {-# INLINE and_ #-} -- | 'not_' inverts the meaning of the given predicate.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad = guard_ (== "foo.hi") :: Cond String ()+-- >>> flip runCond "foo.hs" $ not_ bad >> return "Success"+-- Just "Success"+-- >>> flip runCond "foo.hs" $ not_ good >> return "Shouldn't reach here"+-- Nothing not_ :: Monad m => CondT a m b -> CondT a m () not_ c = when_ c ignore {-# INLINE not_ #-}-+ -- | 'ignore' ignores the current entry, but allows recursion into its -- descendents. This is the same as 'mzero'. ignore :: Monad m => CondT a m b ignore = mzero {-# INLINE ignore #-} --- | 'prune' is a synonym for both ignoring an entry and its descendents. It--- is the same as 'ignore >> norecurse'.-prune :: Monad m => CondT a m ()-prune = CondT $ return Ignore-{-# INLINE prune #-}- -- | 'norecurse' prevents recursion into the current entry's descendents, but -- does not ignore the entry itself. norecurse :: Monad m => CondT a m () norecurse = CondT $ return $ Keep () {-# INLINE norecurse #-} -test :: Monad m => CondT a m b -> a -> m Bool-test = (liftM isJust .) . runCondT-{-# INLINE test #-}-+-- | 'prune' is a synonym for both ignoring an entry and its descendents. It+-- is the same as @ignore >> norecurse@.+prune :: Monad m => CondT a m b+prune = CondT $ return Ignore+{-# INLINE prune #-}+ -- | 'recurse' changes the recursion predicate for any child elements. For -- example, the following file-finding predicate looks for all @*.hs@ files,--- but under any @.git@ directory, only looks for a file named @config@:+-- but under any @.git@ directory looks only for a file named @config@: -- -- @ -- if_ (name_ \".git\" \>\> directory)@@ -377,14 +455,51 @@ -- (glob \"*.hs\") -- @ ----- If this code had used @recurse (glob \"*.hs\"))@ instead in the else case,--- it would have meant that @.git@ is only looked for at the top-level of the--- search (i.e., the top-most element).+-- NOTE: If this code had used @recurse (glob \"*.hs\"))@ instead in the else+-- case, it would have meant that @.git@ is only looked for at the top-level+-- of the search (i.e., the top-most element). recurse :: Monad m => CondT a m b -> CondT a m b-recurse c = CondT $ do- r <- getCondT c- return $ case r of- Ignore -> Ignore- Keep b -> Keep b- RecurseOnly _ -> RecurseOnly (Just c)- KeepAndRecurse b _ -> KeepAndRecurse b (Just c)+recurse c = CondT $ setRecursion c `liftM` getCondT c+{-# INLINE recurse #-}++-- | A specialized variant of 'runCondT' that simply returns True or False.+--+-- >>> let good = guard_ (== "foo.hs") :: Cond String ()+-- >>> let bad = guard_ (== "foo.hi") :: Cond String ()+-- >>> runIdentity $ test "foo.hs" $ not_ bad >> return "Success"+-- True+-- >>> runIdentity $ test "foo.hs" $ not_ good >> return "Shouldn't reach here"+-- False+test :: Monad m => a -> CondT a m b -> m Bool+test = (liftM isJust .) . flip runCondT+{-# INLINE test #-}++-- | This type is for documentation only, and shows the isomorphism between+-- 'CondT' and 'CondEitherT'. The reason for using 'Result' is that it+-- makes meaning of the constructors more explicit.+newtype CondEitherT a m b = CondEitherT+ (StateT a (EitherT (Maybe (Maybe (CondEitherT a m b))) m)+ (b, Maybe (Maybe (CondEitherT a m b))))++-- | Witness one half of the isomorphism from 'CondT' to 'CondEitherT'.+fromCondT :: Monad m => CondT a m b -> CondEitherT a m b+fromCondT (CondT f) = CondEitherT $ do+ s <- get+ (r, s') <- lift $ lift $ runStateT f s+ case r of+ Ignore -> lift $ left Nothing+ Keep a -> put s' >> return (a, Nothing)+ RecurseOnly m -> lift $ left (Just (fmap fromCondT m))+ KeepAndRecurse a m -> put s' >> return (a, Just (fmap fromCondT m))++-- | Witness the other half of the isomorphism from 'CondEitherT' to 'CondT'.+toCondT :: Monad m => CondEitherT a m b -> CondT a m b+toCondT (CondEitherT f) = CondT $ do+ s <- get+ eres <- lift $ runEitherT $ runStateT f s+ case eres of+ Left Nothing -> return Ignore+ Right ((a, Nothing), s') -> put s' >> return (Keep a)+ Left (Just m) -> return $ RecurseOnly (fmap toCondT m)+ Right ((a, Just m), s') ->+ put s' >> return (KeepAndRecurse a (fmap toCondT m))
Data/Conduit/Find.hs view
@@ -480,26 +480,26 @@ where wrap = mapInput (const ()) (const Nothing) - go x pr = applyCondT x pr $ \e mb mcond -> do- let opts' = entryFindOptions e- this = unless (findIgnoreResults opts') $- yieldEntry e mb- next = walkChildren e mcond+ go x pr = do+ ((mres, mcond), entry) <- applyCondT x pr+ let opts' = entryFindOptions entry+ this = unless (findIgnoreResults opts') $ yieldEntry entry mres+ next = walkChildren entry mcond if findContentsFirst opts' then next >> this else this >> next - yieldEntry e mb =+ yieldEntry entry mres = -- If the item matched, also yield the predicate's result value.- forM_ mb $ yield . (e,)+ forM_ mres $ yield . (entry,) - walkChildren e@(FileEntry path depth opts' _) mcond =+ walkChildren entry@(FileEntry path depth opts' _) mcond = -- If the conditional matched, we are requested to recurse if this -- is a directory forM_ mcond $ \cond -> do -- If no status has been determined, we must do so now in order -- to know whether to actually recurse or not.- descend <- fmap (isDirectory . fst) <$> getStat Nothing e+ descend <- fmap (isDirectory . fst) <$> getStat Nothing entry when (descend == Just True) $ (sourceDirectory path =$) $ awaitForever $ \fp -> wrap $ go (newFileEntry fp (succ depth) opts') cond@@ -534,10 +534,11 @@ -- 'findFiles'. test :: MonadIO m => CondT FileEntry m () -> FilePath -> m Bool test matcher path =- Cond.test matcher (newFileEntry path 0 defaultFindOptions)+ Cond.test (newFileEntry path 0 defaultFindOptions) matcher -- | Test a file path using the same type of predicate that is accepted by -- 'findFiles', but do not follow symlinks. ltest :: MonadIO m => CondT FileEntry m () -> FilePath -> m Bool-ltest matcher path = Cond.test matcher+ltest matcher path = Cond.test (newFileEntry path 0 defaultFindOptions { findFollowSymlinks = False })+ matcher
find-conduit.cabal view
@@ -1,5 +1,5 @@ Name: find-conduit-Version: 0.4.0+Version: 0.4.1 Synopsis: A file-finding conduit that allows user control over traversals. License-file: LICENSE License: MIT@@ -35,11 +35,10 @@ , transformers , transformers-base , mmorph+ , either , monad-control exposed-modules:- Data.Conduit.Find- other-modules:- Data.Cond+ Data.Cond, Data.Conduit.Find test-suite test hs-source-dirs: test@@ -59,6 +58,7 @@ , regex-posix , mtl , time+ , either , semigroups , exceptions , transformers@@ -66,3 +66,16 @@ , monad-control , mmorph , hspec >= 1.4++Test-suite doctests+ Default-language: Haskell98+ Type: exitcode-stdio-1.0+ Main-is: doctest.hs+ Hs-source-dirs: test+ Build-depends: + base+ , directory >= 1.0+ , doctest >= 0.8+ , filepath >= 1.3+ , semigroups >= 0.4+
+ test/doctest.hs view
@@ -0,0 +1,30 @@+module Main where++import Test.DocTest+import System.Directory+import System.FilePath+import Control.Applicative+import Control.Monad+import Data.List++main :: IO ()+main = getSources >>= \sources -> doctest $+ "-iData"+ : "-idist/build/autogen"+ : "-package=semigroups-0.13.0.1"+ : "-optP-include"+ : "-optPdist/build/autogen/cabal_macros.h"+ : sources++getSources :: IO [FilePath]+getSources =+ filter (\n -> ".hs" `isSuffixOf` n) <$> go "./Data"+ where+ go dir = do+ (dirs, files) <- getFilesAndDirectories dir+ (files ++) . concat <$> mapM go dirs++getFilesAndDirectories :: FilePath -> IO ([FilePath], [FilePath])+getFilesAndDirectories dir = do+ c <- map (dir </>) . filter (`notElem` ["..", "."]) <$> getDirectoryContents dir+ (,) <$> filterM doesDirectoryExist c <*> filterM doesFileExist c