hflags 0.2 → 0.3
raw patch · 2 files changed
+64/−24 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ HFlags: globalUndefinedOptions :: IORef (Maybe [String])
+ HFlags: instance FlagType Char
+ HFlags: undefinedOptions :: [String]
Files
- HFlags.hs +55/−21
- hflags.cabal +9/−3
HFlags.hs view
@@ -34,8 +34,8 @@ -- the toplevel @flags_name@ constants. Those can be used purely -- throughout the program. ----- At the beginning of the @main@ function, @$initHFlags "program--- description"@ has to be called to initialize the flags. All flags+-- At the beginning of the @main@ function, @$'initHFlags' \"program+-- description\"@ has to be called to initialize the flags. All flags -- will be initialized that are transitively reachable via imports -- from @main@. This means, that any Haskell package can easily -- define command line flags with @HFlags@. This feature is@@ -62,10 +62,11 @@ -- > where -- > greet = putStrLn $ "Hello " ++ flags_name ++ ", very nice to meet you!" ----- At @initHFlags@ time, the library also tries to gather flags out of+-- At 'initHFlags' time, the library also tries to gather flags out of -- environment variables. @HFLAGS_verbose=True@ is equivalent to--- specify --verbose=True. This environment feature only works with--- long options and the user has to specify a value even for Bools.+-- specifying @--verbose=True@ on the command line. This environment+-- feature only works with long options and the user has to specify a+-- value even for @Bool@s. -- -- /Since version 0.2, you mustn't put the initHFlags in a parentheses with the program description. Just/ @$initHFlags@, /it's cleaner./ @@ -80,10 +81,12 @@ initHFlagsDependentDefaults, -- * For easy access to arguments, after initHFlags has been called arguments,+ undefinedOptions, -- * For debugging, shouldn't be used in production code Flag(..), globalHFlags,- globalArguments+ globalArguments,+ globalUndefinedOptions ) where -- TODOs:@@ -121,7 +124,7 @@ , fArgType :: String , fDescription :: String , fModuleName :: String- , fCheck :: IO () -- ^ function to evaluate in 'initFlags'+ , fCheck :: IO () -- ^ function to evaluate in @initFlags@ -- to force syntax check of the argument. } @@ -242,6 +245,16 @@ instance FlagType Bool where defineFlag n v = defineCustomFlag n [| v :: Bool |] "BOOL" [| boolRead |] [| boolShow |] +charShow :: Char -> String+charShow x = x:[]++charRead :: String -> Char+charRead [x] = x+charRead s = error $ "Unable to parse string as char: " ++ s++instance FlagType Char where+ defineFlag n v = defineCustomFlag n [| v :: Char |] "CHAR" [| charRead |] [| charShow |]+ instance FlagType Int where defineFlag n v = defineEQFlag n [| v :: Int |] "INT" @@ -262,19 +275,19 @@ let s = Data.Text.unpack v in defineCustomFlag n [| Data.Text.pack s :: Data.Text.Text |] "TEXT" [| Data.Text.pack |] [| Data.Text.unpack |] --- | A global "IORef" for the communication between @initHFlags@ and+-- | A global 'IORef' for the communication between 'initHFlags' and -- @flags_*@. This is a map between flag name and current value. {-# NOINLINE globalHFlags #-} globalHFlags :: IORef (Maybe (Map String String)) globalHFlags = unsafePerformIO $ newIORef Nothing --- | A global "IORef" for the easy access to the arguments.+-- | A global 'IORef' for the easy access to the arguments. {-# NOINLINE globalArguments #-} globalArguments :: IORef (Maybe [String]) globalArguments = unsafePerformIO $ newIORef Nothing -- | Contains the non-parsed, non-option parts of the command line,--- the arguments. Can only be used after @initHFlags@ has been called.+-- the arguments. Can only be used after 'initHFlags' has been called. {-# NOINLINE arguments #-} arguments :: [String] arguments = unsafePerformIO $ do@@ -283,6 +296,25 @@ Just args -> return $ args Nothing -> error $ "HFlags.arguments used before calling initHFlags." +-- | A global 'IORef' for the easy access to the undefined options, if+-- @--undefok@ is used. Useful, if you have to pass these options to+-- another library, e.g. @criterion@ or @GTK@.+{-# NOINLINE globalUndefinedOptions #-}+globalUndefinedOptions :: IORef (Maybe [String])+globalUndefinedOptions = unsafePerformIO $ newIORef Nothing++-- | Contains the non-parsed, option parts of the command line, if+-- @--undefok@ is in use. This can be useful, when you have to pass+-- these options to other libraries, e.g. @criterion@ or @GTK@. Can+-- only be used after 'initHFlags' has been called.+{-# NOINLINE undefinedOptions #-}+undefinedOptions :: [String]+undefinedOptions = unsafePerformIO $ do+ margs <- readIORef globalUndefinedOptions+ case margs of+ Just args -> return $ args+ Nothing -> error $ "HFlags.globalUndefOpts used before calling initHFlags."+ lookupFlag :: String -> String -> String lookupFlag fName fModuleName = unsafePerformIO $ do flags <- readIORef globalHFlags@@ -296,12 +328,13 @@ -- | A function that gets three alists and returns a new one. type DependentDefaults = AList -> AList -> AList -> AList --- | Initializes @globalHFlags@ and returns the non-option arguments.+-- | Initializes 'globalHFlags' and returns the non-option arguments. initFlags :: DependentDefaults -> String -> [FlagData] -> [String] -> IO [String] initFlags dependentDefaults progDescription flags args = do doHelp- let (opts, nonopts, errs) | doUndefok = (\(a,b,_,c) -> (a,b,c)) $ getOpt' Permute getOptFlags args- | otherwise = getOpt Permute getOptFlags args+ let (opts, nonopts, undefopts, errs)+ | doUndefok = getOpt' Permute getOptFlags args+ | otherwise = (\(a,b,c) -> (a,b,[],c)) $ getOpt Permute getOptFlags args when (not $ null errs) $ do mapM_ (hPutStrLn stderr) errs exitFailure@@ -311,6 +344,7 @@ let depdef = dependentDefaults defaults envDefaults opts writeIORef globalHFlags $ Just $ Map.fromList $ defaults ++ depdef ++ envDefaults ++ opts writeIORef globalArguments $ Just nonopts+ writeIORef globalUndefinedOptions $ Just undefopts mapM_ forceFlag flags return nonopts where@@ -318,7 +352,7 @@ helpOption = Option "h" ["help", "usage", "version"] (NoArg ("", "")) "Display help and version information." doHelp = case getOpt Permute [helpOption] args of ([], _, _) -> return ()- _ -> do putStrLn $ usageInfo (progDescription ++ "\n") (helpOption:undefokOption:getOptFlags)+ _ -> do putStrLn $ usageInfo (progDescription ++ "\n") (helpOption:getOptFlags) exitFailure undefokOption = Option "" ["undefok"] (NoArg ("", "")) "Whether to fail on unrecognized command line options."@@ -331,9 +365,11 @@ | otherwise = ReqArg (\a -> (fName, a)) fArgType -- compute GetOpt compatible [Option] structure from flags ([FlagData])- getOptFlags = flip map flags $ \flagData@(FlagData { fName, fShort, fDefValue, fDescription, fModuleName }) ->- Option (maybeToList fShort) [fName] (flagToGetOptArgDescr flagData)- (fDescription ++ " (default: " ++ fDefValue ++ ", from module: " ++ fModuleName ++ ")")+ getOptFlags = undefokOption:+ (flip map flags $ \flagData@(FlagData { fName, fShort, fDefValue, fDescription, fModuleName }) ->+ Option (maybeToList fShort) [fName]+ (flagToGetOptArgDescr flagData)+ (fDescription ++ " (default: " ++ fDefValue ++ ", from module: " ++ fModuleName ++ ")")) forceFlag FlagData { fName, fModuleName, fCheck } = fCheck `catch`@@ -399,10 +435,8 @@ -- | Has to be called from the main before doing anything else: ----- @--- main = do args <- $initHFlags "Simple program v0.1"--- ...--- @+-- > main = do args <- $initHFlags "Simple program v0.1"+-- > ... -- -- /Since version 0.2, you mustn't put the initHFlags in a parentheses with the program description. Just/ @$initHFlags@, /it's cleaner./ --
hflags.cabal view
@@ -1,5 +1,5 @@ name: hflags-version: 0.2+version: 0.3 license: OtherLicense license-file: COPYING author: Mihaly Barasz <klao@google.com>, Gergely Risko <gergely@risko.hu>@@ -22,8 +22,8 @@ the toplevel @flags_name@ constants. Those can be used purely throughout the program. .- At the beginning of the @main@ function, @$initHFlags "program- description"@ has to be called to initialize the flags. All flags+ At the beginning of the @main@ function, @$initHFlags \"program+ description\"@ has to be called to initialize the flags. All flags will be initialized that are transitively reachable via imports from @main@. This means, that any Haskell package can easily define command line flags with @HFlags@. This feature is demonstrated by@@ -57,6 +57,12 @@ long options and the user has to specify a value even for Bools. . /Since version 0.2, you mustn't put the initHFlags in a parentheses with the program description. Just/ @$initHFlags@, /it's cleaner./+ .+ Changes in version 0.3+ .+ * Added @undefinedOptions@+ .+ * Added support for @Char@ . Changes in version 0.2 .