Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding TOML support #154

Merged
merged 2 commits into from
Jun 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 15 additions & 18 deletions data.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -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
}
Expand Down
68 changes: 67 additions & 1 deletion docs/content/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
6 changes: 4 additions & 2 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import:
- package: github.com/ugorji/go
subpackages:
- codec
- package: github.com/hairyhenderson/toml
version: support-map-interface-keys
testImport:
- package: github.com/stretchr/testify
version: ^1.1.4
Expand Down
2 changes: 2 additions & 0 deletions gomplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down
19 changes: 19 additions & 0 deletions test/integration/typeconv_funcs.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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\"" ]]
}
18 changes: 18 additions & 0 deletions typeconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
100 changes: 100 additions & 0 deletions typeconv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
5 changes: 5 additions & 0 deletions vendor/github.com/hairyhenderson/toml/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions vendor/github.com/hairyhenderson/toml/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions vendor/github.com/hairyhenderson/toml/COMPATIBLE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions vendor/github.com/hairyhenderson/toml/COPYING

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading