config-ini 0.2.1.1 → 0.2.2.0
raw patch · 3 files changed
+82/−8 lines, 3 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Data.Ini.Config: sectionOf :: (Text -> Maybe b) -> (b -> SectionParser a) -> IniParser a
+ Data.Ini.Config: sections :: Text -> SectionParser a -> IniParser (Seq a)
+ Data.Ini.Config: sectionsOf :: (Text -> Maybe b) -> (b -> SectionParser a) -> IniParser (Seq a)
- Data.Ini.Config.Bidir: (&) :: a -> (a -> b) -> b
+ Data.Ini.Config.Bidir: (&) :: () => a -> (a -> b) -> b
Files
- CHANGELOG.md +7/−0
- config-ini.cabal +7/−3
- src/Data/Ini/Config.hs +68/−5
CHANGELOG.md view
@@ -1,3 +1,10 @@+0.2.2.0+=======++- Added `sections`, `sectionOf`, and `sectionsOf` helpers to the+ vanilla API for more flexibility in working with section names+- Put `test-doctest` behind a flag, which is disabled by default+ 0.2.1.1 =======
config-ini.cabal view
@@ -1,5 +1,5 @@ name: config-ini-version: 0.2.1.1+version: 0.2.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@@ -18,7 +18,7 @@ license-file: LICENSE author: Getty Ritter <config-ini@infinitenegativeutility.com> maintainer: Getty Ritter <config-ini@infinitenegativeutility.com>-copyright: ©2017 Getty Ritter+copyright: ©2018 Getty Ritter category: Configuration build-type: Simple cabal-version: >= 1.18@@ -33,6 +33,10 @@ type: git location: git://github.com/aisamanra/config-ini.git +flag enable-doctests+ description: Build doctest modules as well (can be finicky)+ default: False+ library hs-source-dirs: src exposed-modules: Data.Ini.Config@@ -75,7 +79,7 @@ , directory test-suite test-doctest- if impl(ghc < 7.10)+ if impl(ghc < 7.10) || !flag(enable-doctests) buildable: False type: exitcode-stdio-1.0 ghc-options: -Wall
src/Data/Ini/Config.hs view
@@ -12,7 +12,7 @@ For example, the following INI file has two sections, @NETWORK@ and @LOCAL@, and each contains its own key-value pairs. Comments, which begin with @#@ or @;@, are ignored:---+ > [NETWORK] > host = example.com > port = 7878@@ -20,7 +20,7 @@ > # here is a comment > [LOCAL] > user = terry---+ The combinators provided here are designed to write quick and idiomatic parsers for files of this form. Sections are parsed by 'IniParser' computations, like 'section' and its variations,@@ -28,7 +28,7 @@ computations, like 'field' and its variations. If we want to parse an INI file like the one above, treating the entire @LOCAL@ section as optional, we can write it like this:---+ > data Config = Config > { cfNetwork :: NetworkConfig, cfLocal :: Maybe LocalConfig } > deriving (Eq, Show)@@ -50,11 +50,12 @@ > locCf <- sectionMb "LOCAL" $ > LocalConfig <$> field "user" > return Config { cfNetwork = netCf, cfLocal = locCf }---++ We can run our computation with 'parseIniFile', which, when run on our example file above, would produce the following:---+ >>> parseIniFile example configParser Right (Config {cfNetwork = NetworkConfig {netHost = "example.com", netPort = 7878}, cfLocal = Just (LocalConfig {localUser = "terry"})}) @@ -73,6 +74,9 @@ , SectionParser -- * Section-Level Parsing , section+, sections+, sectionOf+, sectionsOf , sectionMb , sectionDef -- * Field-Level Parsing@@ -149,6 +153,65 @@ case lkp (normalize name) ini of Nothing -> Left ("No top-level section named " ++ show name) Just sec -> runExceptT thunk sec++-- | Find multiple named sections in the INI file and parse them all+-- with the provided section parser. In order to support classic INI+-- files with capitalized section names, section lookup is+-- __case-insensitive__.+--+-- >>> parseIniFile "[ONE]\nx = hello\n[ONE]\nx = goodbye\n" $ sections "ONE" (field "x")+-- Right (fromList ["hello","goodbye"])+-- >>> parseIniFile "[ONE]\nx = hello\n" $ sections "TWO" (field "x")+-- Right (fromList [])+sections :: Text -> SectionParser a -> IniParser (Seq a)+sections name (SectionParser thunk) = IniParser $ ExceptT $ \(RawIni ini) ->+ let name' = normalize name+ in mapM (runExceptT thunk . snd)+ (Seq.filter (\ (t, _) -> t == name') ini)++-- | A call to @sectionOf f@ will apply @f@ to each section name and,+-- if @f@ produces a "Just" value, pass the extracted value in order+-- to get the "SectionParser" to use for that section. This will+-- find at most one section, and will produce an error if no section+-- exists.+--+-- >>> parseIniFile "[FOO]\nx = hello\n" $ sectionOf (T.stripSuffix "OO") (\ l -> fmap ((,) l) (field "x"))+-- Right ("F","hello")+-- >>> parseIniFile "[BAR]\nx = hello\n" $ sectionOf (T.stripSuffix "OO") (\ l -> fmap ((,) l) (field "x"))+-- Left "No matching top-level section"+sectionOf :: (Text -> Maybe b) -> (b -> SectionParser a) -> IniParser a+sectionOf fn sectionParser = IniParser $ ExceptT $ \(RawIni ini) ->+ let go Seq.EmptyL = Left "No matching top-level section"+ go ((t, sec) Seq.:< rs)+ | Just v <- fn (actualText t) =+ let SectionParser thunk = sectionParser v+ in runExceptT thunk sec+ | otherwise = go (Seq.viewl rs)+ in go (Seq.viewl ini)+++-- | A call to @sectionsOf f@ will apply @f@ to each section name and,+-- if @f@ produces a @Just@ value, pass the extracted value in order+-- to get the "SectionParser" to use for that section. This will+-- return every section for which the call to @f@ produces a "Just"+-- value.+--+-- >>> parseIniFile "[FOO]\nx = hello\n[BOO]\nx = goodbye\n" $ sectionsOf (T.stripSuffix "OO") (\ l -> fmap ((,) l) (field "x"))+-- Right (fromList [("F","hello"),("B","goodbye")])+-- >>> parseIniFile "[BAR]\nx = hello\n" $ sectionsOf (T.stripSuffix "OO") (\ l -> fmap ((,) l) (field "x"))+-- Right (fromList [])+sectionsOf :: (Text -> Maybe b) -> (b -> SectionParser a) -> IniParser (Seq a)+sectionsOf fn sectionParser = IniParser $ ExceptT $ \(RawIni ini) ->+ let go Seq.EmptyL = return Seq.empty+ go ((t, sec) Seq.:< rs)+ | Just v <- fn (actualText t) =+ let SectionParser thunk = sectionParser v+ in do+ x <- runExceptT thunk sec+ xs <- go (Seq.viewl rs)+ return (x Seq.<| xs)+ | otherwise = go (Seq.viewl rs)+ in go (Seq.viewl ini) -- | Find a named section in the INI file and parse it with the provided -- section parser, returning 'Nothing' if the section does not exist.