Add support for YAML array data files

* Unmarshaled YAML arrays indistinguishable from JSON arrays.
* Fixes #3890
This commit is contained in:
Vas Sudanagunta 2018-02-11 19:10:49 -05:00 committed by Bjørn Erik Pedersen
parent bb549a0d57
commit 1fa2417777
3 changed files with 35 additions and 46 deletions

View file

@ -95,25 +95,23 @@ func TestDataDirBoolean(t *testing.T) {
func TestDataDirTwoFiles(t *testing.T) { func TestDataDirTwoFiles(t *testing.T) {
t.Parallel() t.Parallel()
equivDataDirs := make([]dataDir, 2) equivDataDirs := make([]dataDir, 3)
equivDataDirs[0].addSource("data/test/foo.json", `{ "bar": "foofoo" }`) 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/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/foo.toml", "bar = \"foofoo\"")
equivDataDirs[2].addSource("data/test.toml", "[[hello]]\nworld = \"foo\"") equivDataDirs[2].addSource("data/test.toml", "hello = [\"world\", \"foo\"]")
*/
expected := expected :=
map[string]interface{}{ map[string]interface{}{
"test": map[string]interface{}{ "test": map[string]interface{}{
"hello": []interface{}{ "hello": []interface{}{
map[string]interface{}{"world": "foo"}, "world",
"foo",
}, },
"foo": map[string]interface{}{ "foo": map[string]interface{}{
"bar": "foofoo", "bar": "foofoo",
@ -156,12 +154,17 @@ func TestDataDirOverriddenValue(t *testing.T) {
doTestEquivalentDataDirs(t, equivDataDirs, expected) doTestEquivalentDataDirs(t, equivDataDirs, expected)
} }
// Issue #4361 // Issue #4361, #3890
func TestDataDirJSONArrayAtTopLevelOfFile(t *testing.T) { func TestDataDirArrayAtTopLevelOfFile(t *testing.T) {
t.Parallel() t.Parallel()
equivDataDirs := make([]dataDir, 2)
var dd dataDir equivDataDirs[0].addSource("data/test.json", `[ { "hello": "world" }, { "what": "time" }, { "is": "lunch?" } ]`)
dd.addSource("data/test.json", `[ { "hello": "world" }, { "what": "time" }, { "is": "lunch?" } ]`) equivDataDirs[1].addSource("data/test.yaml", `
- hello: world
- what: time
- is: lunch?
`)
expected := expected :=
map[string]interface{}{ map[string]interface{}{
@ -172,38 +175,7 @@ func TestDataDirJSONArrayAtTopLevelOfFile(t *testing.T) {
}, },
} }
doTestDataDir(t, dd, expected) doTestEquivalentDataDirs(t, equivDataDirs, expected)
}
// TODO Issue #3890 unresolved
func TestDataDirYAMLArrayAtTopLevelOfFile(t *testing.T) {
t.Parallel()
var dd dataDir
dd.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?"},
},
}
// what we are actually getting as of v0.34
expectedV0_34 :=
map[string]interface{}{}
_ = expected
doTestDataDir(t, dd, expectedV0_34)
} }
// Issue #892 // Issue #892

View file

@ -870,7 +870,7 @@ func (s *Site) readData(f source.ReadableFile) (interface{}, error) {
switch f.Extension() { switch f.Extension() {
case "yaml", "yml": case "yaml", "yml":
return parser.HandleYAMLMetaData(content) return parser.HandleYAMLData(content)
case "json": case "json":
return parser.HandleJSONData(content) return parser.HandleJSONData(content)
case "toml": case "toml":

View file

@ -216,6 +216,23 @@ func HandleYAMLMetaData(datum []byte) (map[string]interface{}, error) {
return m, err 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 // stringifyKeysMapValue recurses into in and changes all instances of
// map[interface{}]interface{} to map[string]interface{}. This is useful to // map[interface{}]interface{} to map[string]interface{}. This is useful to
// work around the impedence mismatch between JSON and YAML unmarshaling that's // work around the impedence mismatch between JSON and YAML unmarshaling that's