Skip to content

Commit

Permalink
Add 'default' value in case of presence of a variable
Browse files Browse the repository at this point in the history
Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
  • Loading branch information
ulyssessouza committed Jul 27, 2022
1 parent 0f4a387 commit 202f25a
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 9 deletions.
45 changes: 36 additions & 9 deletions template/template.go
Expand Up @@ -28,7 +28,7 @@ import (
var delimiter = "\\$"
var substitutionNamed = "[_a-z][_a-z0-9]*"

var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-?](.*}|[^}]*))?"
var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-+?](.*}|[^}]*))?"

var patternString = fmt.Sprintf(
"%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?P<braced>%s)}|(?P<invalid>))",
Expand Down Expand Up @@ -214,9 +214,10 @@ func recurseExtract(value interface{}, pattern *regexp.Regexp) map[string]Variab
}

type Variable struct {
Name string
DefaultValue string
Required bool
Name string
DefaultValue string
PresenceValue string
Required bool
}

func extractVariable(value interface{}, pattern *regexp.Regexp) ([]Variable, bool) {
Expand All @@ -240,6 +241,7 @@ func extractVariable(value interface{}, pattern *regexp.Regexp) ([]Variable, boo
}
name := val
var defaultValue string
var presenceValue string
var required bool
switch {
case strings.Contains(val, ":?"):
Expand All @@ -252,11 +254,16 @@ func extractVariable(value interface{}, pattern *regexp.Regexp) ([]Variable, boo
name, defaultValue = partition(val, ":-")
case strings.Contains(val, "-"):
name, defaultValue = partition(val, "-")
case strings.Contains(val, ":+"):
name, presenceValue = partition(val, ":+")
case strings.Contains(val, "+"):
name, presenceValue = partition(val, "+")
}
values = append(values, Variable{
Name: name,
DefaultValue: defaultValue,
Required: required,
Name: name,
DefaultValue: defaultValue,
PresenceValue: presenceValue,
Required: required,
})
}
return values, len(values) > 0
Expand All @@ -273,11 +280,11 @@ func defaultWhenUnset(substitution string, mapping Mapping) (string, bool, error
}

func defaultWhenNotEmpty(substitution string, mapping Mapping) (string, bool, error) {
return "", false, nil // TODO Implement ":+"
return withDefaultWhenPresence(substitution, mapping, true)
}

func defaultWhenSet(substitution string, mapping Mapping) (string, bool, error) {
return "", false, nil // TODO Implement "+"
return withDefaultWhenPresence(substitution, mapping, false)
}

func requiredErrorWhenEmptyOrUnset(substitution string, mapping Mapping) (string, bool, error) {
Expand All @@ -288,6 +295,26 @@ func requiredErrorWhenUnset(substitution string, mapping Mapping) (string, bool,
return withRequired(substitution, mapping, "?", func(_ string) bool { return true })
}

func withDefaultWhenPresence(substitution string, mapping Mapping, notEmpty bool) (string, bool, error) {
sep := "+"
if notEmpty {
sep = ":+"
}
if !strings.Contains(substitution, sep) {
return "", false, nil
}
name, defaultValue := partition(substitution, sep)
defaultValue, err := Substitute(defaultValue, mapping)
if err != nil {
return "", false, err
}
value, ok := mapping(name)
if ok && (!notEmpty || (notEmpty && value != "")) {
return defaultValue, true, nil
}
return value, true, nil
}

func withDefaultWhenAbsence(substitution string, mapping Mapping, emptyOrUnset bool) (string, bool, error) {
sep := "-"
if emptyOrUnset {
Expand Down
62 changes: 62 additions & 0 deletions template/template_test.go
Expand Up @@ -113,6 +113,42 @@ func TestEmptyValueWithHardDefault(t *testing.T) {
assert.Check(t, is.Equal("ok ", result))
}

func TestPresentValueWithUnset(t *testing.T) {
result, err := Substitute("ok ${UNSET_VAR:+presence_value}", defaultMapping)
assert.NilError(t, err)
assert.Check(t, is.Equal("ok ", result))
}

func TestPresentValueWithUnset2(t *testing.T) {
result, err := Substitute("ok ${UNSET_VAR+presence_value}", defaultMapping)
assert.NilError(t, err)
assert.Check(t, is.Equal("ok ", result))
}

func TestPresentValueWithNonEmpty(t *testing.T) {
result, err := Substitute("ok ${FOO:+presence_value}", defaultMapping)
assert.NilError(t, err)
assert.Check(t, is.Equal("ok presence_value", result))
}

func TestPresentValueAndNonEmptyWithNonEmpty(t *testing.T) {
result, err := Substitute("ok ${FOO+presence_value}", defaultMapping)
assert.NilError(t, err)
assert.Check(t, is.Equal("ok presence_value", result))
}

func TestPresentValueWithSet(t *testing.T) {
result, err := Substitute("ok ${BAR+presence_value}", defaultMapping)
assert.NilError(t, err)
assert.Check(t, is.Equal("ok presence_value", result))
}

func TestPresentValueAndNotEmptyWithSet(t *testing.T) {
result, err := Substitute("ok ${BAR:+presence_value}", defaultMapping)
assert.NilError(t, err)
assert.Check(t, is.Equal("ok ", result))
}

func TestNonAlphanumericDefault(t *testing.T) {
result, err := Substitute("ok ${BAR:-/non:-alphanumeric}", defaultMapping)
assert.NilError(t, err)
Expand Down Expand Up @@ -148,6 +184,14 @@ func TestDefaultsWithNestedExpansion(t *testing.T) {
template: "ok ${BAR:-${FOO} ${FOO}}",
expected: "ok first first",
},
{
template: "ok ${BAR+$FOO}",
expected: "ok first",
},
{
template: "ok ${BAR+$FOO ${FOO:+second}}",
expected: "ok first second",
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -398,6 +442,24 @@ func TestExtractVariables(t *testing.T) {
"project": {Name: "project", DefaultValue: "cli"},
},
},
{
name: "presence-value-nonEmpty",
dict: map[string]interface{}{
"foo": "${bar:+foo}",
},
expected: map[string]Variable{
"bar": {Name: "bar", PresenceValue: "foo"},
},
},
{
name: "presence-value",
dict: map[string]interface{}{
"foo": "${bar+foo}",
},
expected: map[string]Variable{
"bar": {Name: "bar", PresenceValue: "foo"},
},
},
}
for _, tc := range testCases {
tc := tc
Expand Down

0 comments on commit 202f25a

Please sign in to comment.