diff --git a/cfger.go b/cfger.go index 748fc57..28d7617 100644 --- a/cfger.go +++ b/cfger.go @@ -59,8 +59,6 @@ var indexedPartRegexp = regexp.MustCompile(`(?m)([a-zA-Z]+)(?:\[(\d+)\])?`) // - beta: "hello" func (cl *ConfigLoader) Get(key string) OptionalItem { // httpcore[2].bananas - cl.lastKey = key - parts := strings.Split(key, ".") var cursor any = cl.rawConfigFileContents for _, part := range parts { @@ -87,9 +85,8 @@ func (cl *ConfigLoader) Get(key string) OptionalItem { return OptionalItem{key, cursor, true} } +// GetEnv gets a given key from the environment variables. func (cl *ConfigLoader) GetEnv(envKey string) OptionalItem { - cl.lastKey = envKey - ev := os.Getenv(envKey) if ev == "" { @@ -98,28 +95,3 @@ func (cl *ConfigLoader) GetEnv(envKey string) OptionalItem { return OptionalItem{envKey, ev, true} } - -// Required gets a given key from the currently loaded configuration and raises -// a fatal error if it cannot be found. -// -// See documentation for Get for key format. -func (cl *ConfigLoader) Required(key string) OptionalItem { - opt := cl.Get(key) - if !opt.found { - FatalErrorHandler(fmt.Errorf("required key %s not found in config file", key)) - os.Exit(1) - } - return opt -} - -// WithDefault gets a given key from the currently loaded configuration and -// returns a default value if it cannot be found. -// -// See documentation for Get for key format. -func (cl *ConfigLoader) WithDefault(key string, defaultValue any) OptionalItem { - opt := cl.Get(key) - if !opt.found { - return OptionalItem{item: defaultValue, found: true} - } - return opt -} diff --git a/types.go b/types.go index 7849aa9..7b754f1 100644 --- a/types.go +++ b/types.go @@ -1,11 +1,36 @@ package cfger +import ( + "fmt" + "os" + "strconv" +) + type OptionalItem struct { key string item any found bool } +// Required raises a fatal error if the item is not present +func (x OptionalItem) Required() OptionalItem { + if !x.found { + FatalErrorHandler(fmt.Errorf("required key %s not found in config", x.key)) + os.Exit(1) + } + return x +} + +// WithDefault returns the value if it is present, otherwise it returns the provided default value. +func (x OptionalItem) WithDefault(val any) OptionalItem { + if !x.found { + x.item = val + x.found = true + } + return x +} + +// AsInt returns the value of x as an integer, or 0 if no value is present. func (x OptionalItem) AsInt() int { if !x.found { return 0 @@ -13,6 +38,28 @@ func (x OptionalItem) AsInt() int { return x.item.(int) } +// ToInt parses x as an integer from a string and returns its value. If no value is present, 0 is returned, and if x is +// unparseable, a fatal error is raised. +func (x OptionalItem) ToInt() int { + if !x.found { + return 0 + } + + v, ok := x.item.(string) + if !ok { + FatalErrorHandler(fmt.Errorf("cfger: expected %s to be a string, got %T", x.key, x.item)) + os.Exit(1) + } + + iv, err := strconv.Atoi(v) + if err != nil { + FatalErrorHandler(fmt.Errorf("cfger: unable to parse %s as an integer: %w", x.key, err)) + } + + return iv +} + +// AsString returns the value of x as a string, or an empty string if no value is present. func (x OptionalItem) AsString() string { if !x.found { return "" @@ -20,9 +67,31 @@ func (x OptionalItem) AsString() string { return x.item.(string) } +// AsBool returns the value of x as a boolean, or an empty string if no value is present. func (x OptionalItem) AsBool() bool { if !x.found { return false } return x.item.(bool) } + +// ToBool parses x as a boolean from a string and returns its value. If no value is present, false is returned, and if x +// is unparseable, a fatal error is raised. +func (x OptionalItem) ToBool() bool { + if !x.found { + return false + } + + v, ok := x.item.(string) + if !ok { + FatalErrorHandler(fmt.Errorf("cfger: expected %s to be a string, got %T", x.key, x.item)) + os.Exit(1) + } + + iv, err := strconv.ParseBool(v) + if err != nil { + FatalErrorHandler(fmt.Errorf("cfger: unable to parse %s as an boolean: %w", x.key, err)) + } + + return iv +}