packages feed

hsini 0.5.1.2 → 0.5.1.3

raw patch · 9 files changed

+283/−268 lines, 9 filesdep +hsinidep ~basedep ~mtlPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependencies added: hsini

Dependency ranges changed: base, mtl

API changes (from Hackage documentation)

+ Data.Ini.Reader.Internals: CommentL :: IniFile
+ Data.Ini.Reader.Internals: IniOtherError :: String -> IniReaderError
+ Data.Ini.Reader.Internals: IniParserError :: String -> IniReaderError
+ Data.Ini.Reader.Internals: IniSyntaxError :: String -> IniReaderError
+ Data.Ini.Reader.Internals: OptionContL :: String -> IniFile
+ Data.Ini.Reader.Internals: OptionL :: String -> String -> IniFile
+ Data.Ini.Reader.Internals: SectionL :: String -> IniFile
+ Data.Ini.Reader.Internals: buildConfig :: [IniFile] -> IniParseResult Config
+ Data.Ini.Reader.Internals: data IniFile
+ Data.Ini.Reader.Internals: data IniReaderError
+ Data.Ini.Reader.Internals: eatWhiteSpace :: Parser String
+ Data.Ini.Reader.Internals: iniParser :: Parser [IniFile]
+ Data.Ini.Reader.Internals: instance GHC.Classes.Eq Data.Ini.Reader.Internals.IniFile
+ Data.Ini.Reader.Internals: instance GHC.Classes.Eq Data.Ini.Reader.Internals.IniReaderError
+ Data.Ini.Reader.Internals: instance GHC.Show.Show Data.Ini.Reader.Internals.IniFile
+ Data.Ini.Reader.Internals: instance GHC.Show.Show Data.Ini.Reader.Internals.IniReaderError
+ Data.Ini.Reader.Internals: noiseParser :: Parser IniFile
+ Data.Ini.Reader.Internals: optContParser :: Parser IniFile
+ Data.Ini.Reader.Internals: optLineParser :: Parser IniFile
+ Data.Ini.Reader.Internals: secParser :: Parser IniFile
+ Data.Ini.Reader.Internals: type IniParseResult = Either IniReaderError

Files

