optparse-applicative 0.10.0 → 0.11.0
raw patch · 10 files changed
+103/−65 lines, 10 filesdep ~base
Dependency ranges changed: base
Files
- CHANGELOG.md +15/−2
- Options/Applicative/BashCompletion.hs +1/−3
- Options/Applicative/Builder.hs +13/−13
- Options/Applicative/Common.hs +6/−10
- Options/Applicative/Help/Chunk.hs +4/−0
- Options/Applicative/Help/Core.hs +2/−2
- Options/Applicative/Internal.hs +13/−5
- Options/Applicative/Types.hs +33/−26
- README.md +15/−3
- optparse-applicative.cabal +1/−1
CHANGELOG.md view
@@ -1,3 +1,16 @@+## Version 0.11.0 (4 Oct 2014)++- Added Alternative instances for `Chunk` and `ReadM`.++- The `ReadM` monad is now a `ReaderT` for the argument being parsed. User+ defined readers do not need to handle their argument explicitly, but can+ always access it using `readerAsk`.++- Argument builders now take a `ReadM` parameter, just like options.++- Fixed bugs+ * \#106 - argument should perhaps use `ReadM`+ ## Version 0.10.0 (1 Sep 2014) - Parser execution and help text generation are now more modular, and allow for@@ -168,8 +181,8 @@ foo --out - will match an option called `--output`, as long as its the only one starting- with the string `out`.+ will match an option called `--output`, as long as its the only one starting+ with the string `out`. - Added `briefDesc` modifier.
Options/Applicative/BashCompletion.hs view
@@ -71,9 +71,7 @@ w:_ -> isPrefixOf w _ -> const True - compl = do- setParser Nothing (infoParser pinfo)- runParserInfo pinfo (drop 1 ws')+ compl = runParserInfo pinfo (drop 1 ws') bashCompletionScript :: String -> String -> IO [String] bashCompletionScript prog progn = return
Options/Applicative/Builder.hs view
@@ -111,18 +111,18 @@ -- readers -- -- | 'Option' reader based on the 'Read' type class.-auto :: Monad m => Read a => String -> m a-auto arg = case reads arg of+auto :: Read a => ReadM a+auto = eitherReader $ \arg -> case reads arg of [(r, "")] -> return r- _ -> fail $ "cannot parse value `" ++ arg ++ "'"+ _ -> Left $ "cannot parse value `" ++ arg ++ "'" -- | String 'Option' reader.-str :: Monad m => String -> m String-str = return+str :: ReadM String+str = readerAsk -- | Null 'Option' reader. All arguments will fail validation.-disabled :: Monad m => String -> m a-disabled = const . fail $ "disabled option"+disabled :: ReadM a+disabled = readerError "disabled option" -- modifiers -- @@ -156,8 +156,8 @@ helpDoc doc = optionMod $ \p -> p { propHelp = Chunk doc } -- | Convert a function in the 'Either' monad to a reader.-eitherReader :: (String -> Either String a) -> String -> ReadM a-eitherReader f = either readerError return . f+eitherReader :: (String -> Either String a) -> ReadM a+eitherReader f = readerAsk >>= either readerError return . f -- | Specify the error to display when no argument is provided to this option. noArgError :: ParseError -> Mod OptionFields a@@ -209,7 +209,7 @@ rdr = uncurry CmdReader (mkCommand m) -- | Builder for an argument parser.-argument :: (String -> Maybe a) -> Mod ArgumentFields a -> Parser a+argument :: ReadM a -> Mod ArgumentFields a -> Parser a argument p (Mod f d g) = mkParser d g (ArgReader rdr) where ArgumentFields compl = f (ArgumentFields mempty)@@ -260,7 +260,7 @@ -- the given parse error. If you simply want to output a message, use -- 'infoOption' instead. abortOption :: ParseError -> Mod OptionFields (a -> a) -> Parser (a -> a)-abortOption err m = option (const (ReadM (Left err))) . (`mappend` m) $ mconcat+abortOption err m = option (readerAbort err) . (`mappend` m) $ mconcat [ noArgError err , value id , metavar "" ]@@ -275,11 +275,11 @@ -- | Same as 'option'. {-# DEPRECATED nullOption "Use 'option' instead" #-}-nullOption :: (String -> ReadM a) -> Mod OptionFields a -> Parser a+nullOption :: ReadM a -> Mod OptionFields a -> Parser a nullOption = option -- | Builder for an option using the 'auto' reader.-option :: (String -> ReadM a) -> Mod OptionFields a -> Parser a+option :: ReadM a -> Mod OptionFields a -> Parser a option r m = mkParser d g rdr where Mod f d g = metavar "ARG" `mappend` m
Options/Applicative/Common.hs view
@@ -51,7 +51,7 @@ ) where import Control.Applicative (pure, (<*>), (<$>), (<|>), (<$))-import Control.Monad (guard, mzero, msum, when, liftM, MonadPlus)+import Control.Monad (guard, mzero, msum, when, liftM) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State (StateT(..), get, put, runStateT) import Data.List (isPrefixOf)@@ -91,9 +91,9 @@ argMatches :: MonadP m => OptReader a -> String -> Maybe (StateT Args m a) argMatches opt arg = case opt of- ArgReader rdr -> do- result <- crReader rdr arg- Just $ return result+ ArgReader rdr -> Just $ do+ result <- lift $ runReadM (crReader rdr) arg+ return result CmdReader _ f -> flip fmap (f arg) $ \subp -> StateT $ \args -> do setContext (Just arg) subp@@ -116,18 +116,14 @@ let missing_arg = lift $ missingArgP no_arg_err (crCompleter rdr) (arg', args') <- maybe missing_arg return mb_args put args'- case runReadM (crReader rdr arg') of- Left e -> lift $ errorFor arg1 e- Right r -> return r+ lift $ runReadM (withReadM (errorFor arg1) (crReader rdr)) arg' FlagReader names x -> do guard $ has_name arg1 names guard $ isNothing val Just $ return x _ -> Nothing where- errorFor name (ErrorMsg msg) =- errorP (ErrorMsg ("option " ++ showOption name ++ ": " ++ msg))- errorFor _ e = errorP e+ errorFor name msg = "option " ++ showOption name ++ ": " ++ msg has_name a | disambiguate = any (isOptionPrefix a)
Options/Applicative/Help/Chunk.hs view
@@ -37,6 +37,10 @@ pure = Chunk . pure Chunk f <*> Chunk x = Chunk (f <*> x) +instance Alternative Chunk where+ empty = Chunk Control.Applicative.empty+ a <|> b = Chunk $ unChunk a <|> unChunk b+ instance Monad Chunk where return = pure m >>= f = Chunk $ unChunk m >>= unChunk . f
Options/Applicative/Help/Core.hs view
@@ -9,13 +9,13 @@ bodyHelp, footerHelp, parserHelp,- parserUsage+ parserUsage, ) where import Control.Monad (guard) import Data.List (intersperse, sort) import Data.Maybe (maybeToList, catMaybes)-import Data.Monoid (Monoid, mempty, mappend)+import Data.Monoid (mempty, mappend) import Options.Applicative.Common import Options.Applicative.Types
Options/Applicative/Internal.hs view
@@ -8,6 +8,8 @@ , uncons , hoistMaybe , hoistEither+ , runReadM+ , withReadM , runP @@ -30,9 +32,9 @@ import Control.Monad (MonadPlus(..), liftM, ap, guard) import Control.Monad.Trans.Class (MonadTrans, lift) import Control.Monad.Trans.Except- (runExceptT, ExceptT(..), throwE, catchE)+ (runExcept, runExceptT, withExcept, ExceptT(..), throwE, catchE) import Control.Monad.Trans.Reader- (runReader, runReaderT, Reader, ReaderT, ask)+ (mapReaderT, runReader, runReaderT, Reader, ReaderT, ask) import Control.Monad.Trans.Writer (runWriterT, WriterT, tell) import Control.Monad.Trans.State (StateT, get, put, evalStateT) import Data.Maybe (maybeToList)@@ -42,7 +44,6 @@ class (Alternative m, MonadPlus m) => MonadP m where setContext :: Maybe String -> ParserInfo a -> m ()- setParser :: Maybe String -> Parser a -> m () getPrefs :: m ParserPrefs missingArgP :: ParseError -> Completer -> m a@@ -87,7 +88,6 @@ instance MonadP P where setContext name = P . lift . tell . Context (maybeToList name)- setParser _ _ = return () getPrefs = P . lift . lift $ ask missingArgP e _ = errorP e@@ -108,6 +108,15 @@ uncons [] = Nothing uncons (x : xs) = Just (x, xs) +runReadM :: MonadP m => ReadM a -> String -> m a+runReadM (ReadM r) s = hoistEither . runExcept $ runReaderT r s++withReadM :: (String -> String) -> ReadM a -> ReadM a+withReadM f = ReadM . mapReaderT (withExcept f') . unReadM+ where+ f' (ErrorMsg err) = ErrorMsg (f err)+ f' e = e+ data SomeParser = forall a . SomeParser (Parser a) data ComplError@@ -157,7 +166,6 @@ instance MonadP Completion where setContext _ _ = return ()- setParser _ _ = return () getPrefs = Completion $ lift ask missingArgP _ = Completion . lift . lift . ComplOption
Options/Applicative/Types.hs view
@@ -10,6 +10,7 @@ OptProperties(..), OptVisibility(..), ReadM(..),+ readerAsk, readerAbort, readerError, CReader(..),@@ -41,6 +42,9 @@ import Control.Applicative (Applicative(..), Alternative(..), (<$>), optional) import Control.Monad (ap, liftM, MonadPlus, mzero, mplus)+import Control.Monad.Trans.Except (Except, throwE)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Reader (ReaderT, ask) import Data.Monoid (Monoid(..)) import System.Exit (ExitCode(..)) @@ -57,8 +61,8 @@ instance Monoid ParseError where mempty = UnknownError- mappend UnknownError m = m- mappend m _ = m+ mappend m UnknownError = m+ mappend _ m = m -- | A full description for a runnable 'Parser' for a program. data ParserInfo a = ParserInfo@@ -117,51 +121,54 @@ instance Functor Option where fmap f (Option m p) = Option (fmap f m) p -data CReader m a = CReader- { crCompleter :: Completer- , crReader :: String -> m a }--instance Functor m => Functor (CReader m) where- fmap f (CReader c r) = CReader c (fmap f . r)---- | A newtype over the 'Either' monad used by option readers.+-- | A newtype over 'ReaderT String Except', used by option readers. newtype ReadM a = ReadM- { runReadM :: Either ParseError a }+ { unReadM :: ReaderT String (Except ParseError) a } instance Functor ReadM where- fmap f (ReadM m) = ReadM (fmap f m)+ fmap f (ReadM r) = ReadM (fmap f r) instance Applicative ReadM where- pure = ReadM . Right- ReadM b <*> ReadM a = ReadM (b <*> a)+ pure = ReadM . pure+ ReadM x <*> ReadM y = ReadM $ x <*> y +instance Alternative ReadM where+ empty = mzero+ (<|>) = mplus+ instance Monad ReadM where- return = ReadM . Right- ReadM m >>= f = ReadM $ m >>= runReadM . f- fail = ReadM . Left . ErrorMsg+ return = pure+ ReadM r >>= f = ReadM $ r >>= unReadM . f+ fail = readerError instance MonadPlus ReadM where- mzero = ReadM $ Left UnknownError- mplus m1 m2 = case runReadM m1 of- Left _ -> m2- Right r -> return r+ mzero = ReadM mzero+ mplus (ReadM x) (ReadM y) = ReadM $ mplus x y +-- | Return the value being read.+readerAsk :: ReadM String+readerAsk = ReadM ask+ -- | Abort option reader by exiting with a 'ParseError'. readerAbort :: ParseError -> ReadM a-readerAbort = ReadM . Left+readerAbort = ReadM . lift . throwE -- | Abort option reader by exiting with an error message. readerError :: String -> ReadM a readerError = readerAbort . ErrorMsg -type OptCReader = CReader ReadM-type ArgCReader = CReader Maybe+data CReader a = CReader+ { crCompleter :: Completer+ , crReader :: ReadM a } +instance Functor CReader where+ fmap f (CReader c r) = CReader c (fmap f r)+ -- | An 'OptReader' defines whether an option matches an command line argument. data OptReader a- = OptReader [OptName] (OptCReader a) ParseError -- ^ option reader+ = OptReader [OptName] (CReader a) ParseError -- ^ option reader | FlagReader [OptName] !a -- ^ flag reader- | ArgReader (ArgCReader a) -- ^ argument reader+ | ArgReader (CReader a) -- ^ argument reader | CmdReader [String] (String -> Maybe (ParserInfo a)) -- ^ command reader instance Functor OptReader where
README.md view
@@ -4,9 +4,20 @@ parsers. [![Continuous Integration status][status-png]][status]+[![Hackage page (downloads and API reference)][hackage-png]][hackage] -[Hackage page (downloads and documentation)][hackage]+**Table of Contents** +- [Getting started](#getting-started)+- [Supported options](#supported-options)+ - [Regular options](#regular-options)+ - [Flags](#flags)+ - [Arguments](#arguments)+ - [Commands](#commands)+- [Option builders](#option-builders)+- [Advanced features](#advanced-features)+- [How it works](#how-it-works)+ ## Getting started Here is a simple example of an applicative option parser:@@ -336,8 +347,9 @@ See [this blog post][blog] for a more detailed explanation based on a simplified implementation. - [status-png]: https://secure.travis-ci.org/pcapriotti/optparse-applicative.png?branch=master+ [status-png]: https://api.travis-ci.org/pcapriotti/optparse-applicative.svg [status]: http://travis-ci.org/pcapriotti/optparse-applicative?branch=master [blog]: http://paolocapriotti.com/blog/2012/04/27/applicative-option-parser/ [builder-documentation]: http://hackage.haskell.org/package/optparse-applicative/docs/Options-Applicative-Builder.html- [hackage]: http://hackage.haskell.org/package/optparse-applicative-0.9.0+ [hackage-png]: http://img.shields.io/hackage/v/optparse-applicative.svg+ [hackage]: http://hackage.haskell.org/package/optparse-applicative
optparse-applicative.cabal view
@@ -1,5 +1,5 @@ name: optparse-applicative-version: 0.10.0+version: 0.11.0 synopsis: Utilities and combinators for parsing command line options description: Here is a simple example of an applicative option parser: