Add support for YAML array data files
authorVas Sudanagunta <vas@commonkarma.org>
Mon, 12 Feb 2018 00:10:49 +0000 (19:10 -0500)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 12 Feb 2018 16:14:40 +0000 (17:14 +0100)
* Unmarshaled YAML arrays indistinguishable from JSON arrays.
* Fixes #3890

hugolib/datafiles_test.go
hugolib/site.go
parser/frontmatter.go

index de124a77da8603706e427d83f65785d3f5779d59..6b66a51eb73009796537b73acc2b3f332cd1f280 100644 (file)
@@ -95,25 +95,23 @@ func TestDataDirBoolean(t *testing.T) {
 
 func TestDataDirTwoFiles(t *testing.T) {
        t.Parallel()
-       equivDataDirs := make([]dataDir, 2)
+       equivDataDirs := make([]dataDir, 3)
 
        equivDataDirs[0].addSource("data/test/foo.json", `{ "bar": "foofoo"  }`)
-       equivDataDirs[0].addSource("data/test.json", `{ "hello": [ { "world": "foo" } ] }`)
+       equivDataDirs[0].addSource("data/test.json", `{ "hello": [ "world", "foo" ] }`)
 
        equivDataDirs[1].addSource("data/test/foo.yaml", "bar: foofoo")
-       equivDataDirs[1].addSource("data/test.yaml", "hello:\n- world: foo")
+       equivDataDirs[1].addSource("data/test.yaml", "hello:\n- world\n- foo")
 
-       // TODO Unresolved Issue #3890
-       /*
-               equivDataDirs[2].addSource("data/test/foo.toml", "bar = \"foofoo\"")
-               equivDataDirs[2].addSource("data/test.toml", "[[hello]]\nworld = \"foo\"")
-       */
+       equivDataDirs[2].addSource("data/test/foo.toml", "bar = \"foofoo\"")
+       equivDataDirs[2].addSource("data/test.toml", "hello = [\"world\", \"foo\"]")
 
        expected :=
                map[string]interface{}{
                        "test": map[string]interface{}{
                                "hello": []interface{}{
-                                       map[string]interface{}{"world": "foo"},
+                                       "world",
+                                       "foo",
                                },
                                "foo": map[string]interface{}{
                                        "bar": "foofoo",
@@ -156,54 +154,28 @@ func TestDataDirOverriddenValue(t *testing.T) {
        doTestEquivalentDataDirs(t, equivDataDirs, expected)
 }
 
-// Issue #4361
-func TestDataDirJSONArrayAtTopLevelOfFile(t *testing.T) {
-       t.Parallel()
-
-       var dd dataDir
-       dd.addSource("data/test.json", `[ { "hello": "world" }, { "what": "time" }, { "is": "lunch?" } ]`)
-
-       expected :=
-               map[string]interface{}{
-                       "test": []interface{}{
-                               map[string]interface{}{"hello": "world"},
-                               map[string]interface{}{"what": "time"},
-                               map[string]interface{}{"is": "lunch?"},
-                       },
-               }
-
-       doTestDataDir(t, dd, expected)
-}
-
-// TODO Issue #3890 unresolved
-func TestDataDirYAMLArrayAtTopLevelOfFile(t *testing.T) {
+// Issue #4361, #3890
+func TestDataDirArrayAtTopLevelOfFile(t *testing.T) {
        t.Parallel()
+       equivDataDirs := make([]dataDir, 2)
 
-       var dd dataDir
-       dd.addSource("data/test.yaml", `
+       equivDataDirs[0].addSource("data/test.json", `[ { "hello": "world" }, { "what": "time" }, { "is": "lunch?" } ]`)
+       equivDataDirs[1].addSource("data/test.yaml", `
 - hello: world
 - what: time
 - is: lunch?
 `)
 
-       //TODO decide whether desired structure map[interface {}]interface{} as shown
-       // and as the YAML parser produces, or should it be map[string]interface{}
-       // all the way down per Issue #4138
        expected :=
                map[string]interface{}{
                        "test": []interface{}{
-                               map[interface{}]interface{}{"hello": "world"},
-                               map[interface{}]interface{}{"what": "time"},
-                               map[interface{}]interface{}{"is": "lunch?"},
+                               map[string]interface{}{"hello": "world"},
+                               map[string]interface{}{"what": "time"},
+                               map[string]interface{}{"is": "lunch?"},
                        },
                }
 
-       // what we are actually getting as of v0.34
-       expectedV0_34 :=
-               map[string]interface{}{}
-       _ = expected
-
-       doTestDataDir(t, dd, expectedV0_34)
+       doTestEquivalentDataDirs(t, equivDataDirs, expected)
 }
 
 // Issue #892
index d62662814cdfe032ddfbce839b0d0b9aa90de225..95cd0a23edfc46ef29ff98df0162e16cce143225 100644 (file)
@@ -870,7 +870,7 @@ func (s *Site) readData(f source.ReadableFile) (interface{}, error) {
 
        switch f.Extension() {
        case "yaml", "yml":
-               return parser.HandleYAMLMetaData(content)
+               return parser.HandleYAMLData(content)
        case "json":
                return parser.HandleJSONData(content)
        case "toml":
index c1a57ce5b175bf4d0568bb7afbf270dc773e1ec7..5ed3ec11d23f1eff3742a73367e70040bcdc80e8 100644 (file)
@@ -216,6 +216,23 @@ func HandleYAMLMetaData(datum []byte) (map[string]interface{}, error) {
        return m, err
 }
 
+// HandleYAMLData unmarshals YAML-encoded datum and returns a Go interface
+// representing the encoded data structure.
+func HandleYAMLData(datum []byte) (interface{}, error) {
+       var m interface{}
+       err := yaml.Unmarshal(datum, &m)
+
+       // To support boolean keys, the `yaml` package unmarshals maps to
+       // map[interface{}]interface{}. Here we recurse through the result
+       // and change all maps to map[string]interface{} like we would've
+       // gotten from `json`.
+       if err == nil {
+               m = stringifyYAMLMapKeys(m)
+       }
+
+       return m, err
+}
+
 // stringifyKeysMapValue recurses into in and changes all instances of
 // map[interface{}]interface{} to map[string]interface{}. This is useful to
 // work around the impedence mismatch between JSON and YAML unmarshaling that's