Merge #3239: "compact" interpolation function
This commit is contained in:
commit
3c939f9b26
|
@ -20,6 +20,7 @@ var Funcs map[string]ast.Function
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Funcs = map[string]ast.Function{
|
Funcs = map[string]ast.Function{
|
||||||
|
"compact": interpolationFuncCompact(),
|
||||||
"concat": interpolationFuncConcat(),
|
"concat": interpolationFuncConcat(),
|
||||||
"element": interpolationFuncElement(),
|
"element": interpolationFuncElement(),
|
||||||
"file": interpolationFuncFile(),
|
"file": interpolationFuncFile(),
|
||||||
|
@ -35,6 +36,22 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interpolationFuncCompact strips a list of multi-variable values
|
||||||
|
// (e.g. as returned by "split") of any empty strings.
|
||||||
|
func interpolationFuncCompact() ast.Function {
|
||||||
|
return ast.Function{
|
||||||
|
ArgTypes: []ast.Type{ast.TypeString},
|
||||||
|
ReturnType: ast.TypeString,
|
||||||
|
Variadic: false,
|
||||||
|
Callback: func(args []interface{}) (interface{}, error) {
|
||||||
|
if !IsStringList(args[0].(string)) {
|
||||||
|
return args[0].(string), nil
|
||||||
|
}
|
||||||
|
return StringList(args[0].(string)).Compact().String(), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// interpolationFuncConcat implements the "concat" function that
|
// interpolationFuncConcat implements the "concat" function that
|
||||||
// concatenates multiple strings. This isn't actually necessary anymore
|
// concatenates multiple strings. This isn't actually necessary anymore
|
||||||
// since our language supports string concat natively, but for backwards
|
// since our language supports string concat natively, but for backwards
|
||||||
|
|
|
@ -11,6 +11,33 @@ import (
|
||||||
"github.com/hashicorp/terraform/config/lang/ast"
|
"github.com/hashicorp/terraform/config/lang/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestInterpolateFuncCompact(t *testing.T) {
|
||||||
|
testFunction(t, testFunctionConfig{
|
||||||
|
Cases: []testFunctionCase{
|
||||||
|
// empty string within array
|
||||||
|
{
|
||||||
|
`${compact(split(",", "a,,b"))}`,
|
||||||
|
NewStringList([]string{"a", "b"}).String(),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// empty string at the end of array
|
||||||
|
{
|
||||||
|
`${compact(split(",", "a,b,"))}`,
|
||||||
|
NewStringList([]string{"a", "b"}).String(),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// single empty string
|
||||||
|
{
|
||||||
|
`${compact(split(",", ""))}`,
|
||||||
|
NewStringList([]string{}).String(),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestInterpolateFuncDeprecatedConcat(t *testing.T) {
|
func TestInterpolateFuncDeprecatedConcat(t *testing.T) {
|
||||||
testFunction(t, testFunctionConfig{
|
testFunction(t, testFunctionConfig{
|
||||||
Cases: []testFunctionCase{
|
Cases: []testFunctionCase{
|
||||||
|
|
|
@ -24,6 +24,20 @@ type StringList string
|
||||||
// ["", ""] => SLDSLDSLD
|
// ["", ""] => SLDSLDSLD
|
||||||
const stringListDelim = `B780FFEC-B661-4EB8-9236-A01737AD98B6`
|
const stringListDelim = `B780FFEC-B661-4EB8-9236-A01737AD98B6`
|
||||||
|
|
||||||
|
// Takes a Stringlist and returns one without empty strings in it
|
||||||
|
func (sl StringList) Compact() StringList {
|
||||||
|
parts := sl.Slice()
|
||||||
|
|
||||||
|
newlist := []string{}
|
||||||
|
// drop the empty strings
|
||||||
|
for i := range parts {
|
||||||
|
if parts[i] != "" {
|
||||||
|
newlist = append(newlist, parts[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NewStringList(newlist)
|
||||||
|
}
|
||||||
|
|
||||||
// Build a StringList from a slice
|
// Build a StringList from a slice
|
||||||
func NewStringList(parts []string) StringList {
|
func NewStringList(parts []string) StringList {
|
||||||
// We have to special case the empty list representation
|
// We have to special case the empty list representation
|
||||||
|
@ -55,11 +69,10 @@ func (sl StringList) Length() int {
|
||||||
func (sl StringList) Slice() []string {
|
func (sl StringList) Slice() []string {
|
||||||
parts := strings.Split(string(sl), stringListDelim)
|
parts := strings.Split(string(sl), stringListDelim)
|
||||||
|
|
||||||
switch len(parts) {
|
// split on an empty StringList will have a length of 2, since there is
|
||||||
case 0, 1:
|
// always at least one deliminator
|
||||||
|
if len(parts) <= 2 {
|
||||||
return []string{}
|
return []string{}
|
||||||
case 2:
|
|
||||||
return []string{""}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip empty elements generated by leading and trailing delimiters
|
// strip empty elements generated by leading and trailing delimiters
|
||||||
|
|
|
@ -27,3 +27,26 @@ func TestStringList_element(t *testing.T) {
|
||||||
list, expected, actual)
|
list, expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStringList_empty_slice(t *testing.T) {
|
||||||
|
expected := []string{}
|
||||||
|
l := NewStringList(expected)
|
||||||
|
actual := l.Slice()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Fatalf("Expected %q, got %q", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringList_empty_slice_length(t *testing.T) {
|
||||||
|
list := []string{}
|
||||||
|
l := NewStringList([]string{})
|
||||||
|
actual := l.Length()
|
||||||
|
|
||||||
|
expected := 0
|
||||||
|
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("Expected length of %q to be %d, got %d",
|
||||||
|
list, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -330,11 +330,6 @@ func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) {
|
||||||
Value: config.NewStringList([]string{}).String(),
|
Value: config.NewStringList([]string{}).String(),
|
||||||
Type: ast.TypeString,
|
Type: ast.TypeString,
|
||||||
})
|
})
|
||||||
// Zero + zero elements
|
|
||||||
testInterpolate(t, i, scope, "aws_route53_zone.terra.*.nothing", ast.Variable{
|
|
||||||
Value: config.NewStringList([]string{"", ""}).String(),
|
|
||||||
Type: ast.TypeString,
|
|
||||||
})
|
|
||||||
// Zero + 1 element
|
// Zero + 1 element
|
||||||
testInterpolate(t, i, scope, "aws_route53_zone.terra.*.special", ast.Variable{
|
testInterpolate(t, i, scope, "aws_route53_zone.terra.*.special", ast.Variable{
|
||||||
Value: config.NewStringList([]string{"extra"}).String(),
|
Value: config.NewStringList([]string{"extra"}).String(),
|
||||||
|
|
Loading…
Reference in New Issue