mirror of
https://github.com/Luzifer/rconfig.git
synced 2024-11-09 16:30:04 +00:00
Add AutoEnv feature
to automatically derive environment variable names from struct field names Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
954ac1f137
commit
f2a0efe97c
3 changed files with 108 additions and 2 deletions
64
autoenv.go
Normal file
64
autoenv.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package rconfig
|
||||
|
||||
import "strings"
|
||||
|
||||
type characterClass [2]rune
|
||||
|
||||
func (c characterClass) Contains(r rune) bool {
|
||||
return c[0] <= r && c[1] >= r
|
||||
}
|
||||
|
||||
type characterClasses []characterClass
|
||||
|
||||
func (c characterClasses) Contains(r rune) bool {
|
||||
for _, cc := range c {
|
||||
if cc.Contains(r) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
charGroupUpperLetter = characterClass{'A', 'Z'}
|
||||
charGroupLowerLetter = characterClass{'a', 'z'}
|
||||
charGroupNumber = characterClass{'0', '9'}
|
||||
charGroupLowerNumber = characterClasses{charGroupLowerLetter, charGroupNumber}
|
||||
)
|
||||
|
||||
func deriveEnvVarName(s string) string {
|
||||
var (
|
||||
words []string
|
||||
word []rune
|
||||
)
|
||||
|
||||
for _, l := range s {
|
||||
switch {
|
||||
case charGroupUpperLetter.Contains(l):
|
||||
if len(word) > 0 && charGroupLowerNumber.Contains(word[len(word)-1]) {
|
||||
words = append(words, string(word))
|
||||
word = []rune{}
|
||||
}
|
||||
word = append(word, l)
|
||||
|
||||
case charGroupLowerLetter.Contains(l):
|
||||
if len(word) > 1 && charGroupUpperLetter.Contains(word[len(word)-1]) {
|
||||
words = append(words, string(word[0:len(word)-1]))
|
||||
word = word[len(word)-1:]
|
||||
}
|
||||
word = append(word, l)
|
||||
|
||||
case charGroupNumber.Contains(l):
|
||||
word = append(word, l)
|
||||
|
||||
default:
|
||||
if len(word) > 0 {
|
||||
words = append(words, string(word))
|
||||
}
|
||||
word = []rune{}
|
||||
}
|
||||
}
|
||||
words = append(words, string(word))
|
||||
|
||||
return strings.ToUpper(strings.Join(words, "_"))
|
||||
}
|
29
autoenv_test.go
Normal file
29
autoenv_test.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package rconfig
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeriveEnvVarName(t *testing.T) {
|
||||
for test, expect := range map[string]string{
|
||||
"1Foobar": "1_FOOBAR",
|
||||
"BC1": "BC1",
|
||||
"BIGCase1": "BIG_CASE1",
|
||||
"BIGCase": "BIG_CASE",
|
||||
"Camel1": "CAMEL1",
|
||||
"camel": "CAMEL",
|
||||
"Camel": "CAMEL",
|
||||
"CAMEL": "CAMEL",
|
||||
"CamelCase": "CAMEL_CASE",
|
||||
"_foobar": "FOOBAR",
|
||||
"ILoveGoAndJSONSoMuch": "I_LOVE_GO_AND_JSON_SO_MUCH",
|
||||
"mrT": "MR_T",
|
||||
"my_case1": "MY_CASE1",
|
||||
"MyFieldName": "MY_FIELD_NAME",
|
||||
"SmallCASE": "SMALL_CASE",
|
||||
} {
|
||||
if d := deriveEnvVarName(test); d != expect {
|
||||
t.Errorf("Derived variable %q did not match expectation %q", d, expect)
|
||||
}
|
||||
}
|
||||
}
|
17
config.go
17
config.go
|
@ -17,6 +17,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
autoEnv bool
|
||||
fs *pflag.FlagSet
|
||||
variableDefaults map[string]string
|
||||
)
|
||||
|
@ -60,6 +61,13 @@ func Args() []string {
|
|||
return fs.Args()
|
||||
}
|
||||
|
||||
// AutoEnv enables or disables automated env variable guessing. If no `env` struct
|
||||
// tag was set and AutoEnv is enabled the env variable name is derived from the
|
||||
// name of the field: `MyFieldName` will get `MY_FIELD_NAME`
|
||||
func AutoEnv(enable bool) {
|
||||
autoEnv = enable
|
||||
}
|
||||
|
||||
// Usage prints a basic usage with the corresponding defaults for the flags to
|
||||
// os.Stdout. The defaults are derived from the `default` struct-tag and the ENV.
|
||||
func Usage() {
|
||||
|
@ -116,7 +124,7 @@ func execTags(in interface{}, fs *pflag.FlagSet) error {
|
|||
}
|
||||
|
||||
value := varDefault(typeField.Tag.Get("vardefault"), typeField.Tag.Get("default"))
|
||||
value = envDefault(typeField.Tag.Get("env"), value)
|
||||
value = envDefault(typeField, value)
|
||||
parts := strings.Split(typeField.Tag.Get("flag"), ",")
|
||||
|
||||
switch typeField.Type {
|
||||
|
@ -334,9 +342,14 @@ func registerFlagUint(t reflect.Kind, fs *pflag.FlagSet, field interface{}, part
|
|||
}
|
||||
}
|
||||
|
||||
func envDefault(env, def string) string {
|
||||
func envDefault(field reflect.StructField, def string) string {
|
||||
value := def
|
||||
|
||||
env := field.Tag.Get("env")
|
||||
if env == "" && autoEnv {
|
||||
env = deriveEnvVarName(field.Name)
|
||||
}
|
||||
|
||||
if env != "" {
|
||||
if e := os.Getenv(env); e != "" {
|
||||
value = e
|
||||
|
|
Loading…
Reference in a new issue