on master help sign in
Support complex keys for mappings
commit154471a35555ca80ba41e87018794637ed458111 authorRobbie McMichael <RobbieMcMichael@users.noreply.github.com> dateMon 4 Nov 2019, 23:10 (7 years ago) parent40a68af
3 files changed+96−24
yaml/src/Data/Yaml/Builder.hs+30−11 yaml/src/Data/Yaml/Internal.hs+1−1 yaml/test/Data/YamlSpec.hs+65−12
yaml/src/Data/Yaml/Builder.hs+30−11
@@ -9,6 +9,9 @@ module Data.Yaml.Builder
99 , mapping
1010 , namedMapping
1111 , maybeNamedMapping
12+ , mappingComplex
13+ , namedMappingComplex
14+ , maybeNamedMappingComplex
1215 , array
1316 , namedArray
1417 , maybeNamedArray
@@ -37,7 +40,6 @@ module Data.Yaml.Builder
3740
3841import Prelude hiding (null)
3942
40−import Control.Arrow (second)
4143#if MIN_VERSION_aeson(1,0,0)
4244import Data.Aeson.Text (encodeToTextBuilder)
4345#else
@@ -66,22 +68,21 @@ class ToYaml a where
6668 toYaml :: a -> YamlBuilder
6769instance ToYaml YamlBuilder where
6870 toYaml = id
69−instance ToYaml a => ToYaml [(Text, a)] where
70− toYaml = mapping . map (second toYaml)
71+instance (ToYaml a, ToYaml b) => ToYaml [(a, b)] where
72+ toYaml = mappingComplex . map (\(k, v) -> (toYaml k, toYaml v))
7173instance ToYaml a => ToYaml [a] where
7274 toYaml = array . map toYaml
7375instance ToYaml Text where
7476 toYaml = string
7577instance ToYaml Int where
76− toYaml i = YamlBuilder (EventScalar (S8.pack $ show i) IntTag PlainNoTag Nothing:)
78+ toYaml i = YamlBuilder (EventScalar (S8.pack $ show i) NoTag PlainNoTag Nothing:)
7779
7880-- |
7981-- @since 0.11.0
8082maybeNamedMapping :: Maybe Text -> [(Text, YamlBuilder)] -> YamlBuilder
81−maybeNamedMapping anchor pairs = YamlBuilder $ \rest ->
82− EventMappingStart NoTag AnyMapping (unpack <$> anchor) : foldr addPair (EventMappingEnd : rest) pairs
83+maybeNamedMapping anchor pairs = maybeNamedMappingComplex anchor complexPairs
8384 where
84− addPair (key, YamlBuilder value) after = unYamlBuilder (string key) $ value after
85+ complexPairs = map (\(k, v) -> (string k, v)) pairs
8586
8687mapping :: [(Text, YamlBuilder)] -> YamlBuilder
8788mapping = maybeNamedMapping Nothing
@@ -91,6 +92,24 @@ mapping = maybeNamedMapping Nothing
9192namedMapping :: Text -> [(Text, YamlBuilder)] -> YamlBuilder
9293namedMapping name = maybeNamedMapping $ Just name
9394
95+-- |
96+-- @since 0.11.2.0
97+maybeNamedMappingComplex :: Maybe Text -> [(YamlBuilder, YamlBuilder)] -> YamlBuilder
98+maybeNamedMappingComplex anchor pairs = YamlBuilder $ \rest ->
99+ EventMappingStart NoTag AnyMapping (unpack <$> anchor) : foldr addPair (EventMappingEnd : rest) pairs
100+ where
101+ addPair (YamlBuilder key, YamlBuilder value) after = key $ value after
102+
103+-- |
104+-- @since 0.11.2.0
105+mappingComplex :: [(YamlBuilder, YamlBuilder)] -> YamlBuilder
106+mappingComplex = maybeNamedMappingComplex Nothing
107+
108+-- |
109+-- @since 0.11.2.0
110+namedMappingComplex :: Text -> [(YamlBuilder, YamlBuilder)] -> YamlBuilder
111+namedMappingComplex name = maybeNamedMappingComplex $ Just name
112+
94113-- |
95114-- @since 0.11.0
96115maybeNamedArray :: Maybe Text -> [YamlBuilder] -> YamlBuilder
@@ -124,7 +143,7 @@ namedString name = maybeNamedString $ Just name
124143-- |
125144-- @since 0.11.0
126145maybeNamedScientific :: Maybe Text -> Scientific -> YamlBuilder
127−maybeNamedScientific anchor n = YamlBuilder (EventScalar (TE.encodeUtf8 $ TL.toStrict $ toLazyText $ encodeToTextBuilder (Number n)) IntTag PlainNoTag (unpack <$> anchor) :)
146+maybeNamedScientific anchor n = YamlBuilder (EventScalar (TE.encodeUtf8 $ TL.toStrict $ toLazyText $ encodeToTextBuilder (Number n)) NoTag PlainNoTag (unpack <$> anchor) :)
128147
129148scientific :: Scientific -> YamlBuilder
130149scientific = maybeNamedScientific Nothing
@@ -141,8 +160,8 @@ number = scientific
141160-- |
142161-- @since 0.11.0
143162maybeNamedBool :: Maybe Text -> Bool -> YamlBuilder
144−maybeNamedBool anchor True = YamlBuilder (EventScalar "true" BoolTag PlainNoTag (unpack <$> anchor) :)
145−maybeNamedBool anchor False = YamlBuilder (EventScalar "false" BoolTag PlainNoTag (unpack <$> anchor) :)
163+maybeNamedBool anchor True = YamlBuilder (EventScalar "true" NoTag PlainNoTag (unpack <$> anchor) :)
164+maybeNamedBool anchor False = YamlBuilder (EventScalar "false" NoTag PlainNoTag (unpack <$> anchor) :)
146165
147166bool :: Bool -> YamlBuilder
148167bool = maybeNamedBool Nothing
@@ -155,7 +174,7 @@ namedBool name = maybeNamedBool $ Just name
155174-- |
156175-- @since 0.11.0
157176maybeNamedNull :: Maybe Text -> YamlBuilder
158−maybeNamedNull anchor = YamlBuilder (EventScalar "null" NullTag PlainNoTag (unpack <$> anchor) :)
177+maybeNamedNull anchor = YamlBuilder (EventScalar "null" NoTag PlainNoTag (unpack <$> anchor) :)
159178
160179null :: YamlBuilder
161180null = maybeNamedNull Nothing
yaml/src/Data/Yaml/Internal.hs+1−1
@@ -329,7 +329,7 @@ defaultStringStyle = \s ->
329329 ()
330330 | "\n" `T.isInfixOf` s -> ( NoTag, Literal )
331331 | isSpecialString s -> ( NoTag, SingleQuoted )
332− | otherwise -> ( StrTag, PlainNoTag )
332+ | otherwise -> ( NoTag, PlainNoTag )
333333
334334-- | Determine whether a string must be quoted in YAML and can't appear as plain text.
335335-- Useful if you want to use 'setStringStyle'.
yaml/test/Data/YamlSpec.hs+65−12
@@ -27,6 +27,7 @@ import System.Directory (createDirectory, createDirectoryIfMissing)
2727import Test.Mockery.Directory
2828
2929import qualified Data.Yaml as D
30+import qualified Data.Yaml.Builder as B
3031import qualified Data.Yaml.Internal as Internal
3132import qualified Data.Yaml.Pretty as Pretty
3233import Data.Yaml (object, array, (.=))
@@ -65,15 +66,28 @@ testJSON = TestJSON
6566
6667shouldDecode :: (Show a, D.FromJSON a, Eq a) => B8.ByteString -> a -> IO ()
6768shouldDecode bs expected = do
68− actual <- D.decodeThrow bs
69− actual `shouldBe` expected
69+ actual <- D.decodeThrow bs
70+ actual `shouldBe` expected
71+
72+shouldDecodeEvents :: B8.ByteString -> [Y.Event] -> IO ()
73+shouldDecodeEvents bs expected = do
74+ actual <- runConduitRes $ Y.decode bs .| CL.consume
75+ map anyStyle actual `shouldBe` map anyStyle expected
76+
77+anyStyle :: Y.Event -> Y.Event
78+anyStyle (Y.EventScalar bs tag _ anchor) = Y.EventScalar bs tag Y.Any anchor
79+anyStyle (Y.EventSequenceStart tag _ anchor) = Y.EventSequenceStart tag Y.AnySequence anchor
80+anyStyle (Y.EventMappingStart tag _ anchor) = Y.EventMappingStart tag Y.AnyMapping anchor
81+anyStyle event = event
7082
7183testEncodeWith :: Y.FormatOptions -> [Y.Event] -> IO BS.ByteString
72−testEncodeWith opts es = runConduitRes (CL.sourceList events .| Y.encodeWith opts)
73− where
74− events =
75− [Y.EventStreamStart, Y.EventDocumentStart] ++ es ++
76− [Y.EventDocumentEnd, Y.EventStreamEnd]
84+testEncodeWith opts es = runConduitRes $ CL.sourceList (eventStream es) .| Y.encodeWith opts
85+
86+eventStream :: [Y.Event] -> [Y.Event]
87+eventStream events =
88+ [Y.EventStreamStart, Y.EventDocumentStart]
89+ ++ events
90+ ++ [Y.EventDocumentEnd, Y.EventStreamEnd]
7791
7892main :: IO ()
7993main = hspec spec
@@ -112,6 +126,9 @@ spec = do
112126 it "encode/decode" caseEncodeDecodeDataPretty
113127 it "encode/decode strings" caseEncodeDecodeStringsPretty
114128 it "processes datatypes" caseDataTypesPretty
129+ describe "Data.Yaml.Builder" $ do
130+ it "encode/decode" caseEncodeDecodeDataBuilder
131+ it "encode/decode complex mapping" caseEncodeDecodeComplexMappingBuilder
115132 describe "Data.Yaml aliases" $ do
116133 it "simple scalar alias" caseSimpleScalarAlias
117134 it "simple sequence alias" caseSimpleSequenceAlias
@@ -478,13 +495,9 @@ caseEncodeDecode = do
478495caseEncodeDecodeEvents :: Assertion
479496caseEncodeDecodeEvents = do
480497 let events = Internal.objToEvents D.defaultStringStyle testJSON []
481− result <- Internal.decodeHelper_ . CL.sourceList $ toStream events
498+ result <- Internal.decodeHelper_ . CL.sourceList $ eventStream events
482499 let (_, value) = either (error . show) id result
483500 value @?= testJSON
484− where
485− toStream es =
486− [Y.EventStreamStart, Y.EventDocumentStart] ++ es ++
487− [Y.EventDocumentEnd, Y.EventStreamEnd]
488501
489502caseEncodeDecodeFile :: Assertion
490503caseEncodeDecodeFile = withFile "" $ \tmpPath -> do
@@ -535,6 +548,24 @@ sample = array
535548 , ("bar3", D.String "")
536549 ]
537550 , D.String ""
551+ , D.Number 1
552+ , D.Number 0.1
553+ , D.Bool True
554+ , D.Null
555+ ]
556+
557+sampleBuilder :: B.YamlBuilder
558+sampleBuilder = B.array
559+ [ B.string "foo"
560+ , B.mapping
561+ [ ("bar1", B.string "bar2")
562+ , ("bar3", B.string "")
563+ ]
564+ , B.string ""
565+ , B.scientific 1
566+ , B.scientific 0.1
567+ , B.bool True
568+ , B.null
538569 ]
539570
540571caseEncodeDecodeData :: Assertion
@@ -544,6 +575,28 @@ caseEncodeDecodeDataPretty :: Assertion
544575caseEncodeDecodeDataPretty =
545576 Pretty.encodePretty Pretty.defConfig sample `shouldDecode` sample
546577
578+caseEncodeDecodeDataBuilder :: Assertion
579+caseEncodeDecodeDataBuilder = do
580+ let events = B.unYamlBuilder sampleBuilder []
581+ bs <- testEncodeWith Y.defaultFormatOptions events
582+ bs `shouldDecodeEvents` eventStream events
583+
584+caseEncodeDecodeComplexMappingBuilder :: Assertion
585+caseEncodeDecodeComplexMappingBuilder = do
586+ let events = B.unYamlBuilder builder []
587+ bs <- testEncodeWith Y.defaultFormatOptions events
588+ bs `shouldDecodeEvents` eventStream events
589+ where
590+ builder :: B.YamlBuilder
591+ builder = B.mappingComplex
592+ [ ( B.mapping
593+ [ ("foo", B.scientific 1)
594+ , ("bar", B.scientific 2)
595+ ]
596+ , B.bool True
597+ )
598+ ]
599+
547600caseEncodeDecodeFileData :: Assertion
548601caseEncodeDecodeFileData = withFile "" $ \fp -> do
549602 D.encodeFile fp sample