From a60fe27f46c373dfd23fc3d08cc70aa62f481d19 Mon Sep 17 00:00:00 2001 From: phuslu Date: Sun, 29 Nov 2020 15:56:59 +0800 Subject: [PATCH] add all/any for mutiple condition --- defaults.go | 22 ++++++++++++++++++++++ defaults_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ docs/defaults.md | 36 ++++++++++++++++++++++++++++++++++++ functions.go | 2 ++ 4 files changed, 101 insertions(+) diff --git a/defaults.go b/defaults.go index 8a35e396..b9f97966 100644 --- a/defaults.go +++ b/defaults.go @@ -69,6 +69,28 @@ func coalesce(v ...interface{}) interface{} { return nil } +// all returns true if empty(x) is false for all values x in the list. +// If the list is empty, return true. +func all(v ...interface{}) bool { + for _, val := range v { + if empty(val) { + return false + } + } + return true +} + +// any returns true if empty(x) is false for any x in the list. +// If the list is empty, return false. +func any(v ...interface{}) bool { + for _, val := range v { + if !empty(val) { + return true + } + } + return false +} + // fromJson decodes JSON into a structured value, ignoring errors. func fromJson(v string) interface{} { output, _ := mustFromJson(v) diff --git a/defaults_test.go b/defaults_test.go index 6f20b498..a35ebf62 100644 --- a/defaults_test.go +++ b/defaults_test.go @@ -63,6 +63,7 @@ func TestEmpty(t *testing.T) { t.Error(err) } } + func TestCoalesce(t *testing.T) { tests := map[string]string{ `{{ coalesce 1 }}`: "1", @@ -83,6 +84,46 @@ func TestCoalesce(t *testing.T) { } } +func TestAll(t *testing.T) { + tests := map[string]string{ + `{{ all 1 }}`: "true", + `{{ all "" 0 nil 2 }}`: "false", + `{{ $two := 2 }}{{ all "" 0 nil $two }}`: "false", + `{{ $two := 2 }}{{ all "" $two 0 0 0 }}`: "false", + `{{ $two := 2 }}{{ all "" $two 3 4 5 }}`: "false", + `{{ all }}`: "true", + } + for tpl, expect := range tests { + assert.NoError(t, runt(tpl, expect)) + } + + dict := map[string]interface{}{"top": map[string]interface{}{}} + tpl := `{{ all .top.NoSuchThing .bottom .bottom.dollar "airplane"}}` + if err := runtv(tpl, "false", dict); err != nil { + t.Error(err) + } +} + +func TestAny(t *testing.T) { + tests := map[string]string{ + `{{ any 1 }}`: "true", + `{{ any "" 0 nil 2 }}`: "true", + `{{ $two := 2 }}{{ any "" 0 nil $two }}`: "true", + `{{ $two := 2 }}{{ any "" $two 3 4 5 }}`: "true", + `{{ $zero := 0 }}{{ any "" $zero 0 0 0 }}`: "false", + `{{ any }}`: "false", + } + for tpl, expect := range tests { + assert.NoError(t, runt(tpl, expect)) + } + + dict := map[string]interface{}{"top": map[string]interface{}{}} + tpl := `{{ any .top.NoSuchThing .bottom .bottom.dollar "airplane"}}` + if err := runtv(tpl, "true", dict); err != nil { + t.Error(err) + } +} + func TestFromJson(t *testing.T) { dict := map[string]interface{}{"Input": `{"foo": 55}`} diff --git a/docs/defaults.md b/docs/defaults.md index b368eddf..b68cd83f 100644 --- a/docs/defaults.md +++ b/docs/defaults.md @@ -58,6 +58,42 @@ The above will first check to see if `.name` is empty. If it is not, it will ret that value. If it _is_ empty, `coalesce` will evaluate `.parent.name` for emptiness. Finally, if both `.name` and `.parent.name` are empty, it will return `Matt`. +## all + +The `all` function takes a list of values and returns true if all values are non-empty. + +``` +all 0 1 2 +``` + +The above returns `false`. + +This function is useful for evaluating multiple conditions of variables or values: + +``` +all (eq .Request.TLS.Version 0x0304) (.Request.ProtoAtLeast 2 0) (eq .Request.Method "POST") +``` + +The above will check http.Request is POST with tls 1.3 and http/2. + +## any + +The `any` function takes a list of values and returns true if any value is non-empty. + +``` +any 0 1 2 +``` + +The above returns `true`. + +This function is useful for evaluating multiple conditions of variables or values: + +``` +any (eq .Request.Method "GET") (eq .Request.Method "POST") (eq .Request.Method "OPTIONS") +``` + +The above will check http.Request method is one of GET/POST/OPTIONS. + ## fromJson, mustFromJson `fromJson` decodes a JSON document into a structure. If the input cannot be decoded as JSON the function will return an empty string. diff --git a/functions.go b/functions.go index b6f6e35e..c36979fe 100644 --- a/functions.go +++ b/functions.go @@ -219,6 +219,8 @@ var genericMap = map[string]interface{}{ "default": dfault, "empty": empty, "coalesce": coalesce, + "all": all, + "any": any, "compact": compact, "mustCompact": mustCompact, "fromJson": fromJson,