config-ini 0.1.1.0 → 0.1.2.0
raw patch · 6 files changed
+89/−22 lines, 6 filesdep +doctestdep +microlensdep ~basedep ~transformersPVP ok
version bump matches the API change (PVP)
Dependencies added: doctest, microlens
Dependency ranges changed: base, transformers
API changes (from Hackage documentation)
Files
- config-ini.cabal +16/−3
- examples/config-example/Main.hs +1/−1
- src/Data/Ini/Config.hs +41/−6
- src/Data/Ini/Config/Raw.hs +7/−4
- test/doctest/Main.hs +8/−0
- test/ini-compat/Main.hs +16/−8
config-ini.cabal view
@@ -1,7 +1,8 @@ name: config-ini-version: 0.1.1.0+version: 0.1.2.0 synopsis: A library for simple INI-based configuration files. homepage: https://github.com/aisamanra/config-ini+bug-reports: https://github.com/aisamanra/config-ini/issues description: The @config-ini@ library is a small monadic language for writing simple configuration languages with convenient, human-readable error messages.@@ -20,7 +21,7 @@ copyright: ©2016 Getty Ritter category: Configuration build-type: Simple-cabal-version: >= 1.14+cabal-version: >= 1.10 source-repository head type: git@@ -38,7 +39,7 @@ build-depends: base >=4.7 && <4.10 , text >=1.2.2 && <1.3 , unordered-containers >=0.2.7 && <0.3- , transformers >=0.5.2 && <0.6+ , transformers >=0.4.1 && <0.6 , megaparsec >=5.1.2 && <5.2 default-language: Haskell2010 @@ -88,3 +89,15 @@ , unordered-containers , text , directory++test-suite test-doctest+ if impl(ghc < 7.10)+ buildable: False+ type: exitcode-stdio-1.0+ ghc-options: -Wall+ default-language: Haskell2010+ hs-source-dirs: test/doctest+ main-is: Main.hs+ build-depends: base+ , doctest+ , microlens
examples/config-example/Main.hs view
@@ -25,7 +25,7 @@ port <- fieldOf "port" number return NetworkConfig { netHost = host, netPort = port } locCf <- sectionMb "LOCAL" $- LocalConfig <$> field "user"+ LocalConfig `fmap` field "user" return Config { cfNetwork = netCf, cfLocal = locCf } main :: IO ()
src/Data/Ini/Config.hs view
@@ -30,7 +30,7 @@ , flag ) where -import Control.Applicative (Alternative(..))+import Control.Applicative (Applicative(..), Alternative(..)) import Control.Monad.Trans.Except import qualified Data.HashMap.Strict as HM import Data.Ini.Config.Raw@@ -137,7 +137,7 @@ -- >>> parseIniFile "[MAIN]\nx = hello\n" $ section "MAIN" (field "x") -- Right "hello" -- >>> parseIniFile "[MAIN]\nx = hello\n" $ section "MAIN" (field "y")--- Left "Missing field \"y\" in section \"main\""+-- Left "Missing field \"y\" in section \"MAIN\"" field :: Text -> SectionParser Text field name = SectionParser $ vValue `fmap` rawField name @@ -173,7 +173,7 @@ -- fail. -- -- >>> parseIniFile "[MAIN]\nx = 72\n" $ section "MAIN" (fieldMbOf "x" number)--- Right 72+-- Right (Just 72) -- >>> parseIniFile "[MAIN]\nx = hello\n" $ section "MAIN" (fieldMbOf "x" number) -- Left "Line 2, in section \"MAIN\": Unable to parse \"hello\" as a value of type Integer" -- >>> parseIniFile "[MAIN]\nx = 72\n" $ section "MAIN" (fieldMbOf "y" number)@@ -226,7 +226,7 @@ -- >>> parseIniFile "[MAIN]\nx = yes\n" $ section "MAIN" (fieldFlag "x") -- Right True -- >>> parseIniFile "[MAIN]\nx = yes\n" $ section "MAIN" (fieldFlag "y")--- Left "Missing field \"y\" in section \"main\""+-- Left "Missing field \"y\" in section \"MAIN\"" fieldFlag :: Text -> SectionParser Bool fieldFlag name = fieldOf name flag @@ -248,7 +248,7 @@ -- with a human-readable error message if reading fails. -- -- >>> readable "(5, 7)" :: Either String (Int, Int)--- Right (5, 7)+-- Right (5,7) -- >>> readable "hello" :: Either String (Int, Int) -- Left "Unable to parse \"hello\" as a value of type (Int,Int)" readable :: forall a. (Read a, Typeable a) => Text -> Either String a@@ -294,7 +294,7 @@ -- >>> flag "F" -- Right False -- >>> flag "That's a secret!"--- Left "Unable to parse \"that's a secret!\" as a boolean"+-- Left "Unable to parse \"That's a secret!\" as a boolean" flag :: Text -> Either String Bool flag s = case T.toLower s of "true" -> Right True@@ -307,6 +307,41 @@ "n" -> Right False _ -> Left ("Unable to parse " ++ show s ++ " as a boolean") ++-- $setup+--+-- >>> :{+-- data NetworkConfig = NetworkConfig+-- { netHost :: String, netPort :: Int }+-- deriving (Eq, Show)+-- >>> :}+--+-- >>> :{+-- data LocalConfig = LocalConfig+-- { localUser :: Text }+-- deriving (Eq, Show)+-- >>> :}+--+-- >>> :{+-- data Config = Config+-- { cfNetwork :: NetworkConfig, cfLocal :: Maybe LocalConfig }+-- deriving (Eq, Show)+-- >>> :}+--+-- >>> :{+-- let configParser = do+-- netCf <- section "NETWORK" $ do+-- host <- fieldOf "host" string+-- port <- fieldOf "port" number+-- return NetworkConfig { netHost = host, netPort = port }+-- locCf <- sectionMb "LOCAL" $+-- LocalConfig <$> field "user"+-- return Config { cfNetwork = netCf, cfLocal = locCf }+-- >>> :}+--+-- >>> :{+-- let example = "[NETWORK]\nhost = example.com\nport = 7878\n\n# here is a comment\n[LOCAL]\nuser = terry\n"+-- >>> :} -- $main -- The 'config-ini' library exports some simple monadic functions to
src/Data/Ini/Config/Raw.hs view
@@ -43,10 +43,13 @@ Right v -> Right v pIni :: Parser Ini-pIni = sBlanks *> (go `fmap` (many (pSection <?> "section") <* eof))- where go vs = Ini $ HM.fromList [ (T.toLower (isName v), v)- | v <- vs- ]+pIni = do+ sBlanks+ vs <- many (pSection <?> "section")+ void eof+ return $ Ini $ HM.fromList [ (T.toLower (isName v), v)+ | v <- vs+ ] sBlanks :: Parser () sBlanks = skipMany (void eol <|> sComment)
+ test/doctest/Main.hs view
@@ -0,0 +1,8 @@+module Main where++import Test.DocTest (doctest)++main :: IO ()+main = do+ doctest [ "src/Data/Ini/Config.hs", "-XOverloadedStrings" ]+ doctest [ "src/Data/Ini/Config/Lens.hs", "-XRankNTypes", "-XOverloadedStrings" ]
test/ini-compat/Main.hs view
@@ -10,8 +10,8 @@ import Test.QuickCheck -iniEquiv :: I1.Ini -> Bool-iniEquiv raw = case (i1, i2) of+iniEquiv :: ArbIni -> Bool+iniEquiv (ArbIni raw) = case (i1, i2) of (Right i1', Right i2') -> let i1'' = lower i1' i2'' = toMaps i2'@@ -28,14 +28,22 @@ toMaps :: I2.Ini -> HashMap Text (HashMap Text Text) toMaps (I2.Ini m) = fmap (fmap I2.vValue . I2.isVals) m -instance Arbitrary I1.Ini where- arbitrary = (I1.Ini . HM.fromList) <$> listOf sections- where sections = (,) <$> str <*> section- str = (T.pack <$> arbitrary) `suchThat` (\ t ->+newtype ArbIni = ArbIni I1.Ini deriving (Show)++instance Arbitrary ArbIni where+ arbitrary = (ArbIni . I1.Ini . HM.fromList) `fmap` listOf sections+ where sections = do+ name <- str+ sec <- section+ return (name, sec)+ str = (T.pack `fmap` arbitrary) `suchThat` (\ t -> T.all (\ c -> isAlphaNum c || c == ' ') t && not (T.null t))- section = HM.fromList <$> listOf kv- kv = (,) <$> str <*> str+ section = HM.fromList `fmap` listOf kv+ kv = do+ name <- str+ val <- str+ return (name, val) main :: IO () main = quickCheck iniEquiv