Skip to content

Commit

Permalink
Add anonymous:"true" tag to not include struct name in embedded struct
Browse files Browse the repository at this point in the history
  • Loading branch information
darinkrauss committed Oct 6, 2016
1 parent fb7a318 commit a7da422
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ $ CONFIGOR_APPNAME="hello world" CONFIGOR_DB_NAME="hello world" go run config.go
$ CONFIGOR_ENV_PREFIX="WEB" WEB_APPNAME="hello world" WEB_DB_NAME="hello world" go run config.go
```

* Anonymous Struct

Add the `anonymous:"true"` tag to an anonymous, embedded struct to NOT include the struct name in the environment
variable of any contained fields. For example:

```go
type Details struct {
Description string
}

type Config struct {
Details `anonymous:"true"`
}
```

With the `anonymous:"true"` tag specified, the environment variable for the `Description` field is `CONFIGOR_DESCRIPTION`.
Without the `anonymous:"true"`tag specified, then environment variable would include the embedded struct name and be `CONFIGOR_DETAILS_DESCRIPTION`.

* With flags

```go
Expand Down
11 changes: 9 additions & 2 deletions configor.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ func Load(config interface{}, files ...string) error {
}
}

func getPrefixForStruct(prefix []string, fieldStruct *reflect.StructField) []string {
if fieldStruct.Anonymous && fieldStruct.Tag.Get("anonymous") == "true" {
return prefix
}
return append(prefix, fieldStruct.Name)
}

func processTags(config interface{}, prefix ...string) error {
configValue := reflect.Indirect(reflect.ValueOf(config))
if configValue.Kind() != reflect.Struct {
Expand Down Expand Up @@ -140,7 +147,7 @@ func processTags(config interface{}, prefix ...string) error {
}

if field.Kind() == reflect.Struct {
if err := processTags(field.Addr().Interface(), append(prefix, fieldStruct.Name)...); err != nil {
if err := processTags(field.Addr().Interface(), getPrefixForStruct(prefix, &fieldStruct)...); err != nil {
return err
}
}
Expand All @@ -149,7 +156,7 @@ func processTags(config interface{}, prefix ...string) error {
var length = field.Len()
for i := 0; i < length; i++ {
if reflect.Indirect(field.Index(i)).Kind() == reflect.Struct {
if err := processTags(field.Index(i).Addr().Interface(), append(prefix, fieldStruct.Name, fmt.Sprintf("%d", i))...); err != nil {
if err := processTags(field.Index(i).Addr().Interface(), append(getPrefixForStruct(prefix, &fieldStruct), fmt.Sprintf("%d", i))...); err != nil {
return err
}
}
Expand Down
33 changes: 32 additions & 1 deletion configor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import (
"github.com/BurntSushi/toml"
)

type Anonymous struct {
Description string
}

type Config struct {
APPName string `default:"configor"`

Expand All @@ -28,6 +32,8 @@ type Config struct {
Name string
Email string `required:"true"`
}

Anonymous `anonymous:"true"`
}

func generateDefaultConfig() Config {
Expand All @@ -53,6 +59,9 @@ func generateDefaultConfig() Config {
Email: "[email protected]",
},
},
Anonymous: Anonymous{
Description: "This is an anonymous embedded struct whose environment variables should NOT include 'ANONYMOUS'",
},
}
return config
}
Expand Down Expand Up @@ -275,7 +284,7 @@ func TestReadFromEnvironmentWithSpecifiedEnvName(t *testing.T) {
file.Write(bytes)
var result Config
os.Setenv("DBPassword", "db_password")
defer os.Setenv("DBPassword", "db_password")
defer os.Setenv("DBPassword", "")
configor.Load(&result, file.Name())

var defaultConfig = generateDefaultConfig()
Expand All @@ -287,6 +296,28 @@ func TestReadFromEnvironmentWithSpecifiedEnvName(t *testing.T) {
}
}

func TestAnonymousStruct(t *testing.T) {
config := generateDefaultConfig()

if bytes, err := json.Marshal(config); err == nil {
if file, err := ioutil.TempFile("/tmp", "configor"); err == nil {
defer file.Close()
defer os.Remove(file.Name())
file.Write(bytes)
var result Config
os.Setenv("CONFIGOR_DESCRIPTION", "environment description")
defer os.Setenv("CONFIGOR_DESCRIPTION", "")
configor.Load(&result, file.Name())

var defaultConfig = generateDefaultConfig()
defaultConfig.Anonymous.Description = "environment description"
if !reflect.DeepEqual(result, defaultConfig) {
t.Errorf("result should equal to original configuration")
}
}
}
}

func TestENV(t *testing.T) {
if configor.ENV() != "test" {
t.Errorf("Env should be test when running `go test`")
Expand Down

0 comments on commit a7da422

Please sign in to comment.