Skip to content

Commit

Permalink
feat: add yaml to/from functions
Browse files Browse the repository at this point in the history
In the same vein of Masterminds#223, add YAML conversion functions. Fixes Masterminds#358.
  • Loading branch information
blakepettersson committed Feb 7, 2023
1 parent 581758e commit a16139f
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 15 deletions.
29 changes: 29 additions & 0 deletions defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sprig
import (
"bytes"
"encoding/json"
"gopkg.in/yaml.v2"
"math/rand"
"reflect"
"strings"
Expand Down Expand Up @@ -153,6 +154,34 @@ func mustToRawJson(v interface{}) (string, error) {
return strings.TrimSuffix(buf.String(), "\n"), nil
}

// fromYaml decodes YAML into a structured value, ignoring errors.
func fromYaml(v string) interface{} {
output, _ := mustFromYaml(v)
return output
}

// mustFromYaml decodes YAML into a structured value, returning errors.
func mustFromYaml(v string) (interface{}, error) {
var output interface{}
err := yaml.Unmarshal([]byte(v), &output)
return output, err
}

// toYaml encodes an item into a YAML string
func toYaml(v interface{}) string {
output, _ := mustToYaml(v)
return string(output)
}

// toYaml encodes an item into a YAML string, returning errors
func mustToYaml(v interface{}) (string, error) {
output, err := yaml.Marshal(v)
if err != nil {
return "", err
}
return string(output), nil
}

// ternary returns the first value if the last value is true, otherwise returns the second value.
func ternary(vt interface{}, vf interface{}, v bool) interface{} {
if v {
Expand Down
29 changes: 29 additions & 0 deletions defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,35 @@ func TestToJson(t *testing.T) {
}
}

func TestFromYaml(t *testing.T) {
dict := map[string]interface{}{"Input": `"foo": 55`}

tpl := `{{.Input | fromYaml}}`
expected := `map[foo:55]`
if err := runtv(tpl, expected, dict); err != nil {
t.Error(err)
}

tpl = `{{(.Input | fromYaml).foo}}`
expected = `55`
if err := runtv(tpl, expected, dict); err != nil {
t.Error(err)
}
}

func TestToYaml(t *testing.T) {
dict := map[string]interface{}{"Top": map[string]interface{}{"bool": true, "string": "test", "number": 42}}

tpl := `{{.Top | toYaml}}`
expected := `bool: true
number: 42
string: test
`
if err := runtv(tpl, expected, dict); err != nil {
t.Error(err)
}
}

func TestToPrettyJson(t *testing.T) {
dict := map[string]interface{}{"Top": map[string]interface{}{"bool": true, "string": "test", "number": 42}}
tpl := `{{.Top | toPrettyJson}}`
Expand Down
20 changes: 20 additions & 0 deletions docs/defaults.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,26 @@ toRawJson .Item

The above returns unescaped JSON string representation of `.Item`.

## fromYaml, mustFromYaml

`fromYaml` decodes a YAML document into a structure. If the input cannot be decoded as YAML the function will return an empty string.
`mustFromYaml` will return an error in case the YAML is invalid.

```
fromYaml "foo: 55"
```

## toYaml, mustToYaml

The `toYaml` function encodes an item into a YAML string. If the item cannot be converted to YAML the function will return an empty string.
`mustToYaml` will return an error in case the item cannot be encoded in YAML.

```
toYaml .Item
```

The above returns YAML string representation of `.Item`.

## ternary

The `ternary` function takes two values, and a test value. If the test value is
Expand Down
33 changes: 18 additions & 15 deletions functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import (
//
// Use this to pass the functions into the template engine:
//
// tpl := template.New("foo").Funcs(sprig.FuncMap()))
//
// tpl := template.New("foo").Funcs(sprig.FuncMap()))
func FuncMap() template.FuncMap {
return HtmlFuncMap()
}
Expand Down Expand Up @@ -251,6 +250,10 @@ var genericMap = map[string]interface{}{
"mustToJson": mustToJson,
"mustToPrettyJson": mustToPrettyJson,
"mustToRawJson": mustToRawJson,
"fromYaml": fromYaml,
"toYaml": toYaml,
"mustFromYaml": mustFromYaml,
"mustToYaml": mustToYaml,
"ternary": ternary,
"deepCopy": deepCopy,
"mustDeepCopy": mustDeepCopy,
Expand Down Expand Up @@ -336,20 +339,20 @@ var genericMap = map[string]interface{}{
"mustChunk": mustChunk,

// Crypto:
"bcrypt": bcrypt,
"htpasswd": htpasswd,
"genPrivateKey": generatePrivateKey,
"derivePassword": derivePassword,
"buildCustomCert": buildCustomCertificate,
"genCA": generateCertificateAuthority,
"genCAWithKey": generateCertificateAuthorityWithPEMKey,
"genSelfSignedCert": generateSelfSignedCertificate,
"bcrypt": bcrypt,
"htpasswd": htpasswd,
"genPrivateKey": generatePrivateKey,
"derivePassword": derivePassword,
"buildCustomCert": buildCustomCertificate,
"genCA": generateCertificateAuthority,
"genCAWithKey": generateCertificateAuthorityWithPEMKey,
"genSelfSignedCert": generateSelfSignedCertificate,
"genSelfSignedCertWithKey": generateSelfSignedCertificateWithPEMKey,
"genSignedCert": generateSignedCertificate,
"genSignedCertWithKey": generateSignedCertificateWithPEMKey,
"encryptAES": encryptAES,
"decryptAES": decryptAES,
"randBytes": randBytes,
"genSignedCert": generateSignedCertificate,
"genSignedCertWithKey": generateSignedCertificateWithPEMKey,
"encryptAES": encryptAES,
"decryptAES": decryptAES,
"randBytes": randBytes,

// UUIDs:
"uuidv4": uuidv4,
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ require (
github.com/spf13/cast v1.3.1
github.com/stretchr/testify v1.5.1
golang.org/x/crypto v0.3.0
gopkg.in/yaml.v2 v2.3.0
)

0 comments on commit a16139f

Please sign in to comment.