hflags (empty) → 0.1
raw patch · 9 files changed
+710/−0 lines, 9 filesdep +basedep +containersdep +template-haskellsetup-changed
Dependencies added: base, containers, template-haskell
Files
- COPYING +202/−0
- HFlags.hs +320/−0
- Setup.hs +2/−0
- examples/ComplexExample.hs +72/−0
- examples/ImportExample.hs +9/−0
- examples/SimpleExample.hs +13/−0
- examples/X/B.hs +9/−0
- examples/X/Y_Y/A.hs +7/−0
- hflags.cabal +76/−0
+ COPYING view
@@ -0,0 +1,202 @@++ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright [yyyy] [name of copyright owner]++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
+ HFlags.hs view
@@ -0,0 +1,320 @@+-- Copyright 2012 Google Inc. All Rights Reserved.+--+-- Licensed under the Apache License, Version 2.0 (the "License");+-- you may not use this file except in compliance with the License.+-- You may obtain a copy of the License at+--+-- http://www.apache.org/licenses/LICENSE-2.0+--+-- Unless required by applicable law or agreed to in writing, software+-- distributed under the License is distributed on an "AS IS" BASIS,+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+-- See the License for the specific language governing permissions and+-- limitations under the License.+--+-- Authors: Mihaly Barasz <klao@google.com>, Gergely Risko <errge@google.com>++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE NamedFieldPuns #-}++-- |+-- Module: HFlags+-- License: Apache 2.0+--+-- The @HFlags@ library supports easy definition of command line flags,+-- reimplementing the ideas from Google's @gflags@+-- (<http://code.google.com/p/gflags>).+--+-- Command line flags can be declared in any file at the toplevel,+-- using 'defineFlag'. At runtime, the actual values are assigned to+-- 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+-- 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+-- <http://github.com/errge/hflags/blob/master/examples/ImportExample.hs>.+--+-- A simple example (more in the+-- <http://github.com/errge/hflags/tree/master/examples> directory):+--+-- > #!/usr/bin/env runhaskell+-- >+-- > {-# LANGUAGE TemplateHaskell #-}+-- >+-- > import HFlags+-- >+-- > defineFlag "name" "Indiana Jones" "Who to greet."+-- > defineFlag "r:repeat" (3 + 4 :: Int) "Number of times to repeat the message."+-- >+-- > main = do s <- $(initHFlags "Simple program v0.1")+-- > sequence_ $ replicate flags_repeat greet+-- > where+-- > greet = putStrLn $ "Hello " ++ flags_name ++ ", very nice to meet you!"+--+-- 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.++module HFlags (+ -- * Definition of flags+ defineCustomFlag,+ defineQQFlag,+ FlagType(..),+ -- * Initialization of flags at runtime+ initHFlags) where++-- TODOs:+-- ?--no* for bools?+-- --help should show the current value if it's different than the default value, so user can test command line args++import Control.Exception+import Control.Monad+import Data.Char+import Data.Function+import Data.List+import Data.IORef+import Data.Maybe+import qualified Data.Map as Map+import Data.Map (Map, (!))+import Language.Haskell.TH+import System.Console.GetOpt+import System.Environment+import System.IO+import System.IO.Unsafe+import System.Exit++import Prelude hiding (catch)++-- | Data type for storing every property of a flag.+data FlagData = FlagData+ { fName :: String+ , fShort :: Maybe Char+ , fDefValue :: String+ , fArgHelp :: String+ , fDescription :: String+ , fModuleName :: String+ , fCheck :: IO () -- ^ function to evaluate in 'initFlags'+ -- to force syntax check of the argument.+ }++-- | Every flag the program supports has to be defined through a new+-- phantom datatype and the Flag instance of that datatype.+--+-- But users of the library shouldn't worry about this class or the+-- implementation details behind these functions, just use the+-- @defineFlag@ Template Haskell function for defining new flags.+class Flag a where+ getFlagData :: a -> FlagData++-- | The most flexible way of defining a flag. For an example see+-- <http://github.com/errge/hflags/blob/master/examples/ComplexExample.hs>.+-- For most things 'defineFlag' should be enough instead.+--+-- The parameters:+--+-- * name of the flag (@l:long@ syntax if you want to have the short option @l@ for this flag),+--+-- * quasiquoted and type signed default value,+--+-- * help string for the argument,+--+-- * read function, quasiquoted,+--+-- * show function, quasiquoted,+--+-- * help string for the flag.+defineCustomFlag :: String -> ExpQ -> String -> ExpQ -> ExpQ -> String -> Q [Dec]+defineCustomFlag name' defQ argHelp readQ showQ description =+ do (name, short) <- case () of+ () | length name' == 0 -> fail "Flag's without names are not supported."+ | length name' == 1 -> return (name', Just $ head name')+ | length name' == 2 -> return (name', Nothing)+ | name' !! 1 == ':' -> return (drop 2 name', Just $ head name')+ | otherwise -> return (name', Nothing)+ defE <- defQ+ case defE of+ SigE _ _ -> return ()+ _ -> fail "Default value for defineCustomFlag has to be an explicitly typed expression, like (12 :: Int)"+ moduleName <- fmap loc_module location+ let accessorName = mkName $ "flags_" ++ name+ let dataName = mkName $ "HFlag_" ++ name+ dataDec <- return $ DataD [] dataName [] [] []+ instanceDec <- instanceD+ (return [])+ (appT (conT ''Flag) (conT dataName))+ [funD 'getFlagData [clause [wildP]+ (normalB+ [| FlagData+ name+ short+ $(appE showQ defQ)+ argHelp+ description+ moduleName+ (evaluate $(varE accessorName) >> return ())+ |]) []]]+ flagPragmaDec <- return $ PragmaD $ InlineP accessorName $ InlineSpec False False Nothing+ flagDec <- funD accessorName [clause [] (normalB [| case True of+ True -> $(appE readQ [| lookupFlag name moduleName |])+ False -> $(defQ) |]) []]+ return [dataDec, instanceDec, flagPragmaDec, flagDec]++-- | This just forwards to 'defineCustomFlag' with @[| read |]@ and+-- @[| show |]@. Useful for flags where the type is not an instance+-- of 'FlagType'. For examples, see+-- <http://github.com/errge/hflags/blob/master/examples/ComplexExample.hs>.+--+-- The parameters:+--+-- * name of the flag (@l:long@ syntax if you want to have the short option @l@ for this flag),,+--+-- * quasiquoted and type signed default value,+--+-- * help string for the argument,+--+-- * help string for the flag.+defineQQFlag :: String -> ExpQ -> String -> String -> Q [Dec]+defineQQFlag name defQ argHelp description =+ defineCustomFlag name defQ argHelp [| read |] [| show |] description++-- | Class of types for which the easy 'defineFlag' syntax is supported.+class FlagType t where+ -- | The @defineFlag@ function defines a new flag.+ --+ -- The parameters:+ --+ -- * name of the flag (@l:long@ syntax if you want to have the short option @l@ for this flag),,+ --+ -- * default value,+ --+ -- * help string for the flag.+ defineFlag :: String -> t -> String -> Q [Dec]++boolShow :: Bool -> String+boolShow True = "true"+boolShow False = "false"++boolRead :: String -> Bool+boolRead = boolRead' . map toLower+ where+ boolRead' ('y':_) = True+ boolRead' ('t':_) = True+ boolRead' ('1':_) = True+ boolRead' ('n':_) = False+ boolRead' ('f':_) = False+ boolRead' ('0':_) = False+ boolRead' s = error $ "Unable to parse string as boolean: " ++ s++instance FlagType Bool where+ defineFlag n v = defineCustomFlag n [| v :: Bool |] "BOOL" [| boolRead |] [| boolShow |]++instance FlagType Int where+ defineFlag n v = defineQQFlag n [| v :: Int |] "INT"++instance FlagType Integer where+ defineFlag n v = defineQQFlag n [| v :: Integer |] "INTEGER"++instance FlagType String where+ defineFlag n v = defineCustomFlag n [| v :: String |] "STRING" [| id |] [| id |]++instance FlagType Double where+ defineFlag n v = defineQQFlag n (sigE (litE (RationalL (toRational v))) [t| Double |] ) "DOUBLE"++-- | A global "IORef" for the communication between @initHFlags@ and+-- @flag_*@. This is a map between flag name and current value.+{-# NOINLINE globalHFlags #-}+globalHFlags :: IORef (Maybe (Map String String))+globalHFlags = unsafePerformIO $ newIORef Nothing++lookupFlag :: String -> String -> String+lookupFlag fName fModuleName = unsafePerformIO $ do+ flags <- readIORef globalHFlags+ case flags of+ Just flagmap -> return $ flagmap ! fName+ Nothing -> error $ "Flag " ++ fName ++ " (from module: " ++ fModuleName ++ ") used before calling initHFlags."++-- | Initializes @globalHFlags@ and returns the non-option arguments.+initFlags :: String -> [FlagData] -> [String] -> IO [String]+initFlags 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+ when (not $ null errs) $ do+ mapM_ (hPutStrLn stderr) errs+ exitFailure+ let defaults = map (\FlagData { fName, fDefValue } -> (fName, fDefValue)) flags+ env <- getEnvironment+ let envDefaults = map (mapFst (fromJust . stripPrefix "HFLAGS_")) $ filter ((isPrefixOf "HFLAGS_") . fst) env+ writeIORef globalHFlags $ Just $ Map.fromList $ defaults ++ envDefaults ++ opts+ mapM_ forceFlag flags+ return nonopts+ where+ mapFst f (a, b) = (f a, b)+ 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)+ exitFailure++ undefokOption = Option "" ["undefok"] (NoArg ("", "")) "Whether to fail on unrecognized command line options."+ doUndefok = case getOpt Permute [undefokOption] args of+ ([], _, _) -> False+ _ -> True++ flagToGetOptArgDescr FlagData { fName, fArgHelp }+ | fArgHelp == "BOOL" = OptArg (\a -> (fName, maybe "True" id a)) fArgHelp+ | otherwise = ReqArg (\a -> (fName, a)) fArgHelp++ -- 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 ++ ")")++ forceFlag FlagData { fName, fModuleName, fCheck } =+ fCheck `catch`+ (\e -> error $+ "Error while parsing argument for flag: " ++ fName +++ ", value: " ++ lookupFlag fName fModuleName +++ ", error: " ++ show (e :: ErrorCall))++-- | Has to be called from the main before doing anything else:+--+-- @+-- main = do args <- $(initHFlags "Simple program v0.1")+-- ...+-- @+--+-- Internally, it uses Template Haskell trickery to gather all the+-- instances of the Flag class and then generates a call to+-- @initFlags@ with the appropriate data gathered together from those+-- instances to a list.+--+-- Type after splicing is @IO [String]@.+initHFlags :: String -> ExpQ -- IO [String]+initHFlags progDescription = do+ ClassI _ instances <- reify ''Flag+ case dupes instances of+ [] -> return ()+ (dupe:_) -> fail ("Multiple definition of flag " ++ (snd $ head dupe) +++ ", modules: " ++ (show $ map fst dupe))+ [| getArgs >>= initFlags progDescription $(listE $ map instanceToOptTuple instances ) |]+ where+ instanceToOptTuple (InstanceD _ (AppT _ inst) _) = [| getFlagData (undefined :: $(return inst)) |]+ instanceToOptTuple _ = error "Shouldn't happen"+ instanceToModuleNamePair (InstanceD _ (AppT _ (ConT inst)) _) =+ let (flagrev, modrev) = span (/= '.') $ reverse $ show inst+ modName = reverse $ drop 1 modrev+ flag = drop 1 $ dropWhile (/= '_') $ reverse $ flagrev+ in (modName, flag)+ instanceToModuleNamePair _ = error "Shouldn't happen"+ dupes instances = filter ((>1) . length) $+ groupBy ((==) `on` snd) $+ sortBy (compare `on` snd) $+ map instanceToModuleNamePair instances
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ examples/ComplexExample.hs view
@@ -0,0 +1,72 @@+#!/usr/bin/env runhaskell+ +{-# LANGUAGE TemplateHaskell #-}++import Control.Monad+import System.Exit++import HFlags++-- For flags with a simple type (technically speaking, for instances+-- of FlagType, see `:info FlagType' in GHCi), defining a new flag is+-- very straightforward:+defineFlag "name" "Indiana Jones" "Who to greet."+-- There is a special syntax to support short options, like `d' here.+-- Also, for the Bool options the argument is not mandatory, if the+-- user just runs the program with -d or --dry_run, flags_dru_run will+-- be set to True.+defineFlag "d:dry_run" False "Don't print anything, just exit."+-- For integral types you have to explicitly define Int or Integer.+defineFlag "repeat" (3 + 4 :: Int) "Number of times to repeat the message."++-- For flags with a more complex type, where the existing Read and+-- Show is suitable for parsing of the argument value, you can use the+-- defineQQFlag syntax. Here, the QQ is mnemonic for QuasiQuoter,+-- because you have to quasiquote the default value, and type sign it+-- inside the quasiquote. Also, you have to provide the name of the+-- type for --help generation.+defineQQFlag "numbers_to_sum" [| [1,2,3,4,5] :: [Int] |] "INT_LIST" "Print the sum of these numbers."++-- This works quite well for simple enums too!+data Color = Red | Yellow | Green deriving (Show, Read)+defineQQFlag "favorite_color" [| Yellow :: Color |] "COLOR" "Your favorite color."++-- Sometimes the default read or show instance is not good enough for+-- your needs. In that case you can use defineCustomFlag to override+-- those functions.+data Language = English | Hungarian+defineCustomFlag "language" [| English :: Language |] "en|hu"+ [| \s -> case s of + "en" -> English+ "hu" -> Hungarian+ _ -> error $ "Unknown language: " ++ s+ |]+ [| \l -> case l of + English -> "en"+ Hungarian -> "hu"+ |]+ "Language of the greeting."++-- You can also do simple range checks with this.+defineCustomFlag "percent" [| 100 :: Double |] "PERCENTAGE"+ [| \s -> let p = read s+ in if 0.0 <= p && p <= 100.0+ then p+ else error "Percentage value has to be between 0 and 100."+ |]+ [| show |]+ "Print first percent percentage of the message."++main = do+ _ <- $(initHFlags "HFlags example program v0.1")+ when (flags_dry_run) $ exitSuccess+ forM_ [1..flags_repeat] (const greet)+ putStrLn $ "IIRC, your favorite color is " ++ show flags_favorite_color ++ "."+ where+ s = show (sum flags_numbers_to_sum)+ percentPutStrLn 0 _ = return ()+ percentPutStrLn p str = let n = ceiling $ fromIntegral (length str) * p / 100.0+ in putStrLn $ take n str+ greet = percentPutStrLn flags_percent $ case flags_language of+ English -> "Hello " ++ flags_name ++ ", very nice to meet you, the sum is " ++ s ++ "!"+ Hungarian -> "Szia " ++ flags_name ++ ", orvendek a talalkozasnak, a szamok osszege " ++ s ++ "!"
+ examples/ImportExample.hs view
@@ -0,0 +1,9 @@+#!/usr/bin/env runhaskell+ +{-# LANGUAGE TemplateHaskell #-}++import HFlags+import X.B++main = do _ <- $(initHFlags "Importing example v0.1")+ print $ b
+ examples/SimpleExample.hs view
@@ -0,0 +1,13 @@+#!/usr/bin/env runhaskell+ +{-# LANGUAGE TemplateHaskell #-}++import HFlags++defineFlag "name" "Indiana Jones" "Who to greet."+defineFlag "repeat" (3 + 4 :: Int) "Number of times to repeat the message."++main = do s <- $(initHFlags "Simple program v0.1")+ sequence_ $ replicate flags_repeat greet+ where+ greet = putStrLn $ "Hello " ++ flags_name ++ ", very nice to meet you!"
+ examples/X/B.hs view
@@ -0,0 +1,9 @@+module X.B (b) where++import qualified X.Y_Y.A as A++-- to test collision detection+-- import HFlags+-- defineFlag "verbose" True "Whether debug output should be printed."++b = A.flags_verbose
+ examples/X/Y_Y/A.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE TemplateHaskell #-}++module X.Y_Y.A where++import HFlags++defineFlag "verbose" True "Whether debug output should be printed."
+ hflags.cabal view
@@ -0,0 +1,76 @@+name: hflags+version: 0.1+license: OtherLicense+license-file: COPYING+author: Mihaly Barasz <klao@google.com>, Gergely Risko <errge@google.com>+maintainer: Gergely Risko <errge@google.com>+build-type: Simple+cabal-version: >= 1.6+category: Console+stability: provisional+homepage: http://github.com/errge/hflags+bug-reports: mailto:errge@google.com++synopsis: Command line flag parser, very similar to Google's gflags+description:+ The @HFlags@ library supports easy definition of command line flags,+ reimplementing the ideas from Google's @gflags@+ (<http://code.google.com/p/gflags>).+ .+ Command line flags can be declared in any file at the toplevel,+ using 'defineFlag'. At runtime, the actual values are assigned to+ 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+ 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+ <http://github.com/errge/hflags/blob/master/examples/ImportExample.hs>.+ .+ A simple example (more in the+ <http://github.com/errge/hflags/tree/master/examples> directory):+ .+ @+ \#!\/usr\/bin\/env runhaskell+ .+ {-\# LANGUAGE TemplateHaskell \#-}+ .+ import HFlags+ .+ 'defineFlag' \"name\" \"Indiana Jones\" \"Who to greet.\"+ 'defineFlag' \"r:repeat\" (3 + 4 :: Int) \"Number of times to repeat the message.\"+ .+ main = do s <- $(initHFlags \"Simple program v0.1\")+   sequence_ $ replicate flags_repeat greet+   where+   greet = putStrLn $ \"Hello \" ++ flags_name ++ \", very nice to meet you!\"+ @+ .+ 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.++extra-source-files:+ examples/ComplexExample.hs+ examples/ImportExample.hs+ examples/SimpleExample.hs+ examples/X/B.hs+ examples/X/Y_Y/A.hs++source-repository head+ type: git+ location: http://github.com/errge/hflags++library+ ghc-options: -Wall++ build-depends:+ base >= 4.5 && < 5+ , containers >= 0.4+ , template-haskell >= 2.7++ exposed-modules:+ HFlags