Add map and pair helper functions for bundle templates (#665)

## Changes
Go text templates allows only specifying one input argument for
invocations of associated templates (ie `{{template ...}}`). This PR
introduces the map and pair functions which allow template authors to
work around this limitation by passing multiple arguments as key value
pairs in a map.

This PR is based on feedback from the mlops stacks migration where
otherwise a bunch of duplicate code is required for computed values and
fixtures.

## Tests
Unit test
This commit is contained in:
shreyas-goenka 2023-08-15 18:07:22 +02:00 committed by GitHub
parent 61b103318f
commit 6c644e159c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 0 deletions

View File

@ -15,6 +15,11 @@ func (err ErrFail) Error() string {
return err.msg return err.msg
} }
type pair struct {
k string
v any
}
var helperFuncs = template.FuncMap{ var helperFuncs = template.FuncMap{
"fail": func(format string, args ...any) (any, error) { "fail": func(format string, args ...any) (any, error) {
return nil, ErrFail{fmt.Sprintf(format, args...)} return nil, ErrFail{fmt.Sprintf(format, args...)}
@ -27,4 +32,23 @@ var helperFuncs = template.FuncMap{
"regexp": func(expr string) (*regexp.Regexp, error) { "regexp": func(expr string) (*regexp.Regexp, error) {
return regexp.Compile(expr) return regexp.Compile(expr)
}, },
// A key value pair. This is used with the map function to generate maps
// to use inside a template
"pair": func(k string, v any) pair {
return pair{k, v}
},
// map converts a list of pairs to a map object. This is useful to pass multiple
// objects to templates defined in the library directory. Go text template
// syntax for invoking a template only allows specifying a single argument,
// this function can be used to workaround that limitation.
//
// For example: {{template "my_template" (map (pair "foo" $arg1) (pair "bar" $arg2))}}
// $arg1 and $arg2 can be referred from inside "my_template" as ".foo" and ".bar"
"map": func(pairs ...pair) map[string]any {
result := make(map[string]any, 0)
for _, p := range pairs {
result[p.k] = p.v
}
return result
},
} }

View File

@ -54,3 +54,18 @@ func TestTemplateUrlFunction(t *testing.T) {
assert.Len(t, r.files, 1) assert.Len(t, r.files, 1)
assert.Equal(t, "https://www.databricks.com", string(r.files[0].(*inMemoryFile).content)) assert.Equal(t, "https://www.databricks.com", string(r.files[0].(*inMemoryFile).content))
} }
func TestTemplateMapPairFunction(t *testing.T) {
ctx := context.Background()
tmpDir := t.TempDir()
r, err := newRenderer(ctx, nil, "./testdata/map-pair/template", "./testdata/map-pair/library", tmpDir)
require.NoError(t, err)
err = r.walk()
assert.NoError(t, err)
assert.Len(t, r.files, 1)
assert.Equal(t, "false 123 hello 12.3", string(r.files[0].(*inMemoryFile).content))
}

View File

@ -0,0 +1,3 @@
{{- define "my_template" -}}
{{- .foo}} {{.bar}} {{.abc}} {{.def -}}
{{- end -}}

View File

@ -0,0 +1 @@
{{template "my_template" (map (pair "foo" false) (pair "bar" 123) (pair "abc" "hello") (pair "def" 12.3)) -}}