@@ -28,7 +28,7 @@ import (
2828var delimiter = "\\ $"
2929var substitutionNamed = "[_a-z][_a-z0-9]*"
3030
31- var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-?](.*}|[^}]*))?"
31+ var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-+ ?](.*}|[^}]*))?"
3232
3333var patternString = fmt .Sprintf (
3434 "%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?P<braced>%s)}|(?P<invalid>))" ,
@@ -214,9 +214,10 @@ func recurseExtract(value interface{}, pattern *regexp.Regexp) map[string]Variab
214214}
215215
216216type Variable struct {
217- Name string
218- DefaultValue string
219- Required bool
217+ Name string
218+ DefaultValue string
219+ PresenceValue string
220+ Required bool
220221}
221222
222223func extractVariable (value interface {}, pattern * regexp.Regexp ) ([]Variable , bool ) {
@@ -240,6 +241,7 @@ func extractVariable(value interface{}, pattern *regexp.Regexp) ([]Variable, boo
240241 }
241242 name := val
242243 var defaultValue string
244+ var presenceValue string
243245 var required bool
244246 switch {
245247 case strings .Contains (val , ":?" ):
@@ -252,11 +254,16 @@ func extractVariable(value interface{}, pattern *regexp.Regexp) ([]Variable, boo
252254 name , defaultValue = partition (val , ":-" )
253255 case strings .Contains (val , "-" ):
254256 name , defaultValue = partition (val , "-" )
257+ case strings .Contains (val , ":+" ):
258+ name , presenceValue = partition (val , ":+" )
259+ case strings .Contains (val , "+" ):
260+ name , presenceValue = partition (val , "+" )
255261 }
256262 values = append (values , Variable {
257- Name : name ,
258- DefaultValue : defaultValue ,
259- Required : required ,
263+ Name : name ,
264+ DefaultValue : defaultValue ,
265+ PresenceValue : presenceValue ,
266+ Required : required ,
260267 })
261268 }
262269 return values , len (values ) > 0
@@ -273,11 +280,11 @@ func defaultWhenUnset(substitution string, mapping Mapping) (string, bool, error
273280}
274281
275282func defaultWhenNotEmpty (substitution string , mapping Mapping ) (string , bool , error ) {
276- return "" , false , nil // TODO Implement ":+"
283+ return withDefaultWhenPresence ( substitution , mapping , true )
277284}
278285
279286func defaultWhenSet (substitution string , mapping Mapping ) (string , bool , error ) {
280- return "" , false , nil // TODO Implement "+"
287+ return withDefaultWhenPresence ( substitution , mapping , false )
281288}
282289
283290func requiredErrorWhenEmptyOrUnset (substitution string , mapping Mapping ) (string , bool , error ) {
@@ -288,6 +295,26 @@ func requiredErrorWhenUnset(substitution string, mapping Mapping) (string, bool,
288295 return withRequired (substitution , mapping , "?" , func (_ string ) bool { return true })
289296}
290297
298+ func withDefaultWhenPresence (substitution string , mapping Mapping , notEmpty bool ) (string , bool , error ) {
299+ sep := "+"
300+ if notEmpty {
301+ sep = ":+"
302+ }
303+ if ! strings .Contains (substitution , sep ) {
304+ return "" , false , nil
305+ }
306+ name , defaultValue := partition (substitution , sep )
307+ defaultValue , err := Substitute (defaultValue , mapping )
308+ if err != nil {
309+ return "" , false , err
310+ }
311+ value , ok := mapping (name )
312+ if ok && (! notEmpty || (notEmpty && value != "" )) {
313+ return defaultValue , true , nil
314+ }
315+ return value , true , nil
316+ }
317+
291318func withDefaultWhenAbsence (substitution string , mapping Mapping , emptyOrUnset bool ) (string , bool , error ) {
292319 sep := "-"
293320 if emptyOrUnset {
0 commit comments