hocon 0.1.0.1 → 0.1.0.2
raw patch · 5 files changed
+62/−22 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Data.HOCON: mapNode :: (Map String Config -> Config) -> Config -> Config
+ Text.Parser.HOCON.Internal: postProcessing :: Config -> Config
Files
- hocon.cabal +2/−2
- src/Data/HOCON.hs +0/−5
- src/Text/Parser/HOCON/Internal.hs +36/−14
- test/Text/Parser/HOCON/InternalSpec.hs +9/−1
- test/Text/Parser/HOCONSpec.hs +15/−0
hocon.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 479320fd325338bd94374a5beb7a949a9bb9804fc9b507fc863a1a4ad2f84b81+-- hash: 4bd9a308ad33bf13b1ecad16f71185175255207b4eb710c118d81821c614ae1f name: hocon-version: 0.1.0.1+version: 0.1.0.2 synopsis: Small library for typesafe's configuration specification description: Small library for typesafe's configuration specification category: Data
src/Data/HOCON.hs view
@@ -7,7 +7,6 @@ , getList , getBool , isNull- , mapNode , getConfig , pretty )@@ -31,10 +30,6 @@ isNull :: Config -> Bool isNull HOCONNull = True isNull _ = False--mapNode :: (Map String Config -> Config) -> Config -> Config-mapNode f (HOCONNode nodes) = f nodes-mapNode _ conf = conf getNode :: String -> Config -> Maybe (Map String Config) getNode key conf = do
src/Text/Parser/HOCON/Internal.hs view
@@ -13,13 +13,14 @@ , nullParser , preProcessing , hoconParser+ , postProcessing ) where import Data.Bifunctor.Extra (mapValues)-import Data.HOCON (Config(..), mapNode)+import Data.HOCON (Config(..)) import Data.List.Split (splitOn)-import Data.Map (groupBy, sortByKey)+import Data.Map (groupBy, sortByKey, Map) import Data.String.Utils (replace, join, strip) import Text.ParserCombinators.Parsec (char, Parser, alphaNum, digit, letter, noneOf, oneOf, space, string, between, sepBy, (<|>), many, many1, skipMany, try)@@ -81,7 +82,7 @@ booleanParser :: Parser Config booleanParser = do whitespace- bool <- string "true" <|> string "false"+ bool <- try (string "true" <|> string "false") whitespace return $ if bool == "true" then HOCONBool True else HOCONBool False @@ -110,23 +111,44 @@ preProcessing :: String -> String preProcessing =- replace "\n" "," . replace "{\n" "{" . replace "\n}" "}" . replace ",\n" "," . join "\n" . map strip . splitOn "\n"+ replace "\n" ","+ . replace "[\n" "["+ . replace "\n]" "]"+ . replace "{\n" "{"+ . replace "\n}" "}"+ . replace ",\n" ","+ . join "\n"+ . map strip+ . splitOn "\n" +postProcessing :: Config -> Config+postProcessing (HOCONNode nodes) = HOCONNode . sort . removeDuplicates . group $ nodes++group :: Map String Config -> Map String Config+group nodes = do+ let grouped = groupBy fst nodes+ (key, configs) <- mapValues (map snd) grouped+ return (key, if all isNode configs then mergeAll configs else head configs)+ where+ isNode n = case n of+ HOCONNode _ -> True+ _ -> False++sort :: Map String Config -> Map String Config+sort = sortByKey+ hoconParser :: Parser Config-hoconParser = objectParser <|> do- values <- sepBy parseProps (char ',')- let grouped = groupAndMerge values- let sorted = mapValues (mapNode (HOCONNode . sortByKey)) . sortByKey $ grouped- return $ HOCONNode sorted+hoconParser = postProcessing <$> parser where- groupAndMerge values = do- (key, mixedConfigsAndKeys) <- groupBy fst values- let configs = map snd mixedConfigsAndKeys- return (key, mergeAll configs)+ parser = objectParser <|> do+ values <- sepBy parseProps (char ',')+ return $ HOCONNode values +removeDuplicates :: Map String Config -> Map String Config+removeDuplicates = foldl (\acc e -> if any ((== fst e) . fst) acc then acc else e : acc) []+ mergeAll :: [Config] -> Config mergeAll = foldl1 merge merge :: Config -> Config -> Config merge (HOCONNode a) (HOCONNode b) = HOCONNode (a ++ b)-
test/Text/Parser/HOCON/InternalSpec.hs view
@@ -5,7 +5,8 @@ import Data.HOCON (Config(..)) import Test.Hspec (describe, it, shouldBe, shouldSatisfy, Spec)-import Text.Parser.HOCON.Internal (arrayParser, numberParser, objectParser, parseProps, stringParser, hoconParser, preProcessing)+import Text.Parser.HOCON.Internal+ (arrayParser, numberParser, objectParser, parseProps, stringParser, hoconParser, preProcessing, postProcessing) import Text.ParserCombinators.Parsec (parse) isLeft :: Either a b -> Bool@@ -60,6 +61,13 @@ preProcessing "{foo = bar\n}" `shouldBe` "{foo = bar}" preProcessing "{foo = bar}" `shouldBe` "{foo = bar}" preProcessing "{foo = bar\n }" `shouldBe` "{foo = bar}"++ describe "postProcessing" $ it "groups all object with the same key, removes duplicates and sorts them" $ do+ postProcessing (HOCONNode [("foo", HOCONString "bar")]) `shouldBe` HOCONNode [("foo", HOCONString "bar")]+ postProcessing (HOCONNode [("foo", HOCONNode [("foo", HOCONString "bar")]), ("foo", HOCONNode [("bar", HOCONString "foo")])])+ `shouldBe` HOCONNode [("foo", HOCONNode [("bar", HOCONString "foo"), ("foo", HOCONString "bar")])]+ postProcessing (HOCONNode [("foo", HOCONString "bar"), ("foo", HOCONNumber 123)])+ `shouldBe` HOCONNode [("foo", HOCONNumber 123)] describe "hoconParser" $ do it "succeeds" $ do
test/Text/Parser/HOCONSpec.hs view
@@ -14,6 +14,21 @@ parseHOCON "foo = bar" `shouldBe` Right (HOCONNode [("foo", HOCONString "bar")]) parseHOCON "foo = bar\nbar = 123\nbaz = \"nani?!\"" `shouldBe` Right (HOCONNode [("bar", HOCONNumber 123), ("baz", HOCONString "nani?!"), ("foo", HOCONString "bar")])+ parseHOCON "{\n \"foo\": \"bar\"\n}" `shouldBe` Right (HOCONNode [("foo", HOCONString "bar")])+ parseHOCON+ "foo = bar\nbar = true\nsomeObject {\n someField = [\n foo,\n bar,\n baz\n ]\n someOtherField = [\n {\n foo = bar\n }\n ]\n}"+ `shouldBe` Right+ (HOCONNode+ [ ("bar", HOCONBool True)+ , ("foo", HOCONString "bar")+ , ( "someObject"+ , HOCONNode+ [ ("someField" , HOCONList [HOCONString "foo", HOCONString "bar", HOCONString "baz"])+ , ("someOtherField", HOCONList [HOCONNode [("foo", HOCONString "bar")]])+ ]+ )+ ]+ ) it "fails" $ do parseHOCON "foo = bar\n{\n foo = bar\n}" `shouldSatisfy` isLeft parseHOCON "{" `shouldSatisfy` isLeft