packages feed

salak-toml 0.3.4 → 0.3.4.1

raw patch · 7 files changed

+409/−367 lines, 7 filesdep +criteriondep ~basedep ~salak

Dependencies added: criterion

Dependency ranges changed: base, salak

Files

+ bench/SalakTomlBench.hs view
@@ -0,0 +1,14 @@+module SalakTomlBench where++import           Criterion.Main+import           Salak+import           Salak.Toml+++main = defaultMain+    [ bgroup "load"+      [ bench "loadYaml" $ whnfIO $ loadAndRunSalak (loadToml "salak.toml") action+      ]+    ]++action = return ()
salak-toml.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: salak-toml-version: 0.3.4+version: 0.3.4.1 license: MIT license-file: LICENSE copyright: 2019 Daniel YU@@ -12,7 +12,7 @@ build-type: Simple extra-source-files:     README.md-    test/salak.toml+    salak.toml  library     exposed-modules:@@ -22,36 +22,58 @@         Paths_salak_toml     default-language: Haskell2010     default-extensions: RecordWildCards TupleSections OverloadedStrings-                        ScopedTypeVariables FlexibleInstances MultiParamTypeClasses-                        DeriveGeneric+                        NoOverloadedLists ScopedTypeVariables FlexibleInstances+                        MultiParamTypeClasses DeriveGeneric FlexibleContexts RankNTypes     ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures     build-depends:         base >=4.10 && <5,-        salak >=0.3.4 && <0.4,+        salak >=0.3.4.1 && <0.4,         text >=1.2.3.1 && <1.3,         time >=1.8.0.2 && <1.9,         tomland >=1.0 && <1.2,         unordered-containers >=0.2.10.0 && <0.3 -test-suite spec+test-suite salak-toml-spec     type: exitcode-stdio-1.0-    main-is: Spec.hs+    main-is: SalakTomlSpec.hs     hs-source-dirs: test src     other-modules:         Salak.Toml         Paths_salak_toml     default-language: Haskell2010     default-extensions: RecordWildCards TupleSections OverloadedStrings-                        ScopedTypeVariables FlexibleInstances MultiParamTypeClasses-                        DeriveGeneric+                        NoOverloadedLists ScopedTypeVariables FlexibleInstances+                        MultiParamTypeClasses DeriveGeneric FlexibleContexts RankNTypes     ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures+                 -main-is SalakTomlSpec.main     build-depends:         QuickCheck >=2.13.2 && <2.14,         base >=4.10 && <5,         exceptions >=0.10.2 && <0.11,         hspec ==2.*,         mtl >=2.2.2 && <2.3,-        salak >=0.3.4 && <0.4,+        salak >=0.3.4.1 && <0.4,+        text >=1.2.3.1 && <1.3,+        time >=1.8.0.2 && <1.9,+        tomland >=1.0 && <1.2,+        unordered-containers >=0.2.10.0 && <0.3++benchmark salak-toml-bench+    type: exitcode-stdio-1.0+    main-is: SalakTomlBench.hs+    hs-source-dirs: bench src+    other-modules:+        Salak.Toml+    default-language: Haskell2010+    default-extensions: RecordWildCards TupleSections OverloadedStrings+                        NoOverloadedLists ScopedTypeVariables FlexibleInstances+                        MultiParamTypeClasses DeriveGeneric FlexibleContexts RankNTypes+    ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures+                 -main-is SalakTomlBench.main -rtsopts -threaded -with-rtsopts=-K1K+    build-depends:+        base >=4.10 && <5,+        criterion >=1.5.5.0 && <1.6,+        salak >=0.3.4.1 && <0.4,         text >=1.2.3.1 && <1.3,         time >=1.8.0.2 && <1.9,         tomland >=1.0 && <1.2,
+ salak.toml view
@@ -0,0 +1,261 @@+server.port        = 8080+server.codes       = [ 5, 10, 42 ]+server.description = """+This is production server.+Don't touch it!+"""++[mail]+    host = "smtp.gmail.com"+    send-if-inactive = false++[me.icymint.conf]+name="shelly"+age=16+male="no"+det.hello="def"++################################################################################+## Comment++# Speak your mind with the hash symbol. They go from the symbol to the end of+# the line.+++################################################################################+## Table++# Tables (also known as hash tables or dictionaries) are collections of+# key/value pairs. They appear in square brackets on a line by themselves.++[table]++key = "value" # Yeah, you can do this.++# Nested tables are denoted by table names with dots in them. Name your tables+# whatever crap you please, just don't use #, ., [ or ].++[table.subtable]++key = "another value"++# You don't need to specify all the super-tables if you don't want to. TOML+# knows how to do it for you.++# [x] you+# [x.y] don't+# [x.y.z] need these+[x.y.z.w] # for this to work+++################################################################################+## Inline Table++# Inline tables provide a more compact syntax for expressing tables. They are+# especially useful for grouped data that can otherwise quickly become verbose.+# Inline tables are enclosed in curly braces `{` and `}`. No newlines are+# allowed between the curly braces unless they are valid within a value.++[table.inline]++name = { first = "Tom", last = "Preston-Werner" }+point = { x = 1, y = 2 }+++################################################################################+## String++# There are four ways to express strings: basic, multi-line basic, literal, and+# multi-line literal. All strings must contain only valid UTF-8 characters.++[string.basic]++basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."++[string.multiline]++# The following strings are byte-for-byte equivalent:+key1 = "One\nTwo"+key2 = """One\nTwo"""+key3 = """+One+Two"""++[string.multiline.continued]++# The following strings are byte-for-byte equivalent:+key1 = "The quick brown fox jumps over the lazy dog."++key2 = """+The quick brown \+++  fox jumps over \+    the lazy dog."""++key3 = """\+       The quick brown \+       fox jumps over \+       the lazy dog.\+       """++[string.literal]++# What you see is what you get.+winpath  = 'C:\\Users\\nodejs\\templates'+winpath2 = '\\\\ServerX\\admin\$\\system32\\'+quoted   = 'Tom "Dubs" Preston-Werner'+regex    = '<\\i\\c*\\s*>'+++[string.literal.multiline]++regex2 = '''I [dw]on't need \\d\{2\} apples'''+lines  = '''+The first newline is+trimmed in raw strings.+   All other whitespace+   is preserved.+'''+++################################################################################+## Integer++# Integers are whole numbers. Positive numbers may be prefixed with a plus sign.+# Negative numbers are prefixed with a minus sign.++[integer]++key1 = +99+key2 = 42+key3 = 0+key4 = -17++[integer.underscores]++# For large numbers, you may use underscores to enhance readability. Each+# underscore must be surrounded by at least one digit.+key1 = 1_000+key2 = 5_349_221+key3 = 1_2_3_4_5     # valid but inadvisable+++################################################################################+## Float++# A float consists of an integer part (which may be prefixed with a plus or+# minus sign) followed by a fractional part and/or an exponent part.++[float.fractional]++key1 = +1.0+key2 = 3.1415+key3 = -0.01++[float.exponent]++key1 = 5e+22+key2 = 1e6+key3 = -2E-2++[float.both]++key = 6.626e-34++[float.underscores]++key1 = 9_224_617.445_991_228_313+key2 = 1e1_000+++################################################################################+## Boolean++# Booleans are just the tokens you're used to. Always lowercase.++[boolean]++True = true+False = false+++################################################################################+## Datetime++# Datetimes are RFC 3339 dates.++[datetime]++key1 = 1979-05-27T07:32:00Z+key2 = 1979-05-27T00:32:00-07:00+key3 = 1979-05-27T00:32:00.999999-07:00+++################################################################################+## Array++# Arrays are square brackets with other primitives inside. Whitespace is+# ignored. Elements are separated by commas. Data types may not be mixed.++[array]++key1 = [ 1, 2, 3 ]+key2 = [ "red", "yellow", "green" ]+key3 = [ [ 1, 2 ], [3, 4, 5] ]+key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok++# Arrays can also be multiline. So in addition to ignoring whitespace, arrays+# also ignore newlines between the brackets.  Terminating commas are ok before+# the closing bracket.++key5 = [+  1, 2, 3+]+key6 = [+  1,+  2, # this is ok+]+++################################################################################+## Array of Tables++# These can be expressed by using a table name in double brackets. Each table+# with the same double bracketed name will be an element in the array. The+# tables are inserted in the order encountered.++[[products]]++name = "Hammer"+sku = 738594937++[[products]]++[[products]]++name = "Nail"+sku = 284758393+color = "gray"+++# You can create nested arrays of tables as well.++[[fruit]]+  name = "apple"++  [fruit.physical]+    color = "red"+    shape = "round"++  [[fruit.variety]]+    name = "red delicious"++  [[fruit.variety]]+    name = "granny smith"++[[fruit]]+  name = "banana"++  [[fruit.variety]]+    name = "plantain"
src/Salak/Toml.hs view
@@ -6,7 +6,7 @@ -- | -- Module:      Salak.Toml -- Copyright:   (c) 2019 Daniel YU--- License:     BSD3+-- License:     MIT -- Maintainer:  leptonyu@gmail.com -- Stability:   experimental -- Portability: portable@@ -21,6 +21,7 @@  import           Control.Exception   (Exception, throwIO) import qualified Data.HashMap.Strict as HM+import           Data.List           (foldl') import qualified Data.List.NonEmpty  as N import           Data.Text           (Text) import qualified Data.Text.IO        as IO@@ -41,9 +42,11 @@ instance HasLoad TOML where   loaders _ = (, loadToml) <$> ["toml", "tml"] +{-# INLINE toSs #-} toSs :: T.Key -> Keys toSs (T.Key ps) = fromKeys $ toS <$> N.toList ps +{-# INLINE toS #-} toS :: Piece -> Key toS = KT . unPiece @@ -53,28 +56,31 @@   . foldTables      tomlTables   . foldTableArrays tomlTableArrays   where-    foldToml go p t = HM.foldlWithKey' go t p-    foldPairs       = foldToml (\s k v -> TR.modify' (toSs k) (insertAnyValue i v) s)-    foldTableArrays = foldToml (\s _ v -> foldArray (N.toList v) (loadTOML i) s)+    {-# INLINE foldToml #-}+    foldToml = flip . HM.foldlWithKey'+    {-# INLINE foldPairs #-}+    foldPairs       = foldToml (\s k v -> TR.modify' (insertAnyValue v) (toSs k) s)+    {-# INLINE foldTableArrays #-}+    foldTableArrays = foldToml (\s _ v -> foldArray (loadTOML i) (N.toList v) s)+    {-# INLINE foldTables #-}     foldTables      = foldToml (\s _ v -> go v s)-      where-        go (Leaf   k toml)    = TR.modify' (toSs k) (loadTOML i toml)-        go (Branch k v tomap) = TR.modify' (toSs k) (foldTables tomap) . maybe id (loadTOML i) v-insertAnyValue :: Int -> AnyValue -> TraceSource -> TraceSource-insertAnyValue i (AnyValue (Array   b))             ts = foldArray b (insertAnyValue i . AnyValue) ts-insertAnyValue i (AnyValue (Bool    b))             ts = setVal i (VB  b) ts-insertAnyValue i (AnyValue (Integer b))             ts = setVal i (VI $ fromIntegral b) ts-insertAnyValue i (AnyValue (Double  b))             ts = setVal i (VI $ realToFrac   b) ts-insertAnyValue i (AnyValue (Text    b))             ts = setVal i (VT  b) ts-insertAnyValue i (AnyValue (Local   b))             ts = setVal i (VLT b) ts-insertAnyValue i (AnyValue (Day     b))             ts = setVal i (VD  b) ts-insertAnyValue i (AnyValue (Hours   b))             ts = setVal i (VH  b) ts-insertAnyValue i (AnyValue (Zoned (ZonedTime a b))) ts = setVal i (VZT b a) ts--foldArray :: [a] -> (a -> TraceSource -> TraceSource) -> TraceSource -> TraceSource-foldArray as f ts = foldl go ts $ zip [0..] as-  where-    go t (i, a) = TR.modify (KI i) (f a) t+    {-# INLINE go #-}+    go (Leaf   k   toml)  = TR.modify' (loadTOML i toml)  (toSs k)+    go (Branch k v tomap) = TR.modify' (foldTables tomap) (toSs k) . maybe id (loadTOML i) v+    {-# INLINE insertAnyValue #-}+    insertAnyValue :: AnyValue -> TraceSource -> TraceSource+    insertAnyValue (AnyValue (Array   b))             = foldArray (insertAnyValue . AnyValue) b+    insertAnyValue (AnyValue (Bool    b))             = setVal i (VB  b)+    insertAnyValue (AnyValue (Integer b))             = setVal i (VI $ fromIntegral b)+    insertAnyValue (AnyValue (Double  b))             = setVal i (VI $ realToFrac   b)+    insertAnyValue (AnyValue (Text    b))             = setVal i (VT  b)+    insertAnyValue (AnyValue (Local   b))             = setVal i (VLT b)+    insertAnyValue (AnyValue (Day     b))             = setVal i (VD  b)+    insertAnyValue (AnyValue (Hours   b))             = setVal i (VH  b)+    insertAnyValue (AnyValue (Zoned   b))             = setVal i (VU  $ zonedTimeToUTC b)+    {-# INLINE foldArray #-}+    foldArray :: (a -> TraceSource -> TraceSource) -> [a] -> TraceSource -> TraceSource+    foldArray f = flip (foldl' (\t (j,a) -> TR.modify (KI j) (f a) t)) . zip [0..]  newtype TomlException = TomlException Text deriving Show 
+ test/SalakTomlSpec.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE ScopedTypeVariables   #-}++module SalakTomlSpec where++import           Control.Monad.Reader+import           Data.List            (intercalate)+import           Data.Text            (Text, pack)+import           GHC.Generics+import           Salak+import           Salak.Internal+import           Salak.Toml+import           Test.Hspec+import           Test.QuickCheck++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "Salak.Toml"  tomlProperty++newtype SKey = SKey { unKey :: Text } deriving Show++instance Arbitrary SKey where+  arbitrary = do+    key <- choose (1,20)+    vs  <- vectorOf key $ do+      k <- choose (1,20)+      v <- vectorOf k $ choose ('a','z')+      b <- choose (0,10) :: Gen Int+      if b > 0 then return v else do+        x <- choose (0,10) :: Gen Int+        return (v ++ "[" ++ show x ++ "]")+    return (SKey $ pack $ intercalate "." vs)++data Conf = Conf+  { name :: String+  , age  :: Int+  , male :: Bool+  , det  :: SubConf+  } deriving (Eq, Show, Generic)++data SubConf = SubConf+  { hello :: String } deriving (Eq, Show, Generic)++instance FromProp m SubConf where+  fromProp = SubConf <$> "hello" .?= "yyy"++instance FromProp m Conf++tomlProperty :: SpecWith ()+tomlProperty = do+  context "load toml" $ do+    it "salak.toml" $ do+      loadAndRunSalak (loadToml "salak.toml") $ do+        SourcePack{..}  <- ask+        cf <- require "me.icymint.conf"+        lift $ do+          name cf `shouldBe` "shelly"+          age  cf `shouldBe` 16+          male cf `shouldBe` False+          det  cf `shouldBe` SubConf "def"+++++
− test/Spec.hs
@@ -1,74 +0,0 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DeriveGeneric         #-}-{-# LANGUAGE FlexibleContexts      #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE RecordWildCards       #-}-{-# LANGUAGE ScopedTypeVariables   #-}--module Main where--import           Control.Monad.Reader-import           Data.List            (intercalate)-import           Data.Text            (Text, pack)-import           GHC.Generics-import           Salak-import           Salak.Internal-import           Salak.Toml-import           Test.Hspec-import           Test.QuickCheck--main :: IO ()-main = hspec spec--spec :: Spec-spec = do-  describe "Salak.Toml"  tomlProperty--newtype SKey = SKey { unKey :: Text } deriving Show--instance Arbitrary SKey where-  arbitrary = do-    key <- choose (1,20)-    vs  <- vectorOf key $ do-      k <- choose (1,20)-      v <- vectorOf k $ choose ('a','z')-      b <- choose (0,10) :: Gen Int-      if b > 0 then return v else do-        x <- choose (0,10) :: Gen Int-        return (v ++ "[" ++ show x ++ "]")-    return (SKey $ pack $ intercalate "." vs)--data Conf = Conf-  { name :: String-  , age  :: Int-  , male :: Bool-  , det  :: SubConf-  } deriving (Eq, Show, Generic)--data SubConf = SubConf-  { hello :: String } deriving (Eq, Show, Generic)--instance FromProp m SubConf where-  fromProp = SubConf <$> "hello" .?= "yyy"--instance FromProp m Conf--tomlProperty :: SpecWith ()-tomlProperty = do-  context "load toml" $ do-    it "salak.toml" $ do-      loadAndRunSalak (loadToml "test/salak.toml") $ do-        SourcePack{..}  <- ask-        cf <- require "me.icymint.conf"-        lift $ do-          name cf `shouldBe` "shelly"-          age  cf `shouldBe` 16-          male cf `shouldBe` False-          det  cf `shouldBe` SubConf "def"-----
− test/salak.toml
@@ -1,261 +0,0 @@-server.port        = 8080-server.codes       = [ 5, 10, 42 ]-server.description = """-This is production server.-Don't touch it!-"""--[mail]-    host = "smtp.gmail.com"-    send-if-inactive = false--[me.icymint.conf]-name="shelly"-age=16-male="no"-det.hello="def"--################################################################################-## Comment--# Speak your mind with the hash symbol. They go from the symbol to the end of-# the line.---################################################################################-## Table--# Tables (also known as hash tables or dictionaries) are collections of-# key/value pairs. They appear in square brackets on a line by themselves.--[table]--key = "value" # Yeah, you can do this.--# Nested tables are denoted by table names with dots in them. Name your tables-# whatever crap you please, just don't use #, ., [ or ].--[table.subtable]--key = "another value"--# You don't need to specify all the super-tables if you don't want to. TOML-# knows how to do it for you.--# [x] you-# [x.y] don't-# [x.y.z] need these-[x.y.z.w] # for this to work---################################################################################-## Inline Table--# Inline tables provide a more compact syntax for expressing tables. They are-# especially useful for grouped data that can otherwise quickly become verbose.-# Inline tables are enclosed in curly braces `{` and `}`. No newlines are-# allowed between the curly braces unless they are valid within a value.--[table.inline]--name = { first = "Tom", last = "Preston-Werner" }-point = { x = 1, y = 2 }---################################################################################-## String--# There are four ways to express strings: basic, multi-line basic, literal, and-# multi-line literal. All strings must contain only valid UTF-8 characters.--[string.basic]--basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."--[string.multiline]--# The following strings are byte-for-byte equivalent:-key1 = "One\nTwo"-key2 = """One\nTwo"""-key3 = """-One-Two"""--[string.multiline.continued]--# The following strings are byte-for-byte equivalent:-key1 = "The quick brown fox jumps over the lazy dog."--key2 = """-The quick brown \---  fox jumps over \-    the lazy dog."""--key3 = """\-       The quick brown \-       fox jumps over \-       the lazy dog.\-       """--[string.literal]--# What you see is what you get.-winpath  = 'C:\\Users\\nodejs\\templates'-winpath2 = '\\\\ServerX\\admin\$\\system32\\'-quoted   = 'Tom "Dubs" Preston-Werner'-regex    = '<\\i\\c*\\s*>'---[string.literal.multiline]--regex2 = '''I [dw]on't need \\d\{2\} apples'''-lines  = '''-The first newline is-trimmed in raw strings.-   All other whitespace-   is preserved.-'''---################################################################################-## Integer--# Integers are whole numbers. Positive numbers may be prefixed with a plus sign.-# Negative numbers are prefixed with a minus sign.--[integer]--key1 = +99-key2 = 42-key3 = 0-key4 = -17--[integer.underscores]--# For large numbers, you may use underscores to enhance readability. Each-# underscore must be surrounded by at least one digit.-key1 = 1_000-key2 = 5_349_221-key3 = 1_2_3_4_5     # valid but inadvisable---################################################################################-## Float--# A float consists of an integer part (which may be prefixed with a plus or-# minus sign) followed by a fractional part and/or an exponent part.--[float.fractional]--key1 = +1.0-key2 = 3.1415-key3 = -0.01--[float.exponent]--key1 = 5e+22-key2 = 1e6-key3 = -2E-2--[float.both]--key = 6.626e-34--[float.underscores]--key1 = 9_224_617.445_991_228_313-key2 = 1e1_000---################################################################################-## Boolean--# Booleans are just the tokens you're used to. Always lowercase.--[boolean]--True = true-False = false---################################################################################-## Datetime--# Datetimes are RFC 3339 dates.--[datetime]--key1 = 1979-05-27T07:32:00Z-key2 = 1979-05-27T00:32:00-07:00-key3 = 1979-05-27T00:32:00.999999-07:00---################################################################################-## Array--# Arrays are square brackets with other primitives inside. Whitespace is-# ignored. Elements are separated by commas. Data types may not be mixed.--[array]--key1 = [ 1, 2, 3 ]-key2 = [ "red", "yellow", "green" ]-key3 = [ [ 1, 2 ], [3, 4, 5] ]-key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok--# Arrays can also be multiline. So in addition to ignoring whitespace, arrays-# also ignore newlines between the brackets.  Terminating commas are ok before-# the closing bracket.--key5 = [-  1, 2, 3-]-key6 = [-  1,-  2, # this is ok-]---################################################################################-## Array of Tables--# These can be expressed by using a table name in double brackets. Each table-# with the same double bracketed name will be an element in the array. The-# tables are inserted in the order encountered.--[[products]]--name = "Hammer"-sku = 738594937--[[products]]--[[products]]--name = "Nail"-sku = 284758393-color = "gray"---# You can create nested arrays of tables as well.--[[fruit]]-  name = "apple"--  [fruit.physical]-    color = "red"-    shape = "round"--  [[fruit.variety]]-    name = "red delicious"--  [[fruit.variety]]-    name = "granny smith"--[[fruit]]-  name = "banana"--  [[fruit.variety]]-    name = "plantain"