Skip to content

Commit

Permalink
replace WithDelimiter by WithNameSplitter (#110)
Browse files Browse the repository at this point in the history
It uses WithDelimiter to customize splitting name of env/flag, which is
pretty limited. This PR replace it with WithNameSplitter which is
superset of WithDelimiter.
  • Loading branch information
ktong authored Feb 10, 2024
1 parent 4668822 commit b366fb3
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 29 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Add env.WithNameSplitter/flag.WithNameSplitter/pflag.WithNameSplitter to split the name of the flag/env (#110).

### Deprecated

- Deprecate env.WithDelimiter/flag.WithDelimiter/pflag.WithDelimiter in favor of WithNameSplitter (#110).

## [0.4.0] - 2024-02-07

### Added
Expand Down
11 changes: 5 additions & 6 deletions provider/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ import (
//
// To create a new Env, call New.
type Env struct {
_ [0]func() // Ensure it's incomparable.
prefix string
delimiter string
prefix string
splitter func(string) []string
}

// New creates an Env with the given Option(s).
Expand All @@ -33,8 +32,8 @@ func New(opts ...Option) Env {
for _, opt := range opts {
opt(option)
}
if option.delimiter == "" {
option.delimiter = "_"
if option.splitter == nil {
option.splitter = func(s string) []string { return strings.Split(s, "_") }
}

return Env(*option)
Expand All @@ -49,7 +48,7 @@ func (e Env) Load() (map[string]any, error) {
// The environment variable with empty value is treated as unset.
continue
}
maps.Insert(values, strings.Split(key, e.delimiter), value)
maps.Insert(values, e.splitter(key), value)
}
}

Expand Down
6 changes: 5 additions & 1 deletion provider/env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package env_test

import (
"strings"
"testing"

"github.com/nil-go/konf"
Expand Down Expand Up @@ -31,7 +32,10 @@ func TestEnv_Load(t *testing.T) {
},
{
description: "with delimiter",
opts: []env.Option{env.WithPrefix("P."), env.WithDelimiter(".")},
opts: []env.Option{
env.WithPrefix("P."),
env.WithNameSplitter(func(s string) []string { return strings.Split(s, ".") }),
},
expected: map[string]any{
"P": map[string]any{
"D": ".",
Expand Down
18 changes: 17 additions & 1 deletion provider/env/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package env

import "strings"

// WithPrefix provides the prefix used when loading environment variables.
// Only environment variables with names that start with the prefix will be loaded.
//
Expand All @@ -18,9 +20,23 @@ func WithPrefix(prefix string) Option {
//
// For example, with the default delimiter "_", an environment variable name like "PARENT_CHILD_KEY"
// would be split into "PARENT", "CHILD", and "KEY".
//
// Deprecated: use WithNameSplitter instead.
func WithDelimiter(delimiter string) Option {
return func(options *options) {
options.delimiter = delimiter
options.splitter = func(s string) []string {
return strings.Split(s, delimiter)
}
}
}

// WithNameSplitter provides the function used to split environment variable names into nested keys.
//
// For example, with the default splitter, an environment variable name like "PARENT_CHILD_KEY"
// would be split into "PARENT", "CHILD", and "KEY".
func WithNameSplitter(splitter func(string) []string) Option {
return func(options *options) {
options.splitter = splitter
}
}

Expand Down
14 changes: 7 additions & 7 deletions provider/flag/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ import (
//
// To create a new Flag, call [New].
type Flag struct {
konf konf
set *flag.FlagSet
delimiter string
prefix string
konf konf
set *flag.FlagSet
splitter func(string) []string
prefix string
}

type konf interface {
Expand All @@ -52,8 +52,8 @@ func New(konf konf, opts ...Option) Flag {
for _, opt := range opts {
opt(option)
}
if option.delimiter == "" {
option.delimiter = "."
if option.splitter == nil {
option.splitter = func(s string) []string { return strings.Split(s, ".") }
}
if option.set == nil {
if !flag.Parsed() {
Expand All @@ -72,7 +72,7 @@ func (f Flag) Load() (map[string]any, error) {
return
}

keys := strings.Split(flag.Name, f.delimiter)
keys := f.splitter(flag.Name)
val := flag.Value.String()
// Skip zero default value to avoid overriding values set by other loader.
if val == flag.DefValue && (f.konf.Exists(keys) || isZeroDefValue(flag)) {
Expand Down
6 changes: 5 additions & 1 deletion provider/flag/flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package flag_test

import (
"flag"
"strings"
"sync"
"testing"

Expand Down Expand Up @@ -41,7 +42,10 @@ func TestFlag_Load(t *testing.T) {
},
{
description: "with delimiter",
opts: []kflag.Option{kflag.WithDelimiter("_"), kflag.WithPrefix("p_")},
opts: []kflag.Option{
kflag.WithPrefix("p_"),
kflag.WithNameSplitter(func(s string) []string { return strings.Split(s, "_") }),
},
expected: map[string]any{
"p": map[string]any{
"d": "_",
Expand Down
21 changes: 19 additions & 2 deletions provider/flag/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

package flag

import "flag"
import (
"flag"
"strings"
)

// WithPrefix provides the prefix used when loading flags.
// Only flags with names that start with the prefix will be loaded.
Expand All @@ -29,9 +32,23 @@ func WithFlagSet(set *flag.FlagSet) Option {
//
// For example, with the default delimiter ".", an flag name like "parent.child.key"
// would be split into "parent", "child", and "key".
//
// Deprecated: use WithNameSplitter instead.
func WithDelimiter(delimiter string) Option {
return func(options *options) {
options.delimiter = delimiter
options.splitter = func(s string) []string {
return strings.Split(s, delimiter)
}
}
}

// WithNameSplitter provides the function used to split environment variable names into nested keys.
//
// For example, with the default splitter, an flag name like "parent.child.key"
// would be split into "parent", "child", and "key".
func WithNameSplitter(splitter func(string) []string) Option {
return func(options *options) {
options.splitter = splitter
}
}

Expand Down
22 changes: 20 additions & 2 deletions provider/pflag/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

package pflag

import "github.com/spf13/pflag"
import (
"strings"

"github.com/spf13/pflag"
)

// WithPrefix provides the prefix used when loading flags.
// Only flags with names that start with the prefix will be loaded.
Expand All @@ -29,9 +33,23 @@ func WithFlagSet(set *pflag.FlagSet) Option {
//
// For example, with the default delimiter ".", an flag name like "parent.child.key"
// would be split into "parent", "child", and "key".
//
// Deprecated: use WithNameSplitter instead.
func WithDelimiter(delimiter string) Option {
return func(options *options) {
options.delimiter = delimiter
options.splitter = func(s string) []string {
return strings.Split(s, delimiter)
}
}
}

// WithNameSplitter provides the function used to split environment variable names into nested keys.
//
// For example, with the default splitter, an flag name like "parent.child.key"
// // would be split into "parent", "child", and "key".
func WithNameSplitter(splitter func(string) []string) Option {
return func(options *options) {
options.splitter = splitter
}
}

Expand Down
14 changes: 7 additions & 7 deletions provider/pflag/pflag.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ import (
//
// To create a new PFlag, call [New].
type PFlag struct {
konf konf
set *pflag.FlagSet
delimiter string
prefix string
konf konf
set *pflag.FlagSet
splitter func(string) []string
prefix string
}

type konf interface {
Expand All @@ -54,8 +54,8 @@ func New(konf konf, opts ...Option) PFlag {
for _, opt := range opts {
opt(option)
}
if option.delimiter == "" {
option.delimiter = "."
if option.splitter == nil {
option.splitter = func(s string) []string { return strings.Split(s, ".") }
}
if option.set == nil {
if !pflag.Parsed() {
Expand All @@ -76,7 +76,7 @@ func (f PFlag) Load() (map[string]any, error) {
return
}

keys := strings.Split(flag.Name, f.delimiter)
keys := f.splitter(flag.Name)
val := f.flagVal(flag)
// Skip zero default value to avoid overriding values set by other loader.
if !flag.Changed && (f.konf.Exists(keys) || reflect.ValueOf(val).IsZero()) {
Expand Down
11 changes: 9 additions & 2 deletions provider/pflag/pflag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package pflag_test

import (
"flag"
"strings"
"testing"

"github.com/spf13/pflag"
Expand Down Expand Up @@ -35,14 +36,20 @@ func TestPFlag_Load(t *testing.T) {
}{
{
description: "with flag set",
opts: []kflag.Option{kflag.WithFlagSet(set), kflag.WithDelimiter("_")},
opts: []kflag.Option{
kflag.WithFlagSet(set),
kflag.WithNameSplitter(func(s string) []string { return strings.Split(s, "_") }),
},
expected: map[string]any{
"k": "v",
},
},
{
description: "with delimiter",
opts: []kflag.Option{kflag.WithDelimiter("_"), kflag.WithPrefix("p_")},
opts: []kflag.Option{
kflag.WithPrefix("p_"),
kflag.WithNameSplitter(func(s string) []string { return strings.Split(s, "_") }),
},
expected: map[string]any{
"p": map[string]any{
"d": "_",
Expand Down

0 comments on commit b366fb3

Please sign in to comment.