multiarg 0.10.0.0 → 0.12.0.0
raw patch · 4 files changed
+230/−4 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ System.Console.MultiArg.Combinator: ErrorMsg :: String -> OptArgError
+ System.Console.MultiArg.Combinator: NoMsg :: OptArgError
+ System.Console.MultiArg.Combinator: OneArgE :: (String -> Exceptional OptArgError a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: OptionalArgE :: (Maybe String -> Exceptional OptArgError a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: ThreeArgE :: (String -> String -> String -> Exceptional OptArgError a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: TwoArgE :: (String -> String -> Exceptional OptArgError a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: VariableArgE :: ([String] -> Exceptional OptArgError a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: data OptArgError
+ System.Console.MultiArg.Combinator: instance Eq OptArgError
+ System.Console.MultiArg.Combinator: instance Show OptArgError
+ System.Console.MultiArg.Combinator: optReader :: Read a => Maybe String -> Exceptional OptArgError (Maybe a)
+ System.Console.MultiArg.Combinator: reader :: Read a => String -> Exceptional OptArgError a
Files
- NEWS +9/−0
- System/Console/MultiArg/Combinator.hs +210/−3
- System/Console/MultiArg/SimpleParser.hs +10/−0
- multiarg.cabal +1/−1
NEWS view
@@ -76,3 +76,12 @@ * Changed the modes function in the SimpleParser module. The new function has a simpler type. It will however break old code.++Release 0.12.0.0, March 27, 2013+Changes since release 0.10.0.0:++* Added value constructors to the Combinator module to allow for+ easier parsing of option arguments that can fail to parse++* Added automatic "Enter -h for help" to simpleWithHelp and+ modesWithHelp functions in SimpleParser
System/Console/MultiArg/Combinator.hs view
@@ -8,8 +8,10 @@ -- * Combined long and short option parser OptSpec(OptSpec, longOpts, shortOpts, argSpec),- ArgSpec(NoArg, OptionalArg, OneArg, TwoArg,- ThreeArg, VariableArg, ChoiceArg),+ OptArgError(..),+ reader,+ optReader,+ ArgSpec(..), parseOption, -- * Formatting errors@@ -22,6 +24,7 @@ import Control.Applicative ((<$>), (<*>), optional, (<$), (*>), (<|>), many) +import qualified Control.Monad.Exception.Synchronous as Ex import System.Console.MultiArg.Prim ( Parser, try, approxLongOpt, nextWord, pendingShortOptArg, nonOptionPosArg,@@ -84,6 +87,69 @@ instance Functor OptSpec where fmap f (OptSpec ls ss as) = OptSpec ls ss (fmap f as) +-- | Reads in values that are members of Read. Provides a generic+-- error message if the read fails.+reader :: Read a => String -> Ex.Exceptional OptArgError a+reader s = case reads s of+ (a, ""):[] -> return a+ _ -> Ex.throw . ErrorMsg $ "could not parse option argument"++-- | Reads in values that are members of Read, but the value does not+-- have to appear on the command line. Provides a generic error+-- message if the read fails. If the argument is Nothing, returns+-- Nothing.+optReader+ :: Read a+ => Maybe String+ -> Ex.Exceptional OptArgError (Maybe a)+optReader ms = case ms of+ Nothing -> return Nothing+ Just s -> case reads s of+ (a, ""):[] -> return (Just a)+ _ -> Ex.throw . ErrorMsg $ "could not parse option argument"++-- | Indicates errors when parsing options to arguments.+data OptArgError+ = NoMsg+ -- ^ No error message accompanies this failure. multiarg will create+ -- a generic error message for you.++ | ErrorMsg String+ -- ^ Parsing the argument failed with this error message. An example+ -- might be @option argument is not an integer@ or @option argument+ -- is too large@. The text of the options the user provided is+ -- automatically prepended to the error message, so do not replicate+ -- this in your message.++ deriving (Eq, Show)++-- | Create an error message from an OptArgError.+errorMsg+ :: Either LongOpt ShortOpt+ -- ^ The option with the faulty argument++ -> [String]+ -- ^ The faulty command line arguments++ -> OptArgError+ -> String+errorMsg badOpt ss err = arg ++ opt ++ msg+ where+ arg = let aw = if length ss > 1 then "arguments " else "argument "+ ws = concat . intersperse " " . map quote $ ss+ quote s = "\"" ++ s ++ "\""+ in aw ++ ws+ opt = " to option " ++ optDesc+ optDesc = case badOpt of+ Left lo -> "--" ++ unLongOpt lo+ Right so -> "-" ++ [unShortOpt so]+ msg = " invalid" ++ detail+ detail = case err of+ NoMsg -> ""+ ErrorMsg s -> ": " ++ s+++ -- | Specifies how many arguments each option takes. As with -- 'System.Console.GetOpt.ArgDescr', there are (at least) two ways to -- use this type. You can simply represent each possible option using@@ -91,6 +157,12 @@ -- have each ArgSpec yield a function that transforms a record. For an -- example that uses an algebraic data type, see -- "System.Console.MultiArg.SampleParser".+--+-- Some of these value constructors have names ending in @E@. Use+-- these constructors when you want to parse option arguments that may+-- fail to parse--for example, you want to parse an Int. The function+-- passed as an argument to the value constructor indicates failure by+-- returing an 'Exception'. data ArgSpec a = NoArg a -- ^ This option takes no arguments@@ -143,7 +215,27 @@ -- option to GNU grep, which requires the user to supply one of -- three arguments: @always@, @never@, or @auto@. + | OptionalArgE (Maybe String -> Ex.Exceptional OptArgError a)+ -- ^ This option takes an optional argument, like+ -- 'OptionalArg'. Parsing of the optional argument might fail. + | OneArgE (String -> Ex.Exceptional OptArgError a)+ -- ^ This option takes a single argument, like 'OneArg'. Parsing+ -- of the argument might fail.++ | TwoArgE (String -> String -> Ex.Exceptional OptArgError a)+ -- ^ This option takes two arguments, like 'TwoArg'. Parsing of+ -- the arguments might fail.++ | ThreeArgE (String -> String -> String -> Ex.Exceptional OptArgError a)+ -- ^ This option takes three arguments, like 'ThreeArg'. Parsing+ -- of the arguments might fail.++ | VariableArgE ([String] -> Ex.Exceptional OptArgError a)+ -- ^ This option takes a variable number of arguments, like+ -- 'VariableArg'. Parsing of the arguments might fail.++ instance Functor ArgSpec where fmap f a = case a of NoArg i -> NoArg $ f i@@ -160,7 +252,21 @@ ChoiceArg gs -> ChoiceArg . map (\(s, r) -> (s, f r)) $ gs + OptionalArgE g -> OptionalArgE $ \ms -> fmap f (g ms) + OneArgE g ->+ OneArgE $ \s1 -> fmap f (g s1)++ TwoArgE g ->+ TwoArgE $ \s1 s2 -> fmap f (g s1 s2)++ ThreeArgE g ->+ ThreeArgE $ \s1 s2 s3 -> fmap f (g s1 s2 s3)++ VariableArgE g ->+ VariableArgE $ \ls -> fmap f (g ls)++ -- | Parses a single command line option. Examines all the options -- specified using multiple OptSpec and parses one option on the -- command line accordingly. Fails without consuming any input if the@@ -229,6 +335,40 @@ ++ (concat . intersperse ", " . map fst $ ls) Just g -> return g + OptionalArgE f -> case maybeArg of+ Nothing -> Ex.switch (fail . errorMsg (Left lo) []) return+ $ f Nothing+ Just s -> Ex.switch (fail . errorMsg (Left lo) [s]) return+ $ f (Just s)+++ OneArgE f -> maybeNextArg >>= g+ where+ g a = Ex.switch (fail . errorMsg (Left lo) [a]) return+ $ f a++ TwoArgE f -> do+ a1 <- maybeNextArg+ a2 <- nextWord+ Ex.switch (fail . errorMsg (Left lo) [a1, a2]) return+ $ f a1 a2++ ThreeArgE f -> do+ a1 <- maybeNextArg+ a2 <- nextWord+ a3 <- nextWord+ Ex.switch (fail . errorMsg (Left lo) [a1, a2, a3]) return+ $ f a1 a2 a3++ VariableArgE f -> do+ as <- many nonOptionPosArg+ let args = case maybeArg of+ Nothing -> as+ Just a -> a:as+ Ex.switch (fail . errorMsg (Left lo) args) return+ $ f args++ shortOpt :: OptSpec a -> Maybe (Parser a) shortOpt o = mconcat parsers where parsers = map mkParser . shortOpts $ o@@ -242,6 +382,11 @@ ThreeArg f -> shortThreeArg f VariableArg f -> shortVariableArg f ChoiceArg ls -> shortChoiceArg opt ls+ OptionalArgE f -> shortOptionalArgE opt f+ OneArgE f -> shortOneArgE opt f+ TwoArgE f -> shortTwoArgE opt f+ ThreeArgE f -> shortThreeArgE opt f+ VariableArgE f -> shortVariableArgE opt f -- | Parses a short option without an argument, either pending or -- non-pending. Fails with a single error message rather than two.@@ -264,9 +409,29 @@ Just arg1 -> return (f (arg1:args)) +shortVariableArgE+ :: ShortOpt+ -> ([String] -> Ex.Exceptional OptArgError a)+ -> Parser a+shortVariableArgE so f = do+ maybeSameWordArg <- optional pendingShortOptArg+ args <- many nonOptionPosArg+ let as = case maybeSameWordArg of+ Nothing -> args+ Just a -> a:args+ Ex.switch (fail . errorMsg (Right so) as) return $ f as++ shortOneArg :: (String -> a) -> Parser a shortOneArg f = f <$> firstShortArg +shortOneArgE+ :: ShortOpt+ -> (String -> Ex.Exceptional OptArgError a)+ -> Parser a+shortOneArgE so f = do+ a <- firstShortArg+ Ex.switch (fail . errorMsg (Right so) [a]) return $ f a firstShortArg :: Parser String firstShortArg =@@ -287,9 +452,30 @@ shortTwoArg :: (String -> String -> a) -> Parser a shortTwoArg f = f <$> firstShortArg <*> nextWord +shortTwoArgE+ :: ShortOpt+ -> (String -> String -> Ex.Exceptional OptArgError a)+ -> Parser a+shortTwoArgE so f = do+ a1 <- firstShortArg+ a2 <- nextWord+ Ex.switch (fail . errorMsg (Right so) [a1, a2]) return+ $ f a1 a2+ shortThreeArg :: (String -> String -> String -> a) -> Parser a shortThreeArg f = f <$> firstShortArg <*> nextWord <*> nextWord +shortThreeArgE+ :: ShortOpt+ -> (String -> String -> String -> Ex.Exceptional OptArgError a)+ -> Parser a+shortThreeArgE so f = do+ a1 <- firstShortArg+ a2 <- nextWord+ a3 <- nextWord+ Ex.switch (fail . errorMsg (Right so) [a1, a2, a3]) return+ $ f a1 a2 a3+ shortOptionalArg :: (Maybe String -> a) -> Parser a shortOptionalArg f = do maybeSameWordArg <- optional pendingShortOptArg@@ -301,6 +487,25 @@ Just a -> return (f (Just a)) Just a -> return (f (Just a)) +shortOptionalArgE+ :: ShortOpt+ -> (Maybe String -> Ex.Exceptional OptArgError a)+ -> Parser a+shortOptionalArgE so f = do+ maybeSameWordArg <- optional pendingShortOptArg+ case maybeSameWordArg of+ Nothing -> do+ maybeArg <- optional nonOptionPosArg+ case maybeArg of+ Nothing -> Ex.switch (fail . errorMsg (Right so) []) return+ $ f Nothing+ Just a -> Ex.switch (fail . errorMsg (Right so) [a]) return+ $ f (Just a)+ Just a -> Ex.switch (fail . errorMsg (Right so) [a]) return+ $ f (Just a)+++ -- | Finds the unambiguous short match for a string, if there is -- one. Returns a string describing the error condition if there is -- one, or the matching result if successful.@@ -339,6 +544,8 @@ gen = unlines . mapMaybe toGeneral $ ls genError = if null gen then ""- else "Other errors:\n" ++ gen+ else let sep = if null expError+ then "" else "\n"+ in sep ++ gen unk = if any (== Unknown) ls then "Unknown error\n" else ""
System/Console/MultiArg/SimpleParser.hs view
@@ -184,10 +184,19 @@ rs <- case exResult of Ex.Exception e -> do IO.hPutStr IO.stderr (C.formatError pn e)+ enterForHelp pn exitFailure Ex.Success g -> return g extractOpts pn h rs +-- | Display a simple enter-h-for-help message.+enterForHelp+ :: String+ -- ^ Program name+ -> IO ()+enterForHelp pn =+ let s = "\nEnter \"" ++ pn ++ " -h\" for help.\n"+ in IO.hPutStr IO.stderr s -- -- Mode parsing@@ -363,6 +372,7 @@ case modesWithHelpPure pn hlp glbls lsToEi as of Ex.Exception e -> do IO.hPutStr IO.stderr $ C.formatError pn e+ enterForHelp pn exitFailure Ex.Success g -> case g of NeedsHelp h -> putStr h >> exitSuccess
multiarg.cabal view
@@ -1,5 +1,5 @@ Name: multiarg-Version: 0.10.0.0+Version: 0.12.0.0 Cabal-version: >=1.8 Build-Type: Simple License: BSD3