Merge pull request #25 from technosophos/feat/toml-parser

feat(chart): add values parser
pull/613/head
Matt Butcher 9 years ago
commit d3830753b4

8
glide.lock generated

@ -1,8 +1,10 @@
hash: 7f9a27ad54a10edaa7c57521246676477d0f84ef4246524bae75f8df9d049983
updated: 2016-04-14T12:24:49.130995956-06:00
hash: e7c99013acb06eb359cf20390579af9a4553ef0fbed3f7bbb784b4ab7c8df807
updated: 2016-04-15T15:15:21.87772545-06:00
imports:
- name: github.com/aokoli/goutils
version: 9c37978a95bd5c709a15883b6242714ea6709e64
- name: github.com/BurntSushi/toml
version: bbd5bb678321a0d6e58f1099321dfa73391c1b6f
- name: github.com/codegangsta/cli
version: 71f57d300dd6a780ac1856c005c4b518cfd498ec
- name: github.com/golang/protobuf
@ -28,7 +30,7 @@ imports:
- http2/hpack
- internal/timeseries
- name: google.golang.org/grpc
version: 9ac074585f926c8506b6351bfdc396d2b19b1cb1
version: 8eeecf2291de9d171d0b1392a27ff3975679f4f5
subpackages:
- codes
- credentials

@ -12,3 +12,4 @@ import:
- package: gopkg.in/yaml.v2
- package: github.com/Masterminds/semver
version: 1.1.0
- package: github.com/BurntSushi/toml

@ -0,0 +1,11 @@
poet = "Coleridge"
title = "Rime of the Ancient Mariner"
stanza = ["at", "length", "did", "cross", "an", "Albatross"]
[mariner]
with = "crossbow"
shot = "ALBATROSS"
[water.water]
where = "everywhere"
nor = "any drop to drink"

@ -0,0 +1,67 @@
package chart
import (
"errors"
"io/ioutil"
"strings"
"github.com/BurntSushi/toml"
)
var ErrNoTable = errors.New("no table")
type Values map[string]interface{}
// Table gets a table (TOML subsection) from a Values object.
//
// The table is returned as a Values.
//
// Compound table names may be specified with dots:
//
// foo.bar
//
// The above will be evaluated as "The table bar inside the table
// foo".
//
// An ErrNoTable is returned if the table does not exist.
func (v Values) Table(name string) (Values, error) {
names := strings.Split(name, ".")
table := v
var err error
for _, n := range names {
table, err = tableLookup(table, n)
if err != nil {
return table, err
}
}
return table, err
}
func tableLookup(v Values, simple string) (Values, error) {
v2, ok := v[simple]
if !ok {
return v, ErrNoTable
}
vv, ok := v2.(map[string]interface{})
if !ok {
return vv, ErrNoTable
}
return vv, nil
}
// ReadValues will parse TOML byte data into a Values.
func ReadValues(data []byte) (Values, error) {
out := map[string]interface{}{}
err := toml.Unmarshal(data, out)
return out, err
}
// ReadValuesFile will parse a TOML file into a Values.
func ReadValuesFile(filename string) (Values, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return map[string]interface{}{}, err
}
return ReadValues(data)
}

@ -0,0 +1,134 @@
package chart
import (
"bytes"
"fmt"
"testing"
"text/template"
)
func TestReadValues(t *testing.T) {
doc := `# Test TOML parse
poet = "Coleridge"
title = "Rime of the Ancient Mariner"
stanza = ["at", "length", "did", "cross", "an", "Albatross"]
[mariner]
with = "crossbow"
shot = "ALBATROSS"
[water.water]
where = "everywhere"
nor = "any drop to drink"
`
data, err := ReadValues([]byte(doc))
if err != nil {
t.Fatalf("Error parsing bytes: %s", err)
}
matchValues(t, data)
}
func TestReadValuesFile(t *testing.T) {
data, err := ReadValuesFile("./testdata/coleridge.toml")
if err != nil {
t.Fatalf("Error reading TOML file: %s", err)
}
matchValues(t, data)
}
func ExampleValues() {
doc := `title="Moby Dick"
[chapter.one]
title = "Loomings"
[chapter.two]
title = "The Carpet-Bag"
[chapter.three]
title = "The Spouter Inn"
`
d, err := ReadValues([]byte(doc))
if err != nil {
panic(err)
}
ch1, err := d.Table("chapter.one")
if err != nil {
panic("could not find chapter one")
}
fmt.Print(ch1["title"])
// Output:
// Loomings
}
func TestTable(t *testing.T) {
doc := `title="Moby Dick"
[chapter.one]
title = "Loomings"
[chapter.two]
title = "The Carpet-Bag"
[chapter.three]
title = "The Spouter Inn"
`
d, err := ReadValues([]byte(doc))
if err != nil {
t.Fatalf("Failed to parse the White Whale: %s", err)
}
if _, err := d.Table("title"); err == nil {
t.Fatalf("Title is not a table.")
}
if _, err := d.Table("chapter"); err != nil {
t.Fatalf("Failed to get the chapter table: %s\n%v", err, d)
}
if v, err := d.Table("chapter.one"); err != nil {
t.Errorf("Failed to get chapter.one: %s", err)
} else if v["title"] != "Loomings" {
t.Errorf("Unexpected title: %s", v["title"])
}
if _, err := d.Table("chapter.three"); err != nil {
t.Errorf("Chapter three is missing: %s\n%v", err, d)
}
if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil {
t.Errorf("I think you mean 'Epilogue'")
}
}
func matchValues(t *testing.T, data map[string]interface{}) {
if data["poet"] != "Coleridge" {
t.Errorf("Unexpected poet: %s", data["poet"])
}
if o, err := ttpl("{{len .stanza}}", data); err != nil {
t.Errorf("len stanza: %s", err)
} else if o != "6" {
t.Errorf("Expected 6, got %s", o)
}
if o, err := ttpl("{{.mariner.shot}}", data); err != nil {
t.Errorf(".mariner.shot: %s", err)
} else if o != "ALBATROSS" {
t.Errorf("Expected that mariner shot ALBATROSS")
}
if o, err := ttpl("{{.water.water.where}}", data); err != nil {
t.Errorf(".water.water.where: %s", err)
} else if o != "everywhere" {
t.Errorf("Expected water water everywhere")
}
}
func ttpl(tpl string, v map[string]interface{}) (string, error) {
var b bytes.Buffer
tt := template.Must(template.New("t").Parse(tpl))
if err := tt.Execute(&b, v); err != nil {
return "", err
}
return b.String(), nil
}
Loading…
Cancel
Save