Skip to content

Commit

Permalink
Add avg and values functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Cameron Stitt committed Jul 8, 2018
1 parent 2d98163 commit 430b06e
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 0 deletions.
1 change: 1 addition & 0 deletions interpolation/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var CoreFunctions = map[string]ast.Function{
// math
"max": interpolationFuncMax(),
"min": interpolationFuncMin(),
"avg": interpolationFuncAvg(),

// encoding
"jsonencode": interpolationFuncJSONEncode(),
Expand Down
27 changes: 27 additions & 0 deletions interpolation/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@ func interpolationFuncKeys() ast.Function {
}
}

// interpolationFuncValues extracts the values from a map
func interpolationFuncValues() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeMap},
ReturnType: ast.TypeList,
Variadic: false,
Callback: func(inputs []interface{}) (interface{}, error) {
mapInput := inputs[0].(map[string]ast.Variable)
values := make([]interface{}, 0, len(mapInput)+1)
result := make([]ast.Variable, 0, len(mapInput)+1)
for _, val := range mapInput {
values = append(values, val)
}

for _, val := range values {
nativeValue, err := hil.InterfaceToVariable(val)
if err != nil {
return nil, err
}
result = append(result, nativeValue)
}

return result, nil
},
}
}

// interpolationFuncMerge will merge multiple maps into a single map. Last reference of a key will always win.
func interpolationFuncMerge() ast.Function {
return ast.Function{
Expand Down
33 changes: 33 additions & 0 deletions interpolation/maps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,39 @@ func TestInterpolationFuncKeys(t *testing.T) {
}
}

func TestInterpolationFuncValues(t *testing.T) {
testCases := []functionTestCase{
{
description: "Returns the values",
text: `${values(foo)}`,
expectation: []interface{}{"other2", "other"},
vars: map[string]ast.Variable{
"foo": ast.Variable{
Type: ast.TypeMap,
Value: map[string]ast.Variable{
"bar2": ast.Variable{
Type: ast.TypeString,
Value: "other2",
},
"bar": ast.Variable{
Type: ast.TypeString,
Value: "other",
},
},
},
},
},
}

valuesTestFunc := testInterpolationFunc(keyFuncs{"values": interpolationFuncValues})

for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
valuesTestFunc(t, tc)
})
}
}

func TestInterpolationFuncMerge(t *testing.T) {
testCases := []functionTestCase{
{
Expand Down
21 changes: 21 additions & 0 deletions interpolation/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,24 @@ func interpolationFuncMin() ast.Function {
},
}
}

// InterpolationFuncAvg calculates the average of the given numbers
func interpolationFuncAvg() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{},
ReturnType: ast.TypeFloat,
Variadic: true,
VariadicType: ast.TypeFloat,
Callback: func(inputs []interface{}) (interface{}, error) {
inputLen := len(inputs)
if inputLen == 0 {
return nil, errors.New("avg function requires at least 1 inputs")
}
total := float64(0)
for _, input := range inputs {
total += input.(float64)
}
return total / float64(inputLen), nil
},
}
}
33 changes: 33 additions & 0 deletions interpolation/math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,36 @@ func TestInterpolationFuncMin(t *testing.T) {
})
}
}

func TestInterpolationFuncAvg(t *testing.T) {
testCases := []functionTestCase{
{
description: "Find average of 20 and 80",
text: `${avg(20, 80)}`,
expectation: "50",
},
{
description: "Single input finds average",
text: `${avg(10)}`,
expectation: "10",
},
{
description: "No inputs returns error",
text: `${avg()}`,
evalError: true,
},
{
description: "0 value returns average",
text: `${avg(0)}`,
expectation: "0",
},
}

avgTestFunc := testInterpolationFunc(keyFuncs{"avg": interpolationFuncAvg})

for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
avgTestFunc(t, tc)
})
}
}

0 comments on commit 430b06e

Please sign in to comment.