Skip to content

Commit

Permalink
Map support (#73)
Browse files Browse the repository at this point in the history
* support maps with "key1:val1,key2:val2" syntax

* quote the invalid string in error msgs

* document map support in the README

closes #70
  • Loading branch information
teepark committed Jan 24, 2017
1 parent 4069f29 commit f611eb3
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 36 deletions.
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export MYAPP_USER=Kelsey
export MYAPP_RATE="0.5"
export MYAPP_TIMEOUT="3m"
export MYAPP_USERS="rob,ken,robert"
export MYAPP_COLORCODES="red:1,green:2,blue:3"
```

Write some code:
Expand All @@ -37,12 +38,13 @@ import (
)

type Specification struct {
Debug bool
Port int
User string
Users []string
Rate float32
Timeout time.Duration
Debug bool
Port int
User string
Users []string
Rate float32
Timeout time.Duration
ColorCodes map[string]int
}

func main() {
Expand All @@ -61,6 +63,11 @@ func main() {
for _, u := range s.Users {
fmt.Printf(" %s\n", u)
}

fmt.Println("Color codes:")
for k, v := range s.ColorCodes {
fmt.Printf(" %s: %d\n", k, v)
}
}
```

Expand All @@ -76,6 +83,10 @@ Users:
rob
ken
robert
Color codes:
red: 1
green: 2
blue: 3
```

## Struct Tag Support
Expand Down Expand Up @@ -145,6 +156,8 @@ envconfig supports supports these struct field types:
* int8, int16, int32, int64
* bool
* float32, float64
* slices of any supported type
* maps (keys and values of any supported type)
* [encoding.TextUnmarshaler](https://golang.org/pkg/encoding/#TextUnmarshaler)

Embedded structs using these fields are also supported.
Expand Down
21 changes: 21 additions & 0 deletions envconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,27 @@ func processField(value string, field reflect.Value) error {
}
}
field.Set(sl)
case reflect.Map:
pairs := strings.Split(value, ",")
mp := reflect.MakeMap(typ)
for _, pair := range pairs {
kvpair := strings.Split(pair, ":")
if len(kvpair) != 2 {
return fmt.Errorf("invalid map item: %q", pair)
}
k := reflect.New(typ.Key()).Elem()
err := processField(kvpair[0], k)
if err != nil {
return err
}
v := reflect.New(typ.Elem()).Elem()
err = processField(kvpair[1], v)
if err != nil {
return err
}
mp.SetMapIndex(k, v)
}
field.Set(mp)
}

return nil
Expand Down
17 changes: 17 additions & 0 deletions envconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type Specification struct {
Timeout time.Duration
AdminUsers []string
MagicNumbers []int
ColorCodes map[string]int
MultiWordVar string
MultiWordVarWithAutoSplit uint32 `split_words:"true"`
SomePointer *string
Expand Down Expand Up @@ -77,6 +78,7 @@ func TestProcess(t *testing.T) {
os.Setenv("ENV_CONFIG_TIMEOUT", "2m")
os.Setenv("ENV_CONFIG_ADMINUSERS", "John,Adam,Will")
os.Setenv("ENV_CONFIG_MAGICNUMBERS", "5,10,20")
os.Setenv("ENV_CONFIG_COLORCODES", "red:1,green:2,blue:3")
os.Setenv("SERVICE_HOST", "127.0.0.1")
os.Setenv("ENV_CONFIG_TTL", "30")
os.Setenv("ENV_CONFIG_REQUIREDVAR", "foo")
Expand Down Expand Up @@ -130,6 +132,21 @@ func TestProcess(t *testing.T) {
t.Errorf("expected empty string, got %#v", s.Ignored)
}

if len(s.ColorCodes) != 3 ||
s.ColorCodes["red"] != 1 ||
s.ColorCodes["green"] != 2 ||
s.ColorCodes["blue"] != 3 {
t.Errorf(
"expected %#v, got %#v",
map[string]int{
"red": 1,
"green": 2,
"blue": 3,
},
s.ColorCodes,
)
}

if s.NestedSpecification.Property != "iamnested" {
t.Errorf("expected '%s' string, got %#v", "iamnested", s.NestedSpecification.Property)
}
Expand Down
1 change: 1 addition & 0 deletions testdata/custom.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ ENV_CONFIG_TTL=
ENV_CONFIG_TIMEOUT=
ENV_CONFIG_ADMINUSERS=
ENV_CONFIG_MAGICNUMBERS=
ENV_CONFIG_COLORCODES=
ENV_CONFIG_MULTIWORDVAR=
ENV_CONFIG_MULTI_WORD_VAR_WITH_AUTO_SPLIT=
ENV_CONFIG_SOMEPOINTER=
Expand Down
5 changes: 5 additions & 0 deletions testdata/default_list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ ENV_CONFIG_MAGICNUMBERS
..[type]........Comma-separated.list.of.Integer
..[default].....
..[required]....
ENV_CONFIG_COLORCODES
..[description].
..[type]........Comma-separated.list.of.String:Integer.pairs
..[default].....
..[required]....
ENV_CONFIG_MULTIWORDVAR
..[description].
..[type]........String
Expand Down
61 changes: 31 additions & 30 deletions testdata/default_table.txt
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
This.application.is.configured.via.the.environment..The.following.environment
variables.can.be.used:

KEY..............................................TYPE...............................DEFAULT...........REQUIRED....DESCRIPTION
ENV_CONFIG_ENABLED...............................True.or.False....................................................some.embedded.value
ENV_CONFIG_EMBEDDEDPORT..........................Integer..........................................................
ENV_CONFIG_MULTIWORDVAR..........................String...........................................................
ENV_CONFIG_MULTI_WITH_DIFFERENT_ALT..............String...........................................................
ENV_CONFIG_EMBEDDED_WITH_ALT.....................String...........................................................
ENV_CONFIG_DEBUG.................................True.or.False....................................................
ENV_CONFIG_PORT..................................Integer..........................................................
ENV_CONFIG_RATE..................................Float............................................................
ENV_CONFIG_USER..................................String...........................................................
ENV_CONFIG_TTL...................................Unsigned.Integer.................................................
ENV_CONFIG_TIMEOUT...............................Duration.........................................................
ENV_CONFIG_ADMINUSERS............................Comma-separated.list.of.String...................................
ENV_CONFIG_MAGICNUMBERS..........................Comma-separated.list.of.Integer..................................
ENV_CONFIG_MULTIWORDVAR..........................String...........................................................
ENV_CONFIG_MULTI_WORD_VAR_WITH_AUTO_SPLIT........Unsigned.Integer.................................................
ENV_CONFIG_SOMEPOINTER...........................String...........................................................
ENV_CONFIG_SOMEPOINTERWITHDEFAULT................String.............................foo2baz.......................foorbar.is.the.word
ENV_CONFIG_MULTI_WORD_VAR_WITH_ALT...............String...........................................................what.alt
ENV_CONFIG_MULTI_WORD_VAR_WITH_LOWER_CASE_ALT....String...........................................................
ENV_CONFIG_SERVICE_HOST..........................String...........................................................
ENV_CONFIG_DEFAULTVAR............................String.............................foobar........................
ENV_CONFIG_REQUIREDVAR...........................String...............................................true........
ENV_CONFIG_BROKER................................String.............................127.0.0.1.....................
ENV_CONFIG_REQUIREDDEFAULT.......................String.............................foo2bar...........true........
ENV_CONFIG_OUTER_INNER...........................String...........................................................
ENV_CONFIG_OUTER_PROPERTYWITHDEFAULT.............String.............................fuzzybydefault................
ENV_CONFIG_AFTERNESTED...........................String...........................................................
ENV_CONFIG_HONOR.................................HonorDecodeInStruct..............................................
ENV_CONFIG_DATETIME..............................Time.............................................................
KEY..............................................TYPE............................................DEFAULT...........REQUIRED....DESCRIPTION
ENV_CONFIG_ENABLED...............................True.or.False.................................................................some.embedded.value
ENV_CONFIG_EMBEDDEDPORT..........................Integer.......................................................................
ENV_CONFIG_MULTIWORDVAR..........................String........................................................................
ENV_CONFIG_MULTI_WITH_DIFFERENT_ALT..............String........................................................................
ENV_CONFIG_EMBEDDED_WITH_ALT.....................String........................................................................
ENV_CONFIG_DEBUG.................................True.or.False.................................................................
ENV_CONFIG_PORT..................................Integer.......................................................................
ENV_CONFIG_RATE..................................Float.........................................................................
ENV_CONFIG_USER..................................String........................................................................
ENV_CONFIG_TTL...................................Unsigned.Integer..............................................................
ENV_CONFIG_TIMEOUT...............................Duration......................................................................
ENV_CONFIG_ADMINUSERS............................Comma-separated.list.of.String................................................
ENV_CONFIG_MAGICNUMBERS..........................Comma-separated.list.of.Integer...............................................
ENV_CONFIG_COLORCODES............................Comma-separated.list.of.String:Integer.pairs..................................
ENV_CONFIG_MULTIWORDVAR..........................String........................................................................
ENV_CONFIG_MULTI_WORD_VAR_WITH_AUTO_SPLIT........Unsigned.Integer..............................................................
ENV_CONFIG_SOMEPOINTER...........................String........................................................................
ENV_CONFIG_SOMEPOINTERWITHDEFAULT................String..........................................foo2baz.......................foorbar.is.the.word
ENV_CONFIG_MULTI_WORD_VAR_WITH_ALT...............String........................................................................what.alt
ENV_CONFIG_MULTI_WORD_VAR_WITH_LOWER_CASE_ALT....String........................................................................
ENV_CONFIG_SERVICE_HOST..........................String........................................................................
ENV_CONFIG_DEFAULTVAR............................String..........................................foobar........................
ENV_CONFIG_REQUIREDVAR...........................String............................................................true........
ENV_CONFIG_BROKER................................String..........................................127.0.0.1.....................
ENV_CONFIG_REQUIREDDEFAULT.......................String..........................................foo2bar...........true........
ENV_CONFIG_OUTER_INNER...........................String........................................................................
ENV_CONFIG_OUTER_PROPERTYWITHDEFAULT.............String..........................................fuzzybydefault................
ENV_CONFIG_AFTERNESTED...........................String........................................................................
ENV_CONFIG_HONOR.................................HonorDecodeInStruct...........................................................
ENV_CONFIG_DATETIME..............................Time..........................................................................
1 change: 1 addition & 0 deletions testdata/fault.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@
{.Key}
{.Key}
{.Key}
{.Key}
6 changes: 6 additions & 0 deletions usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ func toTypeDescription(t reflect.Type) string {
switch t.Kind() {
case reflect.Array, reflect.Slice:
return fmt.Sprintf("Comma-separated list of %s", toTypeDescription(t.Elem()))
case reflect.Map:
return fmt.Sprintf(
"Comma-separated list of %s:%s pairs",
toTypeDescription(t.Key()),
toTypeDescription(t.Elem()),
)
case reflect.Ptr:
return toTypeDescription(t.Elem())
case reflect.Struct:
Expand Down

0 comments on commit f611eb3

Please sign in to comment.