diff --git a/defaults.go b/defaults.go index b9f97966..f2c00893 100644 --- a/defaults.go +++ b/defaults.go @@ -3,6 +3,7 @@ package sprig import ( "bytes" "encoding/json" + "gopkg.in/yaml.v3" "math/rand" "reflect" "strings" @@ -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 { diff --git a/defaults_test.go b/defaults_test.go index a35ebf62..a5a390dc 100644 --- a/defaults_test.go +++ b/defaults_test.go @@ -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}}` diff --git a/docs/defaults.md b/docs/defaults.md index b68cd83f..49a87a69 100644 --- a/docs/defaults.md +++ b/docs/defaults.md @@ -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 diff --git a/functions.go b/functions.go index 57fcec1d..5b98e0a7 100644 --- a/functions.go +++ b/functions.go @@ -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() } @@ -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, @@ -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, diff --git a/go.mod b/go.mod index 494916f1..c96ec052 100644 --- a/go.mod +++ b/go.mod @@ -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.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 11a67119..8fe52150 100644 --- a/go.sum +++ b/go.sum @@ -59,3 +59,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=