lang/funcs: "anytrue" function
This is an analog to the "alltrue" function, using OR as the reduce operator rather than AND. This also includes some simplification of the "alltrue" implementation to implement it similarly as a sort of reduce operation with AND as the reduce operator, but with the same effective behavior.
This commit is contained in:
parent
5522a799f5
commit
d4716a69e1
|
@ -57,40 +57,54 @@ var LengthFunc = function.New(&function.Spec{
|
|||
})
|
||||
|
||||
// AllTrueFunc constructs a function that returns true if all elements of the
|
||||
// collection are true or "true". If the collection is empty, return true.
|
||||
// list are true. If the list is empty, return true.
|
||||
var AllTrueFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "collection",
|
||||
Type: cty.DynamicPseudoType,
|
||||
Name: "list",
|
||||
Type: cty.List(cty.Bool),
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.Bool),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
ty := args[0].Type()
|
||||
if !ty.IsListType() && !ty.IsTupleType() && !ty.IsSetType() {
|
||||
return cty.NilVal, errors.New("argument must be list, tuple, or set")
|
||||
}
|
||||
|
||||
tobool := MakeToFunc(cty.Bool)
|
||||
result := cty.True
|
||||
for it := args[0].ElementIterator(); it.Next(); {
|
||||
_, v := it.Element()
|
||||
if !v.IsKnown() {
|
||||
return cty.UnknownVal(cty.Bool), nil
|
||||
}
|
||||
got, err := tobool.Call([]cty.Value{v})
|
||||
if err != nil {
|
||||
if v.IsNull() {
|
||||
return cty.False, nil
|
||||
}
|
||||
eq, err := stdlib.Equal(got, cty.True)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
if eq.False() {
|
||||
result = result.And(v)
|
||||
if result.False() {
|
||||
return cty.False, nil
|
||||
}
|
||||
}
|
||||
return cty.True, nil
|
||||
return result, nil
|
||||
},
|
||||
})
|
||||
|
||||
// AnyTrueFunc constructs a function that returns true if any element of the
|
||||
// list is true. If the list is empty, return false.
|
||||
var AnyTrueFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "list",
|
||||
Type: cty.List(cty.Bool),
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.Bool),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
|
||||
result := cty.False
|
||||
for it := args[0].ElementIterator(); it.Next(); {
|
||||
_, v := it.Element()
|
||||
if v.IsNull() {
|
||||
continue
|
||||
}
|
||||
result = result.Or(v)
|
||||
if result.True() {
|
||||
return cty.True, nil
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -620,12 +634,18 @@ func Length(collection cty.Value) (cty.Value, error) {
|
|||
return LengthFunc.Call([]cty.Value{collection})
|
||||
}
|
||||
|
||||
// AllTrue returns true if all elements of the collection are true or "true".
|
||||
// If the collection is empty, return true.
|
||||
// AllTrue returns true if all elements of the list are true. If the list is empty,
|
||||
// return true.
|
||||
func AllTrue(collection cty.Value) (cty.Value, error) {
|
||||
return AllTrueFunc.Call([]cty.Value{collection})
|
||||
}
|
||||
|
||||
// AnyTrue returns true if any element of the list is true. If the list is empty,
|
||||
// return false.
|
||||
func AnyTrue(collection cty.Value) (cty.Value, error) {
|
||||
return AnyTrueFunc.Call([]cty.Value{collection})
|
||||
}
|
||||
|
||||
// Coalesce takes any number of arguments and returns the first one that isn't empty.
|
||||
func Coalesce(args ...cty.Value) (cty.Value, error) {
|
||||
return CoalesceFunc.Call(args)
|
||||
|
|
|
@ -146,17 +146,7 @@ func TestAllTrue(t *testing.T) {
|
|||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.ListValEmpty(cty.String),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.TupleVal([]cty.Value{}),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.SetValEmpty(cty.Bool),
|
||||
cty.ListValEmpty(cty.Bool),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
|
@ -165,16 +155,6 @@ func TestAllTrue(t *testing.T) {
|
|||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.StringVal("true")}),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.TupleVal([]cty.Value{cty.True, cty.StringVal("true")}),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.False}),
|
||||
cty.False,
|
||||
|
@ -191,24 +171,14 @@ func TestAllTrue(t *testing.T) {
|
|||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.NumberIntVal(1)}),
|
||||
cty.False,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.StringVal("true"),
|
||||
cty.False,
|
||||
cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}),
|
||||
cty.UnknownVal(cty.Bool),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.ListValEmpty(cty.String)}),
|
||||
cty.False,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
|
||||
cty.UnknownVal(cty.Bool),
|
||||
false,
|
||||
cty.NullVal(cty.List(cty.Bool)),
|
||||
cty.NilVal,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -232,6 +202,69 @@ func TestAllTrue(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAnyTrue(t *testing.T) {
|
||||
tests := []struct {
|
||||
Collection cty.Value
|
||||
Want cty.Value
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
cty.ListValEmpty(cty.Bool),
|
||||
cty.False,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.True}),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.False}),
|
||||
cty.False,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.True, cty.False}),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.False, cty.True}),
|
||||
cty.True,
|
||||
false,
|
||||
},
|
||||
{
|
||||
cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}),
|
||||
cty.UnknownVal(cty.Bool),
|
||||
true,
|
||||
},
|
||||
{
|
||||
cty.NullVal(cty.List(cty.Bool)),
|
||||
cty.NilVal,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(fmt.Sprintf("anytrue(%#v)", test.Collection), func(t *testing.T) {
|
||||
got, err := AnyTrue(test.Collection)
|
||||
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
if !got.RawEquals(test.Want) {
|
||||
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoalesce(t *testing.T) {
|
||||
tests := []struct {
|
||||
Values []cty.Value
|
||||
|
|
|
@ -34,6 +34,7 @@ func (s *Scope) Functions() map[string]function.Function {
|
|||
"abs": stdlib.AbsoluteFunc,
|
||||
"abspath": funcs.AbsPathFunc,
|
||||
"alltrue": funcs.AllTrueFunc,
|
||||
"anytrue": funcs.AnyTrueFunc,
|
||||
"basename": funcs.BasenameFunc,
|
||||
"base64decode": funcs.Base64DecodeFunc,
|
||||
"base64encode": funcs.Base64EncodeFunc,
|
||||
|
|
|
@ -69,11 +69,18 @@ func TestFunctions(t *testing.T) {
|
|||
|
||||
"alltrue": {
|
||||
{
|
||||
`alltrue([true])`,
|
||||
`alltrue(["true", true])`,
|
||||
cty.True,
|
||||
},
|
||||
},
|
||||
|
||||
"anytrue": {
|
||||
{
|
||||
`anytrue([])`,
|
||||
cty.False,
|
||||
},
|
||||
},
|
||||
|
||||
"base64decode": {
|
||||
{
|
||||
`base64decode("YWJjMTIzIT8kKiYoKSctPUB+")`,
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
layout: functions
|
||||
page_title: anytrue - Functions - Configuration Language
|
||||
sidebar_current: docs-funcs-collection-anytrue
|
||||
description: |-
|
||||
The anytrue function determines whether any element of a collection
|
||||
is true or "true". If the collection is empty, it returns false.
|
||||
---
|
||||
|
||||
# `anytrue` Function
|
||||
|
||||
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
|
||||
earlier, see
|
||||
[0.11 Configuration Language: Interpolation Syntax](../../configuration-0-11/interpolation.html).
|
||||
|
||||
`anytrue` returns `true` if any element in a given collection is `true`
|
||||
or `"true"`. It also returns `false` if the collection is empty.
|
||||
|
||||
```hcl
|
||||
anytrue(list)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```command
|
||||
> anytrue(["true"])
|
||||
true
|
||||
> anytrue([true])
|
||||
true
|
||||
> anytrue([true, false])
|
||||
true
|
||||
> anytrue([])
|
||||
false
|
||||
```
|
|
@ -142,6 +142,10 @@
|
|||
<a href="/docs/configuration/functions/alltrue.html">alltrue</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/functions/anytrue.html">anytrue</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/docs/configuration/functions/chunklist.html">chunklist</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue