summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data.go33
-rw-r--r--docs/content/functions.md68
-rw-r--r--gomplate.go2
-rw-r--r--test/integration/typeconv_funcs.bats19
-rw-r--r--typeconv.go18
-rw-r--r--typeconv_test.go100
6 files changed, 221 insertions, 19 deletions
diff --git a/data.go b/data.go
index 483f141b..995eb5bd 100644
--- a/data.go
+++ b/data.go
@@ -20,24 +20,20 @@ import (
// logFatal is defined so log.Fatal calls can be overridden for testing
var logFatalf = log.Fatalf
-func init() {
- // Add some types we want to be able to handle which can be missing by default
- err := mime.AddExtensionType(".json", "application/json")
- if err != nil {
- log.Fatal(err)
- }
- err = mime.AddExtensionType(".yml", "application/yaml")
- if err != nil {
- log.Fatal(err)
- }
- err = mime.AddExtensionType(".yaml", "application/yaml")
- if err != nil {
- log.Fatal(err)
- }
- err = mime.AddExtensionType(".csv", "text/csv")
+func regExtension(ext, typ string) {
+ err := mime.AddExtensionType(ext, typ)
if err != nil {
log.Fatal(err)
}
+}
+
+func init() {
+ // Add some types we want to be able to handle which can be missing by default
+ regExtension(".json", "application/json")
+ regExtension(".yml", "application/yaml")
+ regExtension(".yaml", "application/yaml")
+ regExtension(".csv", "text/csv")
+ regExtension(".toml", "application/toml")
sourceReaders = make(map[string]func(*Source, ...string) ([]byte, error))
@@ -184,18 +180,19 @@ func (d *Data) Datasource(alias string, args ...string) interface{} {
log.Fatalf("Couldn't read datasource '%s': %s", alias, err)
}
s := string(b)
+ ty := &TypeConv{}
if source.Type == "application/json" {
- ty := &TypeConv{}
return ty.JSON(s)
}
if source.Type == "application/yaml" {
- ty := &TypeConv{}
return ty.YAML(s)
}
if source.Type == "text/csv" {
- ty := &TypeConv{}
return ty.CSV(s)
}
+ if source.Type == "application/toml" {
+ return ty.TOML(s)
+ }
log.Fatalf("Datasources of type %s not yet supported", source.Type)
return nil
}
diff --git a/docs/content/functions.md b/docs/content/functions.md
index c8962146..2cf6a6c7 100644
--- a/docs/content/functions.md
+++ b/docs/content/functions.md
@@ -372,6 +372,44 @@ $ gomplate < input.tmpl
Hello world
```
+## `toml`
+
+Converts a [TOML](https://github.com/toml-lang/toml) document into an object.
+This can be used to access properties of TOML documents.
+
+Compatible with [TOML v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md).
+
+### Usage
+
+```go
+toml input
+```
+
+Can also be used in a pipeline:
+```go
+input | toml
+```
+
+### Arguments
+
+| name | description |
+|--------|-------|
+| `input` | the TOML document to parse |
+
+#### Example
+
+_`input.tmpl`:_
+```
+{{ $t := `[data]
+hello = "world"` -}}
+Hello {{ (toml $t).hello }}
+```
+
+```console
+$ gomplate -f input.tmpl
+Hello world
+```
+
## `csv`
Converts a CSV-format string into a 2-dimensional string array.
@@ -547,6 +585,34 @@ $ gomplate < input.tmpl
hello: world
```
+## `toTOML`
+
+Converts an object to a [TOML](https://github.com/toml-lang/toml) document.
+
+### Usage
+
+```go
+toTOML obj
+```
+
+Can also be used in a pipeline:
+```go
+obj | toTOML
+```
+
+### Arguments
+
+| name | description |
+|--------|-------|
+| `obj` | the object to marshal as a TOML document |
+
+#### Example
+
+```console
+$ gomplate -i '{{ `{"foo":"bar"}` | json | toTOML }}'
+foo = "bar"
+```
+
## `toCSV`
Converts an object to a CSV document. The input object must be a 2-dimensional
@@ -598,7 +664,7 @@ Parses a given datasource (provided by the [`--datasource/-d`](#--datasource-d)
Currently, `file://`, `http://`, `https://`, and `vault://` URLs are supported.
-Currently-supported formats are JSON, YAML, and CSV.
+Currently-supported formats are JSON, YAML, TOML, and CSV.
#### Examples
diff --git a/gomplate.go b/gomplate.go
index 78317634..f02c6f14 100644
--- a/gomplate.go
+++ b/gomplate.go
@@ -52,6 +52,7 @@ func NewGomplate(data *Data, leftDelim, rightDelim string) *Gomplate {
"jsonArray": typeconv.JSONArray,
"yaml": typeconv.YAML,
"yamlArray": typeconv.YAMLArray,
+ "toml": typeconv.TOML,
"csv": typeconv.CSV,
"csvByRow": typeconv.CSVByRow,
"csvByColumn": typeconv.CSVByColumn,
@@ -61,6 +62,7 @@ func NewGomplate(data *Data, leftDelim, rightDelim string) *Gomplate {
"toJSON": typeconv.ToJSON,
"toJSONPretty": typeconv.toJSONPretty,
"toYAML": typeconv.ToYAML,
+ "toTOML": typeconv.ToTOML,
"toCSV": typeconv.ToCSV,
"ec2meta": ec2meta.Meta,
"ec2dynamic": ec2meta.Dynamic,
diff --git a/test/integration/typeconv_funcs.bats b/test/integration/typeconv_funcs.bats
index 46c735cc..0b22f311 100644
--- a/test/integration/typeconv_funcs.bats
+++ b/test/integration/typeconv_funcs.bats
@@ -89,3 +89,22 @@ Languages are: {{ join $c.lang " and " }}'
[ "$status" -eq 0 ]
[[ "${output}" == "Languages are: C and Go and COBOL" ]]
}
+
+@test "'toml'" {
+ gomplate -i '{{ $t := `# comment
+foo = "bar"
+
+[baz]
+qux = "quux"` | toml -}}
+{{ $t.baz.qux }}'
+ [ "$status" -eq 0 ]
+ [[ "${output}" == "quux" ]]
+}
+
+@test "'toTOML'" {
+ gomplate -i '{{ "foo:\n bar:\n baz: qux" | yaml | toTOML }}'
+ [ "$status" -eq 0 ]
+ [[ "${output}" == "[foo]
+ [foo.bar]
+ baz = \"qux\"" ]]
+} \ No newline at end of file
diff --git a/typeconv.go b/typeconv.go
index 2d1734c8..f2597d1a 100644
--- a/typeconv.go
+++ b/typeconv.go
@@ -12,6 +12,8 @@ import (
yaml "gopkg.in/yaml.v2"
+ // XXX: replace once https://github.com/BurntSushi/toml/pull/179 is merged
+ "github.com/hairyhenderson/toml"
"github.com/ugorji/go/codec"
)
@@ -69,6 +71,12 @@ func (t *TypeConv) YAMLArray(in string) []interface{} {
return unmarshalArray(obj, in, yaml.Unmarshal)
}
+// TOML - Unmarshal a TOML Object
+func (t *TypeConv) TOML(in string) interface{} {
+ obj := make(map[string]interface{})
+ return unmarshalObj(obj, in, toml.Unmarshal)
+}
+
func parseCSV(args ...string) (records [][]string, hdr []string) {
delim := ","
var in string
@@ -249,6 +257,16 @@ func (t *TypeConv) ToYAML(in interface{}) string {
return marshalObj(in, yaml.Marshal)
}
+// ToTOML - Stringify a struct as TOML
+func (t *TypeConv) ToTOML(in interface{}) string {
+ buf := new(bytes.Buffer)
+ err := toml.NewEncoder(buf).Encode(in)
+ if err != nil {
+ log.Fatalf("Unable to marshal %s: %v", in, err)
+ }
+ return string(buf.Bytes())
+}
+
// Slice creates a slice from a bunch of arguments
func (t *TypeConv) Slice(args ...interface{}) []interface{} {
return args
diff --git a/typeconv_test.go b/typeconv_test.go
index 51b8cd87..5957d693 100644
--- a/typeconv_test.go
+++ b/typeconv_test.go
@@ -293,3 +293,103 @@ func TestToCSV(t *testing.T) {
assert.Equal(t, expected, ty.ToCSV(";", in))
}
+
+func TestTOML(t *testing.T) {
+ ty := new(TypeConv)
+ in := `# This is a TOML document. Boom.
+
+title = "TOML Example"
+
+[owner]
+name = "Tom Preston-Werner"
+organization = "GitHub"
+bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
+dob = 1979-05-27T07:32:00Z # First class dates? Why not?
+
+[database]
+server = "192.168.1.1"
+ports = [ 8001, 8001, 8002 ]
+connection_max = 5000
+enabled = true
+
+[servers]
+
+ # You can indent as you please. Tabs or spaces. TOML don't care.
+ [servers.alpha]
+ ip = "10.0.0.1"
+ dc = "eqdc10"
+
+ [servers.beta]
+ ip = "10.0.0.2"
+ dc = "eqdc10"
+
+[clients]
+data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
+
+# Line breaks are OK when inside arrays
+hosts = [
+ "alpha",
+ "omega"
+]
+`
+ expected := map[string]interface{}{
+ "title": "TOML Example",
+ "owner": map[string]interface{}{
+ "name": "Tom Preston-Werner",
+ "organization": "GitHub",
+ "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.",
+ "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
+ },
+ "database": map[string]interface{}{
+ "server": "192.168.1.1",
+ "ports": []interface{}{int64(8001), int64(8001), int64(8002)},
+ "connection_max": int64(5000),
+ "enabled": true,
+ },
+ "servers": map[string]interface{}{
+ "alpha": map[string]interface{}{
+ "ip": "10.0.0.1",
+ "dc": "eqdc10",
+ },
+ "beta": map[string]interface{}{
+ "ip": "10.0.0.2",
+ "dc": "eqdc10",
+ },
+ },
+ "clients": map[string]interface{}{
+ "data": []interface{}{
+ []interface{}{"gamma", "delta"},
+ []interface{}{int64(1), int64(2)},
+ },
+ "hosts": []interface{}{"alpha", "omega"},
+ },
+ }
+
+ assert.Equal(t, expected, ty.TOML(in))
+}
+
+func TestToTOML(t *testing.T) {
+ ty := new(TypeConv)
+ expected := `foo = "bar"
+one = 1
+true = true
+
+[down]
+ [down.the]
+ [down.the.rabbit]
+ hole = true
+`
+ in := map[string]interface{}{
+ "foo": "bar",
+ "one": 1,
+ "true": true,
+ "down": map[interface{}]interface{}{
+ "the": map[interface{}]interface{}{
+ "rabbit": map[interface{}]interface{}{
+ "hole": true,
+ },
+ },
+ },
+ }
+ assert.Equal(t, expected, ty.ToTOML(in))
+}