Add some basic math interpolation functions
Support the following math functions for interpolation: * ceil * floor * max * min Fixes #7409
This commit is contained in:
parent
0befa15522
commit
0fbd72a355
|
@ -10,6 +10,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"net"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
@ -54,6 +55,7 @@ func Funcs() map[string]ast.Function {
|
|||
"base64decode": interpolationFuncBase64Decode(),
|
||||
"base64encode": interpolationFuncBase64Encode(),
|
||||
"base64sha256": interpolationFuncBase64Sha256(),
|
||||
"ceil": interpolationFuncCeil(),
|
||||
"cidrhost": interpolationFuncCidrHost(),
|
||||
"cidrnetmask": interpolationFuncCidrNetmask(),
|
||||
"cidrsubnet": interpolationFuncCidrSubnet(),
|
||||
|
@ -63,6 +65,7 @@ func Funcs() map[string]ast.Function {
|
|||
"distinct": interpolationFuncDistinct(),
|
||||
"element": interpolationFuncElement(),
|
||||
"file": interpolationFuncFile(),
|
||||
"floor": interpolationFuncFloor(),
|
||||
"format": interpolationFuncFormat(),
|
||||
"formatlist": interpolationFuncFormatList(),
|
||||
"index": interpolationFuncIndex(),
|
||||
|
@ -72,8 +75,10 @@ func Funcs() map[string]ast.Function {
|
|||
"list": interpolationFuncList(),
|
||||
"lower": interpolationFuncLower(),
|
||||
"map": interpolationFuncMap(),
|
||||
"max": interpolationFuncMax(),
|
||||
"md5": interpolationFuncMd5(),
|
||||
"merge": interpolationFuncMerge(),
|
||||
"min": interpolationFuncMin(),
|
||||
"uuid": interpolationFuncUUID(),
|
||||
"replace": interpolationFuncReplace(),
|
||||
"sha1": interpolationFuncSha1(),
|
||||
|
@ -387,6 +392,66 @@ func interpolationFuncFormat() ast.Function {
|
|||
}
|
||||
}
|
||||
|
||||
// interpolationFuncMax returns the maximum of the numeric arguments
|
||||
func interpolationFuncMax() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{ast.TypeFloat},
|
||||
ReturnType: ast.TypeFloat,
|
||||
Variadic: true,
|
||||
VariadicType: ast.TypeFloat,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
max := args[0].(float64)
|
||||
|
||||
for i := 1; i < len(args); i++ {
|
||||
max = math.Max(max, args[i].(float64))
|
||||
}
|
||||
|
||||
return max, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// interpolationFuncMin returns the minimum of the numeric arguments
|
||||
func interpolationFuncMin() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{ast.TypeFloat},
|
||||
ReturnType: ast.TypeFloat,
|
||||
Variadic: true,
|
||||
VariadicType: ast.TypeFloat,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
min := args[0].(float64)
|
||||
|
||||
for i := 1; i < len(args); i++ {
|
||||
min = math.Min(min, args[i].(float64))
|
||||
}
|
||||
|
||||
return min, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// interpolationFuncCeil returns the the least integer value greater than or equal to the argument
|
||||
func interpolationFuncCeil() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{ast.TypeFloat},
|
||||
ReturnType: ast.TypeInt,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
return int(math.Ceil(args[0].(float64))), nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// interpolationFuncFloorreturns returns the greatest integer value less than or equal to the argument
|
||||
func interpolationFuncFloor() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{ast.TypeFloat},
|
||||
ReturnType: ast.TypeInt,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
return int(math.Floor(args[0].(float64))), nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func interpolationFuncZipMap() ast.Function {
|
||||
return ast.Function{
|
||||
ArgTypes: []ast.Type{
|
||||
|
|
|
@ -222,6 +222,150 @@ func TestInterpolateFuncList(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncMax(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
{
|
||||
`${max()}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${max("")}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${max(-1, 0, 1)}`,
|
||||
"1",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${max(1, 0, -1)}`,
|
||||
"1",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${max(-1, -2)}`,
|
||||
"-1",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${max(-1)}`,
|
||||
"-1",
|
||||
false,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncMin(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
{
|
||||
`${min()}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${min("")}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${min(-1, 0, 1)}`,
|
||||
"-1",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${min(1, 0, -1)}`,
|
||||
"-1",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${min(-1, -2)}`,
|
||||
"-2",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${min(-1)}`,
|
||||
"-1",
|
||||
false,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncFloor(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
{
|
||||
`${floor()}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${floor("")}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${floor("-1.3")}`, // there appears to be a AST bug where the parsed argument ends up being -1 without the "s
|
||||
"-2",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${floor(1.7)}`,
|
||||
"1",
|
||||
false,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncCeil(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
{
|
||||
`${ceil()}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${ceil("")}`,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
`${ceil(-1.8)}`,
|
||||
"-1",
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
`${ceil(1.2)}`,
|
||||
"2",
|
||||
false,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestInterpolateFuncMap(t *testing.T) {
|
||||
testFunction(t, testFunctionConfig{
|
||||
Cases: []testFunctionCase{
|
||||
|
|
|
@ -89,6 +89,9 @@ The supported built-in functions are:
|
|||
**This is not equivalent** of `base64encode(sha256(string))`
|
||||
since `sha256()` returns hexadecimal representation.
|
||||
|
||||
* `ceil(float)` - Returns the the least integer value greater than or equal
|
||||
to the argument.
|
||||
|
||||
* `cidrhost(iprange, hostnum)` - Takes an IP address range in CIDR notation
|
||||
and creates an IP address with the given host number. For example,
|
||||
``cidrhost("10.0.0.0/8", 2)`` returns ``10.0.0.2``.
|
||||
|
@ -137,6 +140,9 @@ The supported built-in functions are:
|
|||
module, you generally want to make the path relative to the module base,
|
||||
like this: `file("${path.module}/file")`.
|
||||
|
||||
* `floor(float)` - Returns the greatest integer value less than or equal to
|
||||
the argument
|
||||
|
||||
* `format(format, args, ...)` - Formats a string according to the given
|
||||
format. The syntax for the format is standard `sprintf` syntax.
|
||||
Good documentation for the syntax can be [found here](https://golang.org/pkg/fmt/).
|
||||
|
@ -197,11 +203,15 @@ The supported built-in functions are:
|
|||
* `map("hello", "world")`
|
||||
* `map("us-east", list("a", "b", "c"), "us-west", list("b", "c", "d"))`
|
||||
|
||||
* `max(float1, float2, ...)` - Returns the largest of the floats.
|
||||
|
||||
* `merge(map1, map2, ...)` - Returns the union of 2 or more maps. The maps
|
||||
are consumed in the order provided, and duplicate keys overwrite previous
|
||||
entries.
|
||||
* `${merge(map("a", "b"), map("c", "d"))}` returns `{"a": "b", "c": "d"}`
|
||||
|
||||
* `min(float1, float2, ...)` - Returns the smallest of the floats.
|
||||
|
||||
* `md5(string)` - Returns a (conventional) hexadecimal representation of the
|
||||
MD5 hash of the given string.
|
||||
|
||||
|
|
Loading…
Reference in New Issue