packages feed

app-settings 0.2.0.5 → 0.2.0.6

raw patch · 5 files changed

+240/−241 lines, 5 filesdep ~HUnitdep ~hspecPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: HUnit, hspec

API changes (from Hackage documentation)

- Data.AppSettings: instance Show GetSetting
+ Data.AppSettings: instance GHC.Show.Show Data.AppSettings.GetSetting
- Data.AppSettings: getSetting' :: Read a => Conf -> Setting a -> a
+ Data.AppSettings: getSetting' :: (Read a) => Conf -> Setting a -> a
- Data.AppSettings: setSetting :: Show a => Conf -> Setting a -> a -> Conf
+ Data.AppSettings: setSetting :: (Show a) => Conf -> Setting a -> a -> Conf
- Data.AppSettings: setting :: Show a => Setting a -> State Conf ()
+ Data.AppSettings: setting :: (Show a) => Setting a -> State Conf ()

Files

Data/AppSettings.hs view
@@ -1,20 +1,20 @@ {-# LANGUAGE RankNTypes, GADTs #-}  module Data.AppSettings (-	-- $intro-	Conf,-	DefaultConfig(..),-	Setting(..),-	GetSetting(..),-	setting,-	getDefaultConfig,-	emptyDefaultConfig,-	FileLocation(..),-	readSettings,-	ParseException,-	saveSettings,-	setSetting,-	getSetting') where+    -- $intro+    Conf,+    DefaultConfig(..),+    Setting(..),+    GetSetting(..),+    setting,+    getDefaultConfig,+    emptyDefaultConfig,+    FileLocation(..),+    readSettings,+    ParseException,+    saveSettings,+    setSetting,+    getSetting') where  import System.Directory import qualified Data.Map as M@@ -29,7 +29,7 @@  -- for the tests... instance Show GetSetting where-	show _ = "GetSetting"+    show _ = "GetSetting"  -- | Information about the default configuration. Contains -- all the settings (that you declare using 'getDefaultConfig')@@ -68,15 +68,15 @@  -- | Where to look for or store the configuration file. data FileLocation = AutoFromAppName String-		    -- ^ Automatically build the location based on the-		    -- application name. It will be ~\/.\<app name\>\/config.ini.-		  | Path FilePath-		    -- ^ Absolute path to a location on disk.+            -- ^ Automatically build the location based on the+            -- application name. It will be ~\/.\<app name\>\/config.ini.+          | Path FilePath+            -- ^ Absolute path to a location on disk.  getPathForLocation :: FileLocation -> IO FilePath getPathForLocation location = case location of-	AutoFromAppName appName -> getConfigFileName appName-	Path path -> return path+    AutoFromAppName appName -> getConfigFileName appName+    Path path -> return path  -- | Read settings from disk. -- Because it is doing file I/O it is smart to wrap the call@@ -105,26 +105,26 @@ -- @ -- readResult <- try $ readSettings (Path \"my.config\") -- case readResult of--- 	Right (conf, GetSetting getSetting) -> do--- 		let textSize = getSetting fontSize--- 		saveSettings emptyDefaultConfig (Path \"my.config\") conf--- 	Left (x :: SomeException) -> error \"Error reading the config file!\"+--  Right (conf, GetSetting getSetting) -> do+--      let textSize = getSetting fontSize+--      saveSettings emptyDefaultConfig (Path \"my.config\") conf+--  Left (x :: SomeException) -> error \"Error reading the config file!\" -- @ readSettings :: FileLocation -> IO (Conf, GetSetting) readSettings location = do-	filePath <- getPathForLocation location-	exists <- doesFileExist filePath-	conf <- if exists-		then readConfigFile filePath-		else return M.empty-	return (conf, GetSetting $ getSetting' conf)+    filePath <- getPathForLocation location+    exists <- doesFileExist filePath+    conf <- if exists+        then readConfigFile filePath+        else return M.empty+    return (conf, GetSetting $ getSetting' conf)  -- | It is advised to run the save within a try call -- because it does disk I/O, otherwise the call is straightforward. saveSettings :: DefaultConfig -> FileLocation -> Conf -> IO () saveSettings (DefaultConfig defaults) location conf = do-	filePath <- getPathForLocation location-	writeConfigFile filePath (conf `M.union` defaults)+    filePath <- getPathForLocation location+    writeConfigFile filePath (conf `M.union` defaults)  -- | Change the value of a setting. You'll have to call -- 'saveSettings' so that the change is written to disk.@@ -132,25 +132,25 @@ setSetting conf (Setting key _) v = M.insert key SettingInfo { value = show v, userSet=True } conf -- an empty list for the XX list key is written as XX= in the config file. setSetting conf (ListSetting key _) [] = M.insert key SettingInfo { value = "", userSet= True}-	$ cleanListSetting key conf+    $ cleanListSetting key conf setSetting conf (ListSetting key _) elts = addListSettings True key elts 1-	$ cleanListSetting key conf+    $ cleanListSetting key conf  addListSettings :: Show b => Bool -> String -> [b] -> Int -> Conf -> Conf addListSettings _ _ [] _ = id addListSettings uset key (x:xs) index = M.insert keyForIndex SettingInfo { value = show x, userSet=uset }-		. addListSettings uset key xs (index+1)-	where keyForIndex = key ++ "_" ++ show index+        . addListSettings uset key xs (index+1)+    where keyForIndex = key ++ "_" ++ show index  cleanListSetting :: String -> Conf -> Conf cleanListSetting key = M.filterWithKey (\k _ -> not $ isKeyForListSetting key k)  getSettingsFolder :: String -> IO FilePath getSettingsFolder appName = do-	home <- getHomeDirectory-	let result = home ++ "/." ++ appName ++ "/"-	createDirectoryIfMissing False result-	return result+    home <- getHomeDirectory+    let result = home ++ "/." ++ appName ++ "/"+    createDirectoryIfMissing False result+    return result  getConfigFileName :: String -> IO String getConfigFileName appName = (++"config.ini") <$> getSettingsFolder appName@@ -161,7 +161,7 @@ -- This library deals with read-write application settings. -- You will have to specify the settings that your application -- uses, their name, types and default values.--- Setting types must implement the 'Read' and 'Show' typeclasses. +-- Setting types must implement the 'Read' and 'Show' typeclasses. -- -- The settings are saved in a file in an INI-like key-value format -- (without sections).@@ -175,10 +175,10 @@ -- -- > fontSize :: Setting Double -- > fontSize = Setting "fontSize" 14--- > +-- > -- > dateFormat :: Setting String -- > dateFormat = Setting "dateFormat" "%x"--- > +-- > -- > backgroundColor :: Setting (Int, Int, Int) -- > backgroundColor = Setting "backcolor" (255, 0, 0) --@@ -249,13 +249,13 @@ -- -- > readResult <- try $ readSettings (AutoFromAppName "test") -- > case readResult of--- > 	Right (conf, GetSetting getSetting) -> do--- > 		let textSize = getSetting fontSize--- > 		saveSettings emptyDefaultConfig (AutoFromAppName "test") conf--- > 	Left (x :: SomeException) -> error "Error reading the config file!"+-- >    Right (conf, GetSetting getSetting) -> do+-- >        let textSize = getSetting fontSize+-- >        saveSettings emptyDefaultConfig (AutoFromAppName "test") conf+-- >    Left (x :: SomeException) -> error "Error reading the config file!" -- -- 'AutoFromAppName' specifies where to save the configuration file.--- And we've already covered the getSetting in this snippet, see +-- And we've already covered the getSetting in this snippet, see -- the 'readSettings' documentation for further information.--- +-- -- You can also look at the tests of the library on the github project for sample use.
Data/AppSettingsInternal.hs view
@@ -54,13 +54,13 @@ -- -- > testList= data Setting a where-	Setting :: String -> a -> Setting a+    Setting :: String -> a -> Setting a -	ListSetting :: (Read a, Show a) => String -> [a] -> Setting [a]+    ListSetting :: (Read a, Show a) => String -> [a] -> Setting [a]  isKeyForListSetting :: String -> String -> Bool isKeyForListSetting settingKey key = (settingKey ++ "_") `isPrefixOf` key-	&& all isDigit (drop (length settingKey+1) key)+    && all isDigit (drop (length settingKey+1) key)   -- TODO maybe another getSetting that'll tell you@@ -74,19 +74,19 @@ getSetting' :: (Read a) => Conf -> Setting a -> a getSetting' conf (Setting key defaultV) = fromMaybe defaultV $ getSettingValueFromConf conf key getSetting' conf (ListSetting key defaultV) = case getSettingValueFromConf conf $ key ++ "_1" of-	-- an empty list for the XX list key is written as XX= in the config file.-	Nothing -> case M.lookup key conf of-		Nothing -> defaultV-		_ -> []-	Just x -> x : decodeListSetting conf key 2+    -- an empty list for the XX list key is written as XX= in the config file.+    Nothing -> case M.lookup key conf of+        Nothing -> defaultV+        _       -> []+    Just x -> x : decodeListSetting conf key 2  getSettingValueFromConf :: Read a => Conf -> String -> Maybe a getSettingValueFromConf conf key = do-	asString <- M.lookup key conf-	readMaybe $ value asString+    asString <- M.lookup key conf+    readMaybe $ value asString  decodeListSetting  :: Read a => Conf -> String -> Int -> [a] decodeListSetting conf key index = case getSettingValueFromConf conf fullKey of-		Nothing -> []-		Just v -> v:decodeListSetting conf key (index+1)-	where fullKey = key ++ "_" ++ show index+        Nothing -> []+        Just v  -> v:decodeListSetting conf key (index+1)+    where fullKey = key ++ "_" ++ show index
Data/Serialization.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# OPTIONS_GHC -fno-warn-unused-do-bind #-} module Data.Serialization (-	Conf,-	SettingInfo(..),-	readConfigFile,-	writeConfigFile,-	ParseException) where+    Conf,+    SettingInfo(..),+    readConfigFile,+    writeConfigFile,+    ParseException) where  import System.IO import qualified Data.Text.IO as T@@ -26,19 +26,18 @@  -- | The configuration file is in an invalid format. data ParseException = ParseException FilePath String-	deriving (Show, Typeable)+    deriving (Show, Typeable) instance Exception ParseException  readConfigFile :: FilePath -> IO Conf readConfigFile path = do-	contents <- T.readFile path-	case parse parseConfigFile "" contents of-		Left pe -> throwIO (ParseException path-			$ "Invalid configuration file " ++ show (errorPos pe))-		Right v -> return v+    contents <- T.readFile path+    case parse parseConfigFile "" contents of+        Left pe -> throwIO (ParseException path+            $ "Invalid configuration file " ++ show (errorPos pe))+        Right v -> return v -data ConfigElement = ConfigEntry String String-	| Comment+data ConfigElement = ConfigEntry String String | Comment  isConfigEntry :: ConfigElement -> Bool isConfigEntry (ConfigEntry _ _) = True@@ -46,65 +45,65 @@  parseConfigFile :: T.GenParser st Conf parseConfigFile = do-	elements <- many $ comment <|> configEntry <|> emptyLine-	let configEntries = filter isConfigEntry elements-	return $ M.fromList $ map (\(ConfigEntry a b) ->-		(a, SettingInfo {value=b, userSet=True})) configEntries+    elements <- many $ comment <|> configEntry <|> emptyLine+    let configEntries = filter isConfigEntry elements+    return $ M.fromList $ map (\(ConfigEntry a b) ->+        (a, SettingInfo {value=b, userSet=True})) configEntries  comment :: T.GenParser st ConfigElement comment = char '#' >> finishLine >> return Comment  configEntry :: T.GenParser st ConfigElement configEntry = do-	key <- many1 $ noneOf " \t=\r\n"-	char '='-	val <- finishLine-	-- so now we finished the parsing of the classical-	-- key=value, however we support a little bit more,-	-- you can do something like that:-	-- key=[1,2,-	--  3,4,-	--  5, 6]-	-- In that case the value will be-	--  "[1,2,3,4,5, 6]"-	--  => we can continue a setting on the next-	--  line if that lines starts with a leading space.-	blank <- optionMaybe $ string " "-	fullVal <- if isNothing blank-		then return val-		else do-			firstExtraLine <- finishLine-			rest <- concat <$> many (string " " >> finishLine)-			return $ val ++ firstExtraLine ++ rest-	return $ ConfigEntry key fullVal+    key <- many1 $ noneOf " \t=\r\n"+    char '='+    val <- finishLine+    -- so now we finished the parsing of the classical+    -- key=value, however we support a little bit more,+    -- you can do something like that:+    -- key=[1,2,+    --  3,4,+    --  5, 6]+    -- In that case the value will be+    --  "[1,2,3,4,5, 6]"+    --  => we can continue a setting on the next+    --  line if that lines starts with a leading space.+    blank   <- optionMaybe $ string " "+    fullVal <- if isNothing blank+        then return val+        else do+            firstExtraLine <- finishLine+            rest <- concat <$> many (string " " >> finishLine)+            return $ val ++ firstExtraLine ++ rest+    return $ ConfigEntry key fullVal  finishLine :: T.GenParser st String finishLine = do-	result <- many $ noneOf "\r\n"-	many1 $ oneOf "\r\n"-	return result+    result <- many $ noneOf "\r\n"+    many1 $ oneOf "\r\n"+    return result  emptyLine :: T.GenParser st ConfigElement emptyLine = do-	many1 $ oneOf "\r\n"-	return Comment+    many1 $ oneOf "\r\n"+    return Comment  writeConfigFile :: FilePath -> Conf -> IO () writeConfigFile path config = do-	whenM (doesFileExist path) $-		copyFile path $ path ++ ".bak"-	withFile path WriteMode $ \handle -> do-		hPutStrLn handle "# This file is autogenerated. You can change, comment and uncomment settings but text comments you may add will be lost."-		mapM_ (uncurry $ writeConfigEntry handle) $ M.toList config-	where whenM s r = s >>= flip when r+    whenM (doesFileExist path) $+        copyFile path $ path ++ ".bak"+    withFile path WriteMode $ \handle -> do+        hPutStrLn handle "# This file is autogenerated. You can change, comment and uncomment settings but text comments you may add will be lost."+        mapM_ (uncurry $ writeConfigEntry handle) $ M.toList config+    where whenM s r = s >>= flip when r  writeConfigEntry :: Handle -> String -> SettingInfo -> IO () writeConfigEntry handle key (SettingInfo sValue sUserSet) = do-	unless sUserSet $ hPutStr handle "# "-	hPutStrLn handle $ key ++ "=" ++ (wrap sValue)+    unless sUserSet $ hPutStr handle "# "+    hPutStrLn handle $ key ++ "=" ++ wrap sValue  wrap :: String -> String wrap str = if null rest-		then str-		else first ++ "\n " ++ wrap rest-	where (first, rest) = splitAt 80 str+        then str+        else first ++ "\n " ++ wrap rest+    where (first, rest) = splitAt 80 str
app-settings.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                app-settings-version:             0.2.0.5+version:             0.2.0.6 synopsis:            A library to manage application settings (INI file-like) description:            A library to deal with application settings.@@ -128,8 +128,8 @@   main-is: Tests.hs   default-language:    Haskell2010   build-depends:       base,-                       hspec >= 1.8 && <1.11,-                       HUnit >= 1.2 && <1.3,+                       hspec,+                       HUnit >= 1.2 && <1.4,                        mtl >= 2.1 && <2.3,                        containers == 0.5.*,                        directory == 1.2.*,
tests/Tests.hs view
@@ -26,180 +26,180 @@  defaultConfig :: DefaultConfig defaultConfig = getDefaultConfig $ do-	setting textSizeFromWidth-	setting textSizeFromHeight-	setting textFill-	setting testInlineList-	setting testList+    setting textSizeFromWidth+    setting textSizeFromHeight+    setting textFill+    setting testInlineList+    setting testList  main :: IO () main = hspec $ do-	describe "unit tests" testIsKeyForListSetting-	describe "load config" $ do-		testEmptyFileDefaults-		testPartialFileDefaults-		testPartialFileDefaults2-		testFileWithComments-		testInvalidFile-		testInvalidValue-		testNonExistingFile-		testReadLongSetting-	describe "save config" $ do-		testSaveUserSetAndDefaults-		createBakBeforeSaving-		wrapLongSettings-	describe "set setting" testSetListSetting+    describe "unit tests" testIsKeyForListSetting+    describe "load config" $ do+        testEmptyFileDefaults+        testPartialFileDefaults+        testPartialFileDefaults2+        testFileWithComments+        testInvalidFile+        testInvalidValue+        testNonExistingFile+        testReadLongSetting+    describe "save config" $ do+        testSaveUserSetAndDefaults+        createBakBeforeSaving+        wrapLongSettings+    describe "set setting" testSetListSetting  testEmptyFileDefaults :: Spec testEmptyFileDefaults = it "parses correctly an empty file with defaults" $ do     readResult <- try $ readSettings (Path "tests/empty.config")     case readResult of-    	Right (_, GetSetting getSetting) -> do-    		getSetting textSizeFromWidth `shouldBe` 0.04-    		getSetting textSizeFromHeight `shouldBe` 12.4-    		getSetting textFill `shouldBe` (1,1,0,1)-    		getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]-    		getSetting testList `shouldBe` ["list1", "list2", "list3"]-    	Left (x :: SomeException) -> assertBool (show x) False+        Right (_, GetSetting getSetting) -> do+            getSetting textSizeFromWidth `shouldBe` 0.04+            getSetting textSizeFromHeight `shouldBe` 12.4+            getSetting textFill `shouldBe` (1,1,0,1)+            getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+            getSetting testList `shouldBe` ["list1", "list2", "list3"]+        Left (x :: SomeException) -> assertBool (show x) False  testPartialFileDefaults :: Spec testPartialFileDefaults = it "parses correctly a partial file with defaults" $ do     readResult <- try $ readSettings (Path "tests/partial.config")     case readResult of-    	Right (_, GetSetting getSetting) -> do-    		getSetting textSizeFromWidth `shouldBe` 1.02-    		getSetting textSizeFromHeight `shouldBe` 12.4-    		getSetting textFill `shouldBe` (1,2,3,4)-    		getSetting testInlineList `shouldBe` ["un", "deux"]-    		getSetting testList `shouldBe` ["one", "two"]-    	Left (x :: SomeException) -> assertBool (show x) False+        Right (_, GetSetting getSetting) -> do+            getSetting textSizeFromWidth `shouldBe` 1.02+            getSetting textSizeFromHeight `shouldBe` 12.4+            getSetting textFill `shouldBe` (1,2,3,4)+            getSetting testInlineList `shouldBe` ["un", "deux"]+            getSetting testList `shouldBe` ["one", "two"]+        Left (x :: SomeException) -> assertBool (show x) False  testPartialFileDefaults2 :: Spec testPartialFileDefaults2 = it "parses correctly a partial2 file with defaults" $ do     readResult <- try $ readSettings (Path "tests/partial2.config")     case readResult of-    	Right (_, GetSetting getSetting) -> do-    		getSetting textSizeFromWidth `shouldBe` 1.02-    		getSetting textSizeFromHeight `shouldBe` 12.4-    		getSetting textFill `shouldBe` (1,2,3,4)-    		getSetting testInlineList `shouldBe` ["un", "deux"]-    		getSetting testList `shouldBe` []-    	Left (x :: SomeException) -> assertBool (show x) False+        Right (_, GetSetting getSetting) -> do+            getSetting textSizeFromWidth `shouldBe` 1.02+            getSetting textSizeFromHeight `shouldBe` 12.4+            getSetting textFill `shouldBe` (1,2,3,4)+            getSetting testInlineList `shouldBe` ["un", "deux"]+            getSetting testList `shouldBe` []+        Left (x :: SomeException) -> assertBool (show x) False  testFileWithComments :: Spec testFileWithComments = it "parses correctly a partial file with comments" $ do     readResult <- try $ readSettings (Path "tests/test-save.txt")     case readResult of-    	Right (_, GetSetting getSetting) -> do-    		getSetting textSizeFromWidth `shouldBe` 1.02-    		getSetting textSizeFromHeight `shouldBe` 12.4-    		getSetting textFill `shouldBe` (1,2,3,4)-    		getSetting testInlineList `shouldBe` ["un", "deux"]-    		getSetting testList `shouldBe` ["one", "two"]-    	Left (x :: SomeException) -> assertBool (show x) False+        Right (_, GetSetting getSetting) -> do+            getSetting textSizeFromWidth `shouldBe` 1.02+            getSetting textSizeFromHeight `shouldBe` 12.4+            getSetting textFill `shouldBe` (1,2,3,4)+            getSetting testInlineList `shouldBe` ["un", "deux"]+            getSetting testList `shouldBe` ["one", "two"]+        Left (x :: SomeException) -> assertBool (show x) False  testInvalidValue :: Spec testInvalidValue = it "parses correctly a file with invalid values" $ do     readResult <- try $ readSettings (Path "tests/brokenvalue.config")     case readResult of-    	Right (_, GetSetting getSetting) -> do-    		-- give the default for the invalid value-    		getSetting textSizeFromWidth `shouldBe` 0.04-    		getSetting textSizeFromHeight `shouldBe` 12.4-    		getSetting textFill `shouldBe` (1,2,3,4)-    		getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]-    		getSetting testList `shouldBe` ["list1", "list2", "list3"]-    	Left (x :: SomeException) -> assertBool (show x) False+        Right (_, GetSetting getSetting) -> do+            -- give the default for the invalid value+            getSetting textSizeFromWidth `shouldBe` 0.04+            getSetting textSizeFromHeight `shouldBe` 12.4+            getSetting textFill `shouldBe` (1,2,3,4)+            getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+            getSetting testList `shouldBe` ["list1", "list2", "list3"]+        Left (x :: SomeException) -> assertBool (show x) False  testNonExistingFile :: Spec testNonExistingFile = it "returns empty config for a non-existing file" $ do-	readResult <- try $ readSettings (Path "tests/dontexist.conf")-	case readResult of-		Right (_, GetSetting getSetting) -> do-			getSetting textSizeFromWidth `shouldBe` 0.04-			getSetting textSizeFromHeight `shouldBe` 12.4-			getSetting textFill `shouldBe` (1,1,0,1)-			getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]-			getSetting testList `shouldBe` ["list1", "list2", "list3"]-		Left (x :: SomeException) -> assertBool (show x) False+    readResult <- try $ readSettings (Path "tests/dontexist.conf")+    case readResult of+        Right (_, GetSetting getSetting) -> do+            getSetting textSizeFromWidth `shouldBe` 0.04+            getSetting textSizeFromHeight `shouldBe` 12.4+            getSetting textFill `shouldBe` (1,1,0,1)+            getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+            getSetting testList `shouldBe` ["list1", "list2", "list3"]+        Left (x :: SomeException) -> assertBool (show x) False  testReadLongSetting :: Spec testReadLongSetting = it "Reads setting files with setting values wrapped over several lines" $ do-	readResult <- try $ readSettings (Path "tests/longsetting.conf") -	case readResult of -		Right (_, GetSetting getVal) -> do-			let expected = replicate 20 "long      string"-			let actual = getVal testInlineList-			assertEqual "doesn't match" expected actual-		Left (x :: SomeException) -> assertBool (show x) False+    readResult <- try $ readSettings (Path "tests/longsetting.conf")+    case readResult of+        Right (_, GetSetting getVal) -> do+            let expected = replicate 20 "long      string"+            let actual = getVal testInlineList+            assertEqual "doesn't match" expected actual+        Left (x :: SomeException) -> assertBool (show x) False  testInvalidFile :: Spec testInvalidFile = it "reports errors properly for invalid files" $ do     readResult <- try $ readSettings (Path "tests/broken.config")     case readResult of-    	Left (_ :: SomeException) -> assertBool "ok" True-    	Right _ -> assertBool "did not get an error!" False+        Left (_ :: SomeException) -> assertBool "ok" True+        Right _ -> assertBool "did not get an error!" False  testSaveUserSetAndDefaults :: Spec testSaveUserSetAndDefaults = it "saves a file with user-set and default settings" $ do-	readResult <- try $ readSettings (Path "tests/partial.config") -	case readResult of -		Right (conf, _) -> do-			saveSettings defaultConfig (Path "test.txt") conf-			actual <- readFile "test.txt"-			reference <- readFile "tests/test-save.txt"-			actual `shouldBe` reference-			removeFile "test.txt"-		Left (x :: SomeException) -> assertBool (show x) False+    readResult <- try $ readSettings (Path "tests/partial.config")+    case readResult of+        Right (conf, _) -> do+            saveSettings defaultConfig (Path "test.txt") conf+            actual <- readFile "test.txt"+            reference <- readFile "tests/test-save.txt"+            actual `shouldBe` reference+            removeFile "test.txt"+        Left (x :: SomeException) -> assertBool (show x) False  createBakBeforeSaving :: Spec createBakBeforeSaving = it "creates a backup of the config file before overwriting it" $ do-	readResult <- try $ readSettings (Path "tests/partial.config") -	case readResult of -		Right (conf, _) -> do-			copyFile "tests/partial.config" "p.config"-			saveSettings defaultConfig (Path "p.config") conf-			doesFileExist "p.config.bak" >>= flip shouldBe True-			doesFileExist "p.config" >>= flip shouldBe True-			removeFile "p.config"-			removeFile "p.config.bak"-		Left (x :: SomeException) -> assertBool (show x) False+    readResult <- try $ readSettings (Path "tests/partial.config")+    case readResult of+        Right (conf, _) -> do+            copyFile "tests/partial.config" "p.config"+            saveSettings defaultConfig (Path "p.config") conf+            doesFileExist "p.config.bak" >>= flip shouldBe True+            doesFileExist "p.config" >>= flip shouldBe True+            removeFile "p.config"+            removeFile "p.config.bak"+        Left (x :: SomeException) -> assertBool (show x) False  wrapLongSettings :: Spec wrapLongSettings = it "wraps long settings when saving" $ do-	readResult <- try $ readSettings (Path "tests/partial.config") -	case readResult of -		Right (conf, _) -> do-			let conf1 = setSetting conf testInlineList $ replicate 20 "long      string"-			saveSettings defaultConfig (Path "xx.config") conf1-			expected <- readFile "tests/longsetting.conf"-			actual <- readFile "xx.config"-			assertEqual "doesn't match" expected actual-			removeFile "xx.config"-		Left (x :: SomeException) -> assertBool (show x) False-	+    readResult <- try $ readSettings (Path "tests/partial.config")+    case readResult of+        Right (conf, _) -> do+            let conf1 = setSetting conf testInlineList $ replicate 20 "long      string"+            saveSettings defaultConfig (Path "xx.config") conf1+            expected <- readFile "tests/longsetting.conf"+            actual <- readFile "xx.config"+            assertEqual "doesn't match" expected actual+            removeFile "xx.config"+        Left (x :: SomeException) -> assertBool (show x) False + testSetListSetting :: Spec testSetListSetting = it "overwrites correctly a list setting" $ do     readResult <- try $ readSettings (Path "tests/empty.config")     case readResult of-    	Right (conf, GetSetting getSetting) -> do-    		getSetting testList `shouldBe` ["list1", "list2", "list3"]-    		getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]-    		let conf0 = setSetting conf testList ["un"]-    		let conf1 = setSetting conf0 testInlineList ["one"]-    		getSetting' conf1 testList `shouldBe` ["un"]-    		getSetting' conf1 testInlineList `shouldBe` ["one"]-    		let conf2 = setSetting conf1 testList []-    		let conf3 = setSetting conf2 testInlineList []-    		getSetting' conf3 testList `shouldBe` []-    		getSetting' conf3 testInlineList `shouldBe` []-    	Left (x :: SomeException) -> assertBool (show x) False+        Right (conf, GetSetting getSetting) -> do+            getSetting testList `shouldBe` ["list1", "list2", "list3"]+            getSetting testInlineList `shouldBe` ["inline1", "inline2", "inline3"]+            let conf0 = setSetting conf testList ["un"]+            let conf1 = setSetting conf0 testInlineList ["one"]+            getSetting' conf1 testList `shouldBe` ["un"]+            getSetting' conf1 testInlineList `shouldBe` ["one"]+            let conf2 = setSetting conf1 testList []+            let conf3 = setSetting conf2 testInlineList []+            getSetting' conf3 testList `shouldBe` []+            getSetting' conf3 testInlineList `shouldBe` []+        Left (x :: SomeException) -> assertBool (show x) False  testIsKeyForListSetting :: Spec testIsKeyForListSetting = it "checks correctly whether a key is attached to a list setting" $ do-	isKeyForListSetting "listTest" "listTest_1" `shouldBe` True-	isKeyForListSetting "listTest" "listTest_13" `shouldBe` True-	isKeyForListSetting "listTest" "listTest_unrelated" `shouldBe` False-	isKeyForListSetting "listTest" "listTest_1notanumber" `shouldBe` False-	isKeyForListSetting "listTest" "listTestX_1" `shouldBe` False+    isKeyForListSetting "listTest" "listTest_1" `shouldBe` True+    isKeyForListSetting "listTest" "listTest_13" `shouldBe` True+    isKeyForListSetting "listTest" "listTest_unrelated" `shouldBe` False+    isKeyForListSetting "listTest" "listTest_1notanumber" `shouldBe` False+    isKeyForListSetting "listTest" "listTestX_1" `shouldBe` False