Skip to content

Commit

Permalink
feat: custom key value separator (#284)
Browse files Browse the repository at this point in the history
* feat: custom key value separator

* feat: custom key value separator

Separate test for key value separator

* feat: custom key value separator

Update README.md
  • Loading branch information
ruslan944 authored Sep 29, 2023
1 parent 6723663 commit 13ac655
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 6 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ If you set the `envDefault` tag for something, this value will be used in the
case of absence of it in the environment.

By default, slice types will split the environment value on `,`; you can change
this behavior by setting the `envSeparator` tag.
this behavior by setting the `envSeparator` tag. For map types, the default
separator between key and value is `:` and `,` for key-value pairs.
The behavior can be changed by setting the `envKeyValSeparator` and
`envSeparator` tags accordingly.

## Custom Parser Funcs

Expand Down
9 changes: 7 additions & 2 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,11 +518,16 @@ func handleMap(field reflect.Value, value string, sf reflect.StructField, funcMa
separator = ","
}

keyValSeparator := sf.Tag.Get("envKeyValSeparator")
if keyValSeparator == "" {
keyValSeparator = ":"
}

result := reflect.MakeMap(sf.Type)
for _, part := range strings.Split(value, separator) {
pairs := strings.Split(part, ":")
pairs := strings.Split(part, keyValSeparator)
if len(pairs) != 2 {
return newParseError(sf, fmt.Errorf(`%q should be in "key:value" format`, part))
return newParseError(sf, fmt.Errorf(`%q should be in "key%svalue" format`, part, keyValSeparator))
}

key, err := keyParserFunc(pairs[0])
Expand Down
14 changes: 11 additions & 3 deletions env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,10 @@ func TestParsesEnv(t *testing.T) {

func TestParsesEnv_Map(t *testing.T) {
type config struct {
MapStringString map[string]string `env:"MAP_STRING_STRING" envSeparator:","`
MapStringInt64 map[string]int64 `env:"MAP_STRING_INT64"`
MapStringBool map[string]bool `env:"MAP_STRING_BOOL" envSeparator:";"`
MapStringString map[string]string `env:"MAP_STRING_STRING" envSeparator:","`
MapStringInt64 map[string]int64 `env:"MAP_STRING_INT64"`
MapStringBool map[string]bool `env:"MAP_STRING_BOOL" envSeparator:";"`
CustomSeparatorMapStringString map[string]string `env:"CUSTOM_SEPARATOR_MAP_STRING_STRING" envSeparator:"," envKeyValSeparator:"|"`
}

mss := map[string]string{
Expand All @@ -426,12 +427,19 @@ func TestParsesEnv_Map(t *testing.T) {
}
t.Setenv("MAP_STRING_BOOL", "k1:true;k2:false")

withCustomSeparator := map[string]string{
"k1": "v1",
"k2": "v2",
}
t.Setenv("CUSTOM_SEPARATOR_MAP_STRING_STRING", "k1|v1,k2|v2")

var cfg config
isNoErr(t, Parse(&cfg))

isEqual(t, mss, cfg.MapStringString)
isEqual(t, msi, cfg.MapStringInt64)
isEqual(t, msb, cfg.MapStringBool)
isEqual(t, withCustomSeparator, cfg.CustomSeparatorMapStringString)
}

func TestParsesEnvInvalidMap(t *testing.T) {
Expand Down

0 comments on commit 13ac655

Please sign in to comment.