packages feed

repl-toolkit 0.2.0.0 → 0.3.0.0

raw patch · 4 files changed

+56/−46 lines, 4 filesdep +exceptionsdep +transformersPVP ok

version bump matches the API change (PVP)

Dependencies added: exceptions, transformers

API changes (from Hackage documentation)

+ System.REPL.Command: instance Exception ParamNumError
- System.REPL: ask :: (MonadIO m, MonadError SomeException m, Functor m) => Asker m a -> Maybe Text -> m a
+ System.REPL: ask :: (MonadIO m, MonadCatch m, Functor m) => Asker m a -> Maybe Text -> m a
- System.REPL: ask' :: (MonadIO m, MonadError SomeException m, Functor m) => Asker m a -> m a
+ System.REPL: ask' :: (MonadIO m, MonadCatch m, Functor m) => Asker m a -> m a
- System.REPL: askEither :: (MonadIO m, Functor m) => Asker m a -> Maybe Text -> m (Either AskFailure a)
+ System.REPL: askEither :: (MonadIO m, MonadCatch m, Functor m) => Asker m a -> Maybe Text -> m (Either AskFailure a)
- System.REPL: promptAbort :: (MonadIO m, ListLikeIO full item, ListLikeIO full' Char) => Char -> full -> m (Maybe full')
+ System.REPL: promptAbort :: (MonadIO m, ListLikeIO full item, ListLikeIO full' Char, MonadCatch m) => Char -> full -> m full'
- System.REPL: untilValid :: (MonadIO m, MonadError SomeException m, Functor m, Read a) => m a -> m a
+ System.REPL: untilValid :: (MonadIO m, MonadCatch m, Functor m, Read a) => m a -> m a
- System.REPL.Command: commandDispatch :: (MonadIO m, MonadError SomeException m, Functor m) => Text -> [Command m z] -> m z
+ System.REPL.Command: commandDispatch :: (MonadIO m, MonadCatch m, Functor m) => Text -> [Command m z] -> m z
- System.REPL.Command: makeCommand :: (MonadIO m, MonadError SomeException m, Functor m) => Text -> (Text -> Bool) -> Text -> (Text -> m a) -> Command m a
+ System.REPL.Command: makeCommand :: (MonadIO m, MonadCatch m, Functor m) => Text -> (Text -> Bool) -> Text -> (Text -> m a) -> Command m a
- System.REPL.Command: makeCommand1 :: (MonadIO m, MonadError SomeException m, Functor m, Read a) => Text -> (Text -> Bool) -> Text -> Asker m a -> (Text -> a -> m z) -> Command m z
+ System.REPL.Command: makeCommand1 :: (MonadIO m, MonadCatch m, Functor m, Read a) => Text -> (Text -> Bool) -> Text -> Asker m a -> (Text -> a -> m z) -> Command m z
- System.REPL.Command: makeCommand2 :: (MonadIO m, MonadError SomeException m, Functor m, Read a, Read b) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> (Text -> a -> b -> m z) -> Command m z
+ System.REPL.Command: makeCommand2 :: (MonadIO m, MonadCatch m, Functor m, Read a, Read b) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> (Text -> a -> b -> m z) -> Command m z
- System.REPL.Command: makeCommand3 :: (MonadIO m, MonadError SomeException m, Functor m, Read a, Read b, Read c) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> (Text -> a -> b -> c -> m z) -> Command m z
+ System.REPL.Command: makeCommand3 :: (MonadIO m, MonadCatch m, Functor m, Read a, Read b, Read c) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> (Text -> a -> b -> c -> m z) -> Command m z
- System.REPL.Command: makeCommand4 :: (MonadIO m, MonadError SomeException m, Functor m, Read a, Read b, Read c, Read d) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> (Text -> a -> b -> c -> d -> m z) -> Command m z
+ System.REPL.Command: makeCommand4 :: (MonadIO m, MonadCatch m, Functor m, Read a, Read b, Read c, Read d) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> (Text -> a -> b -> c -> d -> m z) -> Command m z
- System.REPL.Command: makeCommand5 :: (MonadIO m, MonadError SomeException m, Functor m, Read a, Read b, Read c, Read d, Read e) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> (Text -> a -> b -> c -> d -> e -> m z) -> Command m z
+ System.REPL.Command: makeCommand5 :: (MonadIO m, MonadCatch m, Functor m, Read a, Read b, Read c, Read d, Read e) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> (Text -> a -> b -> c -> d -> e -> m z) -> Command m z
- System.REPL.Command: makeCommand6 :: (MonadIO m, MonadError SomeException m, Functor m, Read a, Read b, Read c, Read d, Read e, Read f) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> Asker m f -> (Text -> a -> b -> c -> d -> e -> f -> m z) -> Command m z
+ System.REPL.Command: makeCommand6 :: (MonadIO m, MonadCatch m, Functor m, Read a, Read b, Read c, Read d, Read e, Read f) => Text -> (Text -> Bool) -> Text -> Asker m a -> Asker m b -> Asker m c -> Asker m d -> Asker m e -> Asker m f -> (Text -> a -> b -> c -> d -> e -> f -> m z) -> Command m z
- System.REPL.Command: makeCommandN :: (MonadIO m, MonadError SomeException m, Functor m, Read a) => Text -> (Text -> Bool) -> Text -> [Asker m a] -> [Asker m a] -> (Text -> [a] -> m z) -> Command m z
+ System.REPL.Command: makeCommandN :: (MonadIO m, MonadCatch m, Functor m, Read a) => Text -> (Text -> Bool) -> Text -> [Asker m a] -> [Asker m a] -> (Text -> [a] -> m z) -> Command m z

Files

System/REPL.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE LambdaCase #-}
 
 -- |Functions to expedite the building of REPLs.
@@ -66,8 +67,8 @@ import Prelude hiding (putStrLn, putStr, getLine, reverse)
 
 import Control.Arrow (right, (|||))
-import Control.Exception
-import Control.Monad.Except
+import Control.Monad.Catch
+import Control.Monad.IO.Class (MonadIO(liftIO))
 import Data.Char (isSpace)
 import Data.Functor.Monadic
 import Data.ListLike(ListLike(empty, cons, reverse))
@@ -103,19 +104,23 @@ --  (commonly @'\ESC'@). This function temporarily tries to set the buffering mode
 --  to NoBuffering via 'System.IO.hSetBuffering', which may not be supported.
 --  See the documentation of 'System.IO.hSetBuffering' for details.
-promptAbort :: (MonadIO m, ListLikeIO full item, ListLikeIO full' Char)
-            => Char -> full -> m (Maybe full')
-promptAbort abortChar s = liftIO (do putStr s
-                                     IO.hFlush IO.stdout
-                                     bufMode <- IO.hGetBuffering IO.stdin
-                                     IO.hSetBuffering IO.stdin IO.NoBuffering
-                                     input <- getUntil empty
-                                     IO.hSetBuffering IO.stdin bufMode
-                                     return $ input >$> reverse)
+promptAbort :: (MonadIO m, ListLikeIO full item, ListLikeIO full' Char,
+                MonadCatch m)
+            => Char -> full -> m full'
+promptAbort abortChar s = do
+   liftIO $ putStr s
+   liftIO $ IO.hFlush IO.stdout
+   bufMode <- liftIO $ IO.hGetBuffering IO.stdin
+   liftIO $ IO.hSetBuffering IO.stdin IO.NoBuffering
+   input <- getUntil empty
+            `catch` (\(e :: AskFailure) ->
+                        liftIO (IO.hSetBuffering IO.stdin bufMode) >> throwM e)
+   liftIO $ IO.hSetBuffering IO.stdin bufMode
+   return $ reverse input
    where
-      getUntil acc = do c <- getChar
-                        if c == abortChar then return Nothing
-                        else if c == '\n' then return $ Just acc
+      getUntil acc = do c <- liftIO $ getChar
+                        if c == abortChar then throwM AbortFailure
+                        else if c == '\n' then return acc
                         else                   getUntil (cons c acc)
 
 -- Askers
@@ -282,34 +287,33 @@ -- Running askers
 --------------------------------------------------------------------------------
 
--- |Executes an Asker. If the process fails, an exception is thrown
---  The canonical instance of @MonadError SomeException@ is the 'ExceptT' monad.
-ask :: (MonadIO m, MonadError SomeException m, Functor m)
+-- |Executes an Asker. If the process fails, an exception is thrown.
+ask :: (MonadIO m, MonadCatch m, Functor m)
     => Asker m a
     -> Maybe Text
     -> m a
-ask a v = askEither a v >>= either (throwError . SomeException) return
+ask a v = askEither a v >>= either throwM return
 
 -- |See 'ask'. Always reads the input from stdin.
 --
 -- @
 -- ask' a = ask a Nothing
 -- @
-ask' :: (MonadIO m, MonadError SomeException m, Functor m)
+ask' :: (MonadIO m, MonadCatch m, Functor m)
      => Asker m a
      -> m a
 ask' a = ask a Nothing
 
 -- |Executes an 'Asker'. If the Text argument is Nothing, the user is asked
 --  to enter a line on stdin. If it is @Just x@, @x@ is taken to be input.
-askEither :: (MonadIO m, Functor m)
+askEither :: (MonadIO m, MonadCatch m, Functor m)
           => Asker m a
           -> Maybe Text
           -> m (Either AskFailure a)
 askEither a = maybe getInput check
    where
-      getInput = promptAbort '\ESC' (askerPrompt a)
-                 >>= maybe (return $ Left AbortFailure) check
+      getInput = (promptAbort '\ESC' (askerPrompt a) >>= check)
+                 `catch` (return . Left)
 
       check inp = case askerParser a inp of
          Left err -> return $ Left $ TypeFailure err
@@ -318,7 +322,10 @@ 
 -- |Repeatedly executes an ask action until the user enters a valid value.
 --  Error messages are printed each time.
-untilValid :: (MonadIO m, MonadError SomeException m, Functor m, Read a)
+untilValid :: forall m a.(MonadIO m, MonadCatch m, Functor m, Read a)
            => m a
            -> m a
-untilValid m = m `catchError` (\l -> liftIO (putStrLn (show l)) >> untilValid m)
+untilValid m = m `catch` handler
+   where
+      handler :: AskFailure -> m a
+      handler l = liftIO (putStrLn $ show l) >> untilValid m
System/REPL/Command.hs view
@@ -54,9 +54,9 @@ import qualified Prelude as P
 
 import Control.Arrow (left)
-import Control.Exception
 import Control.Monad
-import Control.Monad.Except
+import Control.Monad.Catch
+import Control.Monad.IO.Class (MonadIO(liftIO))
 import Control.Monad.Loops (unfoldrM)
 import Data.Char (isSpace)
 import Data.Functor.Monadic
@@ -100,6 +100,8 @@ data ParamNumError = NoParams | ExactParams | TooManyParams
    deriving (Enum, Show, Eq, Read, Typeable, Ord)
 
+instance Exception ParamNumError
+
 -- |Prints information (the command name, description and, if given,
 --  the number of parameters) about a command to the console.
 commandInfo :: MonadIO m => Command m a -> m ()
@@ -172,10 +174,8 @@                 c ++ " takes at most " ++ T.pack (show (fromPeano maxNum :: Integer)) ++ " parameters."]
 
 -- |Checks the number of parameters before executing a monadic function.
---  For compatibility (with the IO monad, mainly), the nominal type
---  of the thrown exception is 'SomeException', but only AskFailures will
---  actually be thrown in this function (other IO exceptions may occur).
-checkParams :: (MonadIO m, MonadError SomeException m, Functor m)
+--  Only AskFailures (and IOExceptions) will be thrown in this function.
+checkParams :: (MonadIO m, MonadThrow m, Functor m)
             => Text -- ^The command name.
             -> Text -- ^The raw input (including the command name).
             -> Int -- ^The minimal number of parameters, excluding the command's name.
@@ -186,11 +186,11 @@                    --  passed, this will be a 'ParamNumFailure'.
 checkParams n inp minNum maxNum m =
    case readArgs inp of
-      Left l  -> throwError (SomeException $ ParamFailure l)
+      Left l  -> throwM (ParamFailure l)
       Right r ->
          if natLength r > maxNum + 1 then
-            throwError $ SomeException $ ParamFailure
-                       $ paramErr n r minNum maxNum (errKind $ natLength r)
+            throwM $ ParamFailure
+                   $ paramErr n r minNum maxNum (errKind $ natLength r)
          else m r
    where
       errKind len = if minNum == 0 && 0 == maxNum then NoParams
@@ -210,7 +210,7 @@                 else x
 
 -- |Creates a command without parameters.
-makeCommand :: (MonadIO m, MonadError SomeException m,
+makeCommand :: (MonadIO m, MonadCatch m,
                 Functor m)
             => Text -- ^Command name.
             -> (Text -> Bool) -- ^Command test.
@@ -224,7 +224,7 @@                  f li
 
 -- |Creates a command with one parameter.
-makeCommand1 :: (MonadIO m, MonadError SomeException m, Functor m, Read a)
+makeCommand1 :: (MonadIO m, MonadCatch m, Functor m, Read a)
              => Text -- ^Command name.
              -> (Text -> Bool) -- ^Command test.
              -> Text -- ^Command description
@@ -239,7 +239,7 @@                  f li x1
 
 -- |Creates a command with two parameters.
-makeCommand2 :: (MonadIO m, MonadError SomeException m, Functor m, Read a,
+makeCommand2 :: (MonadIO m, MonadCatch m, Functor m, Read a,
                 Read b)
              => Text -- ^Command name.
              -> (Text -> Bool) -- ^Command test.
@@ -257,7 +257,7 @@                  f li x1 x2
 
 -- |Creates a command with three parameters.
-makeCommand3 :: (MonadIO m, MonadError SomeException m, Functor m, Read a,
+makeCommand3 :: (MonadIO m, MonadCatch m, Functor m, Read a,
                  Read b, Read c)
              => Text -- ^Command name.
              -> (Text -> Bool) -- ^Command test.
@@ -277,7 +277,7 @@                  f li x1 x2 x3
 
 -- |Creates a command with four parameters.
-makeCommand4 :: (MonadIO m, MonadError SomeException m, Functor m, Read a,
+makeCommand4 :: (MonadIO m, MonadCatch m, Functor m, Read a,
                  Read b, Read c, Read d)
              => Text -- ^Command name.
              -> (Text -> Bool) -- ^Command test.
@@ -299,7 +299,7 @@                  f li x1 x2 x3 x4
 
 -- |Creates a command with five parameters.
-makeCommand5 :: (MonadIO m, MonadError SomeException m, Functor m, Read a,
+makeCommand5 :: (MonadIO m, MonadCatch m, Functor m, Read a,
                  Read b, Read c, Read d, Read e)
              => Text -- ^Command name.
              -> (Text -> Bool) -- ^Command test.
@@ -323,7 +323,7 @@                  f li x1 x2 x3 x4 x5
 
 -- |Creates a command with four parameters.
-makeCommand6 :: (MonadIO m, MonadError SomeException m, Functor m, Read a,
+makeCommand6 :: (MonadIO m, MonadCatch m, Functor m, Read a,
                  Read b, Read c, Read d, Read e, Read f)
              => Text -- ^Command name.
              -> (Text -> Bool) -- ^Command test.
@@ -355,7 +355,7 @@ --  If the number of passed parameters exceeds
 --  @length necc + length opt@, or if any 'Asker' fails,
 --  the command returns an 'AskFailure'.
-makeCommandN :: (MonadIO m, MonadError SomeException m, Functor m, Read a)
+makeCommandN :: (MonadIO m, MonadCatch m, Functor m, Read a)
              => Text -- ^Command name.
              -> (Text -> Bool) -- ^Command test.
              -> Text -- ^Command description
@@ -391,15 +391,15 @@ --  trying the out in sequence. The first command whose 'commandTest'
 --  returns True is executed. If none of the commands match,
 --  @NothingFoundFailure@ is thrown.
-commandDispatch :: (MonadIO m, MonadError SomeException m, Functor m)
+commandDispatch :: (MonadIO m, MonadCatch m, Functor m)
                 => Text -- ^The user's input.
                 -> [Command m z] -- ^The command library.
                 -> m z
 commandDispatch input cs =
    case readArgs input of
-      Left l -> throwError (SomeException $ ParamFailure l)
+      Left l -> throwM (ParamFailure l)
       Right input' -> if noMatch input'
-                      then throwError (SomeException NothingFoundFailure)
+                      then throwM NothingFoundFailure
                       else do runCommand (fromJust $ first input') input
    where
       noMatch = isNothing . first
+ changelog.txt view
@@ -0,0 +1,1 @@+0.3 Ditched MonadError in favour of MonadThrow. This should make the functions much easier to use.
repl-toolkit.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                repl-toolkit
-version:             0.2.0.0
+version:             0.3.0.0
 synopsis:            Toolkit for quickly whipping up command-line interfaces.
 description:         A simple toolkit for quickly whipping up REPLs, input validation and sets of commands included.
 homepage:            https://github.com/ombocomp/repl-toolkit
@@ -13,6 +13,7 @@ category:            System, REPL
 build-type:          Simple
 cabal-version:       >=1.10
+extra-source-files:  changelog.txt
 
 source-repository head
   type: git
@@ -21,5 +22,6 @@ library
   exposed-modules:     System.REPL, System.REPL.State, System.REPL.Command
   other-extensions:    OverloadedStrings, DeriveDataTypeable, FlexibleContexts, LambdaCase
-  build-depends:       base >=4.7 && <5, functor-monadic >=0.1, text >=1.1, ListLike >=4.1, mtl >=2.2, parsec >=3.1, numericpeano >= 0.1, listsafe >= 0.1, monad-loops >= 0.3
+  build-depends:       base >=4.7 && <5, functor-monadic >=0.1, text >=1.1, ListLike >=4.1, exceptions >=0.4, parsec >=3.1, numericpeano >= 0.1, listsafe >= 0.1, monad-loops >= 0.3, mtl >= 2.2, transformers >= 0.3
   default-language:    Haskell2010
+