diff --git a/README.md b/README.md index ed6cf639f..4eba577ba 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,26 @@ $ FOO=true gomplate < input.tmpl foo ``` +#### `slice` + +Creates a slice. Useful when needing to `range` over a bunch of variables. + +##### Example + +_`input.tmpl`:_ +``` +{{range slice "Bart" "Lisa" "Maggie"}} +Hello, {{.}} +{{- end}} +``` + +```console +$ gomplate < input.tmpl +Hello, Bart +Hello, Lisa +Hello, Maggie +``` + #### `json` Converts a JSON string into an object. Only works for JSON Objects (not Arrays or other valid JSON types). This can be used to access properties of JSON objects. @@ -90,6 +110,23 @@ $ gomplate < input.tmpl Hello world ``` +#### `jsonArray` + +Converts a JSON string into a slice. Only works for JSON Arrays. + +##### Example + +_`input.tmpl`:_ +``` +Hello {{ index (getenv "FOO" | jsonArray) 1 }} +``` + +```console +$ export FOO='[ "you", "world" ]' +$ gomplate < input.tmpl +Hello world +``` + #### `ec2meta` Queries AWS [EC2 Instance Metadata](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) for information. This only retrieves data in the `meta-data` path -- for data in the `dynamic` path use `ec2dynamic`. diff --git a/main.go b/main.go index a04dc8938..a0109b3b9 100644 --- a/main.go +++ b/main.go @@ -63,6 +63,8 @@ func NewGomplate() *Gomplate { "getenv": env.Getenv, "bool": typeconv.Bool, "json": typeconv.JSON, + "jsonArray": typeconv.JSONArray, + "slice": typeconv.Slice, "ec2meta": ec2meta.Meta, "ec2dynamic": ec2meta.Dynamic, "ec2tag": ec2info.Tag, diff --git a/main_test.go b/main_test.go index a0db9c94d..d87831481 100644 --- a/main_test.go +++ b/main_test.go @@ -34,12 +34,10 @@ func TestGetenvTemplates(t *testing.T) { } func TestBoolTemplates(t *testing.T) { - env := &Env{} typeconv := &TypeConv{} g := &Gomplate{ funcMap: template.FuncMap{ - "getenv": env.Getenv, - "bool": typeconv.Bool, + "bool": typeconv.Bool, }, } assert.Equal(t, "true", testTemplate(g, `{{bool "true"}}`)) @@ -89,3 +87,27 @@ func TestEc2MetaTemplates_WithJSON(t *testing.T) { assert.Equal(t, "bar", testTemplate(g, `{{ (ec2meta "obj" | json).foo }}`)) assert.Equal(t, "bar", testTemplate(g, `{{ (ec2dynamic "obj" | json).foo }}`)) } + +func TestJSONArrayTemplates(t *testing.T) { + ty := new(TypeConv) + g := &Gomplate{ + funcMap: template.FuncMap{ + "jsonArray": ty.JSONArray, + }, + } + + assert.Equal(t, "[foo bar]", testTemplate(g, `{{jsonArray "[\"foo\",\"bar\"]"}}`)) + assert.Equal(t, "bar", testTemplate(g, `{{ index (jsonArray "[\"foo\",\"bar\"]") 1 }}`)) +} + +func TestSliceTemplates(t *testing.T) { + typeconv := &TypeConv{} + g := &Gomplate{ + funcMap: template.FuncMap{ + "slice": typeconv.Slice, + }, + } + assert.Equal(t, "foo", testTemplate(g, `{{index (slice "foo") 0}}`)) + assert.Equal(t, `[foo bar 42]`, testTemplate(g, `{{slice "foo" "bar" 42}}`)) + assert.Equal(t, `helloworld`, testTemplate(g, `{{range slice "hello" "world"}}{{.}}{{end}}`)) +} diff --git a/typeconv.go b/typeconv.go index 9d9a9d28c..dd17e0042 100644 --- a/typeconv.go +++ b/typeconv.go @@ -20,7 +20,7 @@ func (t *TypeConv) Bool(in string) bool { return false } -// JSON - Unmarshal a JSON string +// JSON - Unmarshal a JSON Object func (t *TypeConv) JSON(in string) map[string]interface{} { obj := make(map[string]interface{}) err := json.Unmarshal([]byte(in), &obj) @@ -29,3 +29,18 @@ func (t *TypeConv) JSON(in string) map[string]interface{} { } return obj } + +// JSONArray - Unmarshal a JSON Array +func (t *TypeConv) JSONArray(in string) []interface{} { + obj := make([]interface{}, 1) + err := json.Unmarshal([]byte(in), &obj) + if err != nil { + log.Fatalf("Unable to unmarshal JSON array %s: %v", in, err) + } + return obj +} + +// 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 0baf851bf..7611aa417 100644 --- a/typeconv_test.go +++ b/typeconv_test.go @@ -35,3 +35,20 @@ func TestJSON(t *testing.T) { assert.Equal(t, expected["one"], actual["one"]) assert.Equal(t, expected["true"], actual["true"]) } + +func TestJSONArray(t *testing.T) { + ty := new(TypeConv) + + expected := []string{"foo", "bar"} + actual := ty.JSONArray(`["foo","bar"]`) + assert.Equal(t, expected[0], actual[0]) + assert.Equal(t, expected[1], actual[1]) +} + +func TestSlice(t *testing.T) { + ty := new(TypeConv) + expected := []string{"foo", "bar"} + actual := ty.Slice("foo", "bar") + assert.Equal(t, expected[0], actual[0]) + assert.Equal(t, expected[1], actual[1]) +}