hsini.cabal view
@@ -1,66 +1,56 @@--- This file has been generated from package.yaml by hpack version 0.28.2.------ see: https://github.com/sol/hpack------ hash: 0a9d3d220e23a6165acb4a43a8293ef95e41667b8afd689196d833adad1dba85+cabal-version: 3.0+name:          hsini+version:       0.5.1.3+synopsis:      ini configuration files+description:+  Library for reading and writing configuration files in INI format (see <https://en.wikipedia.org/wiki/INI_file>). -name:           hsini-version:        0.5.1.2-synopsis:       ini configuration files-description:    Library for reading and writing configuration files in INI format (see <https://en.wikipedia.org/wiki/INI_file>).-category:       Configuration, Data-maintainer:     Magnus Therning <magnus@therning.org>-license:        BSD3-license-file:   LICENSE-build-type:     Simple-cabal-version:  >= 1.10-extra-source-files:-    package.yaml-    stack.yaml+category:      Configuration, Data+author:        Magnus Therning <magnus@therning.org>+maintainer:    Magnus Therning <magnus@therning.org>+license:       BSD-3-Clause+license-file:  LICENSE+build-type:    Simple  source-repository head-  type: git+  type:     git   location: https://github.com/magthe/hsini.git  library   exposed-modules:-      Data.Ini-      Data.Ini.Reader-      Data.Ini.Types-  other-modules:-      Data.Ini.Reader.Internals-  hs-source-dirs:-      src+    Data.Ini+    Data.Ini.Reader+    Data.Ini.Reader.Internals+    Data.Ini.Types++  hs-source-dirs:   src   build-depends:-      base <5+    , base        <5     , bytestring     , containers     , mtl     , parsec+   default-language: Haskell2010  test-suite hsini-tests-  type: exitcode-stdio-1.0-  main-is: Main.hs+  type:             exitcode-stdio-1.0+  main-is:          Main.hs   other-modules:-      Ini-      ReaderI-      Data.Ini-      Data.Ini.Reader-      Data.Ini.Reader.Internals-      Data.Ini.Types-      Paths_hsini-  hs-source-dirs:-      tst-      src+    Ini+    ReaderI++  hs-source-dirs:   tst   build-depends:-      base+    , base              <5     , bytestring     , containers+    , hsini     , mtl     , parsec     , tasty     , tasty-hunit     , tasty-quickcheck     , tasty-th+   default-language: Haskell2010
− package.yaml
@@ -1,43 +0,0 @@-name: hsini-version: 0.5.1.2-synopsis: ini configuration files-description: >--  Library for reading and writing configuration files in INI format (see-  <https://en.wikipedia.org/wiki/INI_file>).-maintainer: Magnus Therning <magnus@therning.org>-license: BSD3-category: Configuration, Data-extra-source-files:-  - package.yaml-  - stack.yaml--git: https://github.com/magthe/hsini.git--library:-  source-dirs:-    - src-  dependencies:-    - base <5-    - bytestring-    - containers-    - mtl-    - parsec-  other-modules:-    - Data.Ini.Reader.Internals--tests:-  hsini-tests:-    source-dirs:-      - tst-      - src-    main: Main.hs-    dependencies:-      - base-      - bytestring-      - containers-      - mtl-      - parsec-      - tasty-      - tasty-hunit-      - tasty-quickcheck-      - tasty-th
src/Data/Ini.hs view
@@ -1,14 +1,15 @@--- |--- Module    : Data.Ini--- Copyright : 2011-2014 Magnus Therning--- License   : BSD3------ A representation of configuration options.  It consists of /sections/,--- each which can contain 0 or more /options/.  Each options is a /key/,--- /value/ pair.------ This module contains the API for constructing, manipulating, and querying--- configurations.+{- |+Module    : Data.Ini+Copyright : 2011-2014 Magnus Therning+License   : BSD3++A representation of configuration options.  It consists of /sections/,+each which can contain 0 or more /options/.  Each options is a /key/,+/value/ pair.++This module contains the API for constructing, manipulating, and querying+configurations.+-} module Data.Ini where  -- {{{1 imports@@ -18,11 +19,13 @@ import Data.Ini.Types  -- {{{1 configurations+ -- | Constructs an empty configuration. emptyConfig :: Config emptyConfig = M.empty  -- {{{1 sections+ -- | Returns @True@ iff the configuration has a section with that name. hasSection :: SectionName -> Config -> Bool hasSection = M.member@@ -40,6 +43,7 @@ delSection = M.delete  -- {{{1 options+ -- | Returns @True@ if the names section has the option. hasOption :: SectionName -> OptionName -> Config -> Bool hasOption sn on cfg = isJust $ getSection sn cfg >>= M.lookup on@@ -49,24 +53,25 @@ getOption sn on cfg = getSection sn cfg >>= M.lookup on  -- | Returns a list of all options in the section.-options ::  SectionName -> Config -> [OptionName]+options :: SectionName -> Config -> [OptionName] options sn cfg = maybe [] M.keys (getSection sn cfg)  -- | Sets the value of the option, adding it if it doesn't exist. setOption :: SectionName -> OptionName -> OptionValue -> Config -> Config-setOption sn on ov cfg = maybe (M.insert sn new_s cfg) (\ sec -> M.insert sn (M.insert on ov sec) cfg) s-    where-        s = getSection sn cfg-        new_s = M.insert on ov M.empty+setOption sn on ov cfg = maybe (M.insert sn new_s cfg) (\sec -> M.insert sn (M.insert on ov sec) cfg) s+  where+    s = getSection sn cfg+    new_s = M.insert on ov M.empty  -- | Removes the option if it exists.  Empty sections are pruned. delOption :: SectionName -> OptionName -> Config -> Config-delOption sn on cfg = if sEmptyAfterDelete+delOption sn on cfg =+    if sEmptyAfterDelete         then M.delete sn cfg-        else maybe cfg (\ sec -> M.insert sn (M.delete on sec) cfg) s-    where-        s = getSection sn cfg-        sEmptyAfterDelete = maybe True (\ sec -> M.empty == M.delete on sec) s+        else maybe cfg (\sec -> M.insert sn (M.delete on sec) cfg) s+  where+    s = getSection sn cfg+    sEmptyAfterDelete = maybe True (\sec -> M.empty == M.delete on sec) s  -- | Returns all options and their values of a section. allItems :: SectionName -> Config -> [(OptionName, OptionValue)]
src/Data/Ini/Reader.hs view
@@ -1,25 +1,28 @@--- |--- Module    : Data.Ini.Reader--- Copyright : 2011-2014 Magnus Therning--- License   : BSD3------ Parser for configurations.-module Data.Ini.Reader-    ( parse-    , IniReaderError(..)-    , IniParseResult-    ) where+{- |+Module    : Data.Ini.Reader+Copyright : 2011-2014 Magnus Therning+License   : BSD3 +Parser for configurations.+-}+module Data.Ini.Reader (+    parse,+    IniReaderError (..),+    IniParseResult,+) where+ import Control.Monad.Except import qualified Text.ParserCombinators.Parsec as P -import Data.Ini.Types import Data.Ini.Reader.Internals+import Data.Ini.Types  -- | Parser for a configuration contained in a 'String'. parse :: String -> IniParseResult Config-parse s = let+parse s =+    let         pr = P.parse iniParser "ini" s-    in case pr of-        Left e -> throwError . IniParserError $ show e-        Right is -> buildConfig is+     in+        case pr of+            Left e -> throwError . IniParserError $ show e+            Right is -> buildConfig is
src/Data/Ini/Reader/Internals.hs view
@@ -1,10 +1,12 @@ {-# LANGUAGE FlexibleContexts #-}--- |--- Module    : Data.Ini.Reader.Internals--- Copyright : 2011-2014 Magnus Therning--- License   : BSD3------ Internal functions used in 'Data.Ini.Reader'.++{- |+Module    : Data.Ini.Reader.Internals+Copyright : 2011-2014 Magnus Therning+License   : BSD3++Internal functions used in 'Data.Ini.Reader'.+-} module Data.Ini.Reader.Internals where  import Control.Monad.Except@@ -34,7 +36,8 @@  -- | Build a configuration from a list of 'IniFile' items. buildConfig :: [IniFile] -> IniParseResult Config-buildConfig ifs = let+buildConfig ifs =+    let         isComment CommentL = True         isComment _ = False @@ -43,7 +46,7 @@         -- merge together OptionL and subsequent OptionContL items         mergeOptions [] = return []         mergeOptions (s@(SectionL _) : ifs) = (s :) `liftM` mergeOptions ifs-        mergeOptions (CommentL : ifs ) = (CommentL :) `liftM` mergeOptions ifs+        mergeOptions (CommentL : ifs) = (CommentL :) `liftM` mergeOptions ifs         mergeOptions (OptionL on ov : OptionContL ov2 : ifs) = mergeOptions $ (OptionL on (ov ++ ov2)) : ifs         mergeOptions (o@(OptionL on ov) : ifs) = (o :) `liftM` mergeOptions ifs         mergeOptions _ = throwError $ IniSyntaxError "Syntax error in INI file."@@ -55,65 +58,75 @@             sn <- get             let na = setOption sn on ov a             buildit na is--    in mergeOptions fIfs >>= (\ is -> return . fst $ runState (buildit emptyConfig is) "default")+     in+        mergeOptions fIfs >>= (\is -> return . fst $ runState (buildit emptyConfig is) "default")  -- | Consumer of whitespace \"@ \t@\". eatWhiteSpace :: Parser String eatWhiteSpace = many $ oneOf " \t" --- | Parser for the start-of-section line.  It expects the line to start with a--- @[@ then find the section name, and finally a @]@.  The section name may be--- surrounded by any number of white space characters (see 'eatWhiteSpace').+{- | Parser for the start-of-section line.  It expects the line to start with a+@[@ then find the section name, and finally a @]@.  The section name may be+surrounded by any number of white space characters (see 'eatWhiteSpace').+-} secParser :: Parser IniFile-secParser = let-        validSecNameChrs = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "._-/@\" "-    in do-        char '['-        eatWhiteSpace-        sn <- many1 $ oneOf validSecNameChrs-        eatWhiteSpace-        char ']'-        manyTill anyChar newline-        return $ SectionL sn+secParser =+    let+        validSecNameChrs = ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9'] ++ "._-/@\" "+     in+        do+            char '['+            eatWhiteSpace+            sn <- many1 $ oneOf validSecNameChrs+            eatWhiteSpace+            char ']'+            manyTill anyChar newline+            return $ SectionL sn --- | Parser for a single line of an option.  The line must start with an option--- name, then a @=@ must be found, and finally the rest of the line is taken as--- the option value.  The equal sign may be surrounded by any number of white--- space characters (see 'eatWhiteSpace').+{- | Parser for a single line of an option.  The line must start with an option+name, then a @=@ must be found, and finally the rest of the line is taken as+the option value.  The equal sign may be surrounded by any number of white+space characters (see 'eatWhiteSpace').+-} optLineParser :: Parser IniFile-optLineParser = let-        validOptNameChrs = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "_-/@"-    in do-        on <- many1 $ oneOf validOptNameChrs-        eatWhiteSpace-        char '='-        eatWhiteSpace-        ov <- manyTill anyChar newline-        return $ OptionL on ov+optLineParser =+    let+        validOptNameChrs = ['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9'] ++ "_-/@"+     in+        do+            on <- many1 $ oneOf validOptNameChrs+            eatWhiteSpace+            char '='+            eatWhiteSpace+            ov <- manyTill anyChar newline+            return $ OptionL on ov --- | Parser for an option-value continuation line.  The line must start with--- either a space or a tab character (\"@ \t@\").  Everything else on the line,--- until the newline character, is taken as the continuation of an option--- value.+{- | Parser for an option-value continuation line.  The line must start with+either a space or a tab character (\"@ \t@\").  Everything else on the line,+until the newline character, is taken as the continuation of an option+value.+-} optContParser :: Parser IniFile optContParser = do     oneOf " \t"     eatWhiteSpace     oc <- noneOf " \t"     ov <- manyTill anyChar newline-    return $ OptionContL $ oc:ov+    return $ OptionContL $ oc : ov --- | Parser for "noise" in the configuration file, such as comments and empty--- lines.  (Note that lines containing only space characters will be--- successfully parsed by 'optContParser'.)+{- | Parser for "noise" in the configuration file, such as comments and empty+lines.  (Note that lines containing only space characters will be+successfully parsed by 'optContParser'.)+-} noiseParser :: Parser IniFile-noiseParser = let+noiseParser =+    let         commentP = do             oneOf "#;"             manyTill anyChar newline         emptyL = newline >> return ""-    in choice [commentP, emptyL] >> return CommentL+     in+        choice [commentP, emptyL] >> return CommentL  iniParser :: Parser [IniFile] iniParser =
src/Data/Ini/Types.hs view
@@ -1,11 +1,12 @@--- |--- Module    : Data.Ini.Types--- Copyright : 2011-2014 Magnus Therning--- License   : BSD3+{- |+Module    : Data.Ini.Types+Copyright : 2011-2014 Magnus Therning+License   : BSD3+-} module Data.Ini.Types where -import qualified Data.Map as M import Control.Arrow (second)+import qualified Data.Map as M  type Config = M.Map SectionName Section 
− stack.yaml
@@ -1,10 +0,0 @@-resolver: lts-11.11--packages:-  - '.'--extra-deps: []--flags: {}--extra-package-dbs: []
tst/Ini.hs view
@@ -1,9 +1,10 @@-{-# OPTIONS_GHC -XTemplateHaskell #-}+{-# LANGUAGE TemplateHaskell #-}+ -- Copyright : 2011-2014 Magnus Therning -- License   : BSD3-module Ini-    ( allTests-    ) where+module Ini (+    allTests,+) where  -- {{{1 imports import Data.Maybe@@ -18,54 +19,58 @@ -- adding and then deleting a section is a no-op (if the section doesn't exist -- already) prop_secAddDel sn cfglst = delSection sn (setOption sn "foo" "bar" cfg2) == cfg2-    where-        cfg = cfgFromList cfglst-        cfg2 = delSection sn cfg -- must make sure the section doesn't exist before adding+  where+    cfg = cfgFromList cfglst+    cfg2 = delSection sn cfg -- must make sure the section doesn't exist before adding  -- after adding a section the config has such a section prop_secAddHas sn cfglst = hasSection sn (setOption sn "foo" "bar" cfg)-    where cfg = cfgFromList cfglst+  where+    cfg = cfgFromList cfglst  -- after adding a section it's possible to get it prop_secAddGet sn cfglst = isJust $ getSection sn (setOption sn "foo" "bar" cfg)-    where cfg = cfgFromList cfglst+  where+    cfg = cfgFromList cfglst  -- after deleting a section it's gone prop_secDelGet sn cfglst = isNothing $ getSection sn $ delSection sn cfg2-    where-        cfg = cfgFromList cfglst-        cfg2 = setOption sn "foo" "bar" cfg+  where+    cfg = cfgFromList cfglst+    cfg2 = setOption sn "foo" "bar" cfg  -- {{{1 option properties -- setting and then deleting an option is a no-op (if the option doesn't exist -- already) prop_optSetDel sn on ov cfglst = delOption sn on (setOption sn on ov cfg) == cfg2-    where-        cfg = cfgFromList cfglst-        cfg2 = delOption sn on cfg+  where+    cfg = cfgFromList cfglst+    cfg2 = delOption sn on cfg  -- after setting an option it's there prop_optSetHas sn on ov cfglst = hasOption sn on (setOption sn on ov cfg)-    where cfg = cfgFromList cfglst+  where+    cfg = cfgFromList cfglst  -- after setting an option it's possible to get it prop_optSetGet sn on ov cfglst = isJust $ getOption sn on $ setOption sn on ov cfg-    where cfg = cfgFromList cfglst+  where+    cfg = cfgFromList cfglst  -- after deleting a section it's gone prop_optDelGet sn on ov cfglst = isNothing $ getOption sn on $ delOption sn on cfg2-    where-        cfg = cfgFromList cfglst-        cfg2 = setOption sn on ov cfg+  where+    cfg = cfgFromList cfglst+    cfg2 = setOption sn on ov cfg  -- getting all items-prop_optAllItems cfglst = (length _cfglst > 0) ==> lstItems == (allItems sn cfg)-    where-        cfg = cfgFromList cfglst-        _cfglst = cfgToList cfg-        -- sn = head . sort $ map fst _cfglst-        sn = head $ map fst _cfglst-        lstItems = fromJust $ lookup sn _cfglst+prop_optAllItems cfglst = not (null _cfglst) ==> lstItems == allItems sn cfg+  where+    cfg = cfgFromList cfglst+    _cfglst = cfgToList cfg+    -- sn = head . sort $ map fst _cfglst+    sn = head $ map fst _cfglst+    lstItems = fromJust $ lookup sn _cfglst  -- {{{1 allTests allTests :: TestTree
tst/ReaderI.hs view
@@ -1,10 +1,11 @@ {-# LANGUAGE FlexibleContexts #-}-{-# OPTIONS_GHC -XTemplateHaskell #-}+{-# LANGUAGE TemplateHaskell #-}+ -- Copyright : 2011-2014 Magnus Therning -- License   : BSD3-module ReaderI-    (allTests-    ) where+module ReaderI (+    allTests,+) where  import Test.Tasty import Test.Tasty.HUnit@@ -15,142 +16,192 @@  -- Convenience function that translates a parser result to something that's -- easier to check.-p2E p s t = let+p2E p s t =+    let         res = P.parse p s t-    in case res of-        Left _ -> Left "bad"-        Right e -> Right e+     in+        case res of+            Left _ -> Left "bad"+            Right e -> Right e  -- {{{1 secParser-case_secParserAllowedChars1 = let+case_secParserAllowedChars1 =+    let         expected = Right $ SectionL "foo"         actual = p2E secParser "sec" "[foo]\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserAllowedChars2 = let+case_secParserAllowedChars2 =+    let         expected = Right $ SectionL "FooBar"         actual = p2E secParser "sec" "[FooBar]\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserAllowedChars3 = let+case_secParserAllowedChars3 =+    let         expected = Right $ SectionL "@Foo/Bar-"         actual = p2E secParser "sec" "[@Foo/Bar-]\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserAllowedChars4 = let+case_secParserAllowedChars4 =+    let         expected = Right $ SectionL "foo123"         actual = p2E secParser "sec" "[foo123]\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserAllowedChars5 = let+case_secParserAllowedChars5 =+    let         expected = Right $ SectionL "_foo"         actual = p2E secParser "sec" "[_foo]\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserDropSpace = let+case_secParserDropSpace =+    let         expected = Right $ SectionL "foo"         actual = p2E secParser "sec" "[ \tfoo\t ]\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserDropTrailing = let+case_secParserDropTrailing =+    let         expected = Right $ SectionL "foo"         actual = p2E secParser "sec" "[foo]  \t foobar\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserAllowGit1 = let+case_secParserAllowGit1 =+    let         expected = Right $ SectionL "branch \"master\""         actual = p2E secParser "sec" "[branch \"master\"]\n"-    in expected @=? actual+     in+        expected @=? actual -case_secParserAllowGit2 = let+case_secParserAllowGit2 =+    let         expected = Right $ SectionL "foo \"bar.baz\""         actual = p2E secParser "sec" "[foo \"bar.baz\"]\n"-    in expected @=? actual+     in+        expected @=? actual  -- {{{1 optLineParser-case_optLineParserAllowedChars1 = let+case_optLineParserAllowedChars1 =+    let         expected = Right $ OptionL "foo" "bar"         actual = p2E optLineParser "optLine" "foo=bar\n"-    in expected @=? actual+     in+        expected @=? actual -case_optLineParserAllowedChars2 = let+case_optLineParserAllowedChars2 =+    let         expected = Right $ OptionL "Foo" "bAr"         actual = p2E optLineParser "optLine" "Foo=bAr\n"-    in expected @=? actual+     in+        expected @=? actual -case_optLineParserAllowedChars3 = let+case_optLineParserAllowedChars3 =+    let         expected = Right $ OptionL "foo@/foo-" "bar"         actual = p2E optLineParser "optLine" "foo@/foo-=bar\n"-    in expected @=? actual+     in+        expected @=? actual -case_optLineParserAllowedChars4 = let+case_optLineParserAllowedChars4 =+    let         expected = Right $ OptionL "foo123" "bar"         actual = p2E optLineParser "optLine" "foo123=bar\n"-    in expected @=? actual+     in+        expected @=? actual -case_optLineParserAllowedChars5 = let+case_optLineParserAllowedChars5 =+    let         expected = Right $ OptionL "_foo" "bar"         actual = p2E optLineParser "optLine" "_foo=bar\n"-    in expected @=? actual+     in+        expected @=? actual -case_optLineParserDisallowedChars1 = let+case_optLineParserDisallowedChars1 =+    let         expected = Left "bad"         actual = p2E optLineParser "optLine" "foo.bar=baz\n"-    in expected @=? actual+     in+        expected @=? actual -case_optLineParserDropSpace = let+case_optLineParserDropSpace =+    let         expected = Right $ OptionL "foo" "bar"         actual = p2E optLineParser "optLine" "foo\t \t=\t \t bar\n"-    in expected @=? actual+     in+        expected @=? actual -case_optLineParserKeepSpace = let+case_optLineParserKeepSpace =+    let         expected = Right $ OptionL "foo" "bar \t \t"         actual = p2E optLineParser "optLine" "foo\t \t=\t \t bar \t \t\n"-    in expected @=? actual+     in+        expected @=? actual  -- {{{1 optContParser-case_optContParserSpace = let+case_optContParserSpace =+    let         expected = Right $ OptionContL "foo"         actual = p2E optContParser "optCont" " foo\n"-    in expected @=? actual+     in+        expected @=? actual -case_optContParserTab = let-        expected = Right $OptionContL "foo"+case_optContParserTab =+    let+        expected = Right $ OptionContL "foo"         actual = p2E optContParser "optCont" "\tfoo\n"-    in expected @=? actual+     in+        expected @=? actual -case_optContParserKeepTrailing = let+case_optContParserKeepTrailing =+    let         expected = Right $ OptionContL "foo  \t\t"         actual = p2E optContParser "optCont" "\tfoo  \t\t\n"-    in expected @=? actual+     in+        expected @=? actual  -- {{{1 noiseParser-case_noiseParserEmptyLine = let+case_noiseParserEmptyLine =+    let         expected = Right CommentL         actual = p2E noiseParser "noise" "\n"-    in expected @=? actual+     in+        expected @=? actual -case_noiseParserComment1 = let+case_noiseParserComment1 =+    let         expected = Right CommentL         actual = p2E noiseParser "noise" "# a comment\n"-    in expected @=? actual+     in+        expected @=? actual -case_noiseParserComment2 = let+case_noiseParserComment2 =+    let         expected = Right CommentL         actual = p2E noiseParser "noise" "; another comment\n"-    in expected @=? actual+     in+        expected @=? actual -case_noiseParserNonEmpty = let+case_noiseParserNonEmpty =+    let         expected = Left "bad"         actual = p2E noiseParser "noise" " \n"-    in expected @=? actual+     in+        expected @=? actual  -- {{{1 iniParser case_iniParserEmpty :: Assertion case_iniParserEmpty = expected @=? actual-    where-        expected = Right []-        actual = p2E iniParser "parsing empty file" ""+  where+    expected = Right []+    actual = p2E iniParser "parsing empty file" ""  -- {{{1 buildConfig -- TBD