structconfig

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 16, 2024 License: MIT Imports: 3 Imported by: 7

README

structconfig

Map default values, environment variables, and command-line arguments to struct tags.

Examples

Default values

type T struct {
  I int `default:"10"`
}

sc := structconfig.New[T]()
var got T
if err := sc.FromDefault(&got); err != nil {
  panic(err)
}
// got.I == 10

Environment variables

type T struct {
  I int `name:"int_value"`
}

os.Setenv("INT_VALUE", "10")
sc := structconfig.New[T]()
var got T
if err := sc.FromDefault(&got); err != nil {
  panic(err)
}
// got.I == 10

Command-line flags (pflag)

type T struct {
  I int `name:"int_value" default:"10"`
}

var fs *pflag.FlagSet = // ...
sc := structconfig.New[T]()
if err := sc.SetFlags(fs); err != nil {
  panic(err)
}
if err := fs.Parse([]string{"--int_value", "100"}); err != nil {
  panic(err)
}
var got T
if err := sc.FromFlags(&got, fs); err != nil {
  panic(err)
}
// got.I == 100

More examples

Documentation

Index

Examples

Constants

View Source
const (
	TagName    = internal.TagName
	TagUsage   = internal.TagUsage
	TagDefault = internal.TagDefault
)

Variables

View Source
var (
	ErrStructConfig     = internal.ErrStructConfig
	ErrNotStruct        = internal.ErrNotStruct
	ErrNotStructPointer = internal.ErrNotStructPointer
)

Functions

func IsSupportedKind

func IsSupportedKind(k reflect.Kind) bool

Types

type AnyCallbackFunc

type AnyCallbackFunc = func(StructField, string, func() reflect.Value) error

type AnyEqualFunc

type AnyEqualFunc = func(left, right any) (bool, error)

type AnyReceptor

type AnyReceptor = internal.AnyReceptor

type BoolReceptor

type BoolReceptor = internal.BoolReceptor

type Config

type Config struct {
	AnyCallback *ConfigItem[AnyCallbackFunc]
	AnyEqual    *ConfigItem[AnyEqualFunc]
	Prefix      *ConfigItem[string]
}

func (*Config) Apply

func (s *Config) Apply(opt ...Option)

type ConfigBuilder

type ConfigBuilder struct {
	// contains filtered or unexported fields
}

func NewConfigBuilder

func NewConfigBuilder() *ConfigBuilder

func (*ConfigBuilder) AnyCallback

func (s *ConfigBuilder) AnyCallback(v AnyCallbackFunc) *ConfigBuilder

func (*ConfigBuilder) AnyEqual

func (s *ConfigBuilder) AnyEqual(v AnyEqualFunc) *ConfigBuilder

func (*ConfigBuilder) Build

func (s *ConfigBuilder) Build() *Config

func (*ConfigBuilder) Prefix

func (s *ConfigBuilder) Prefix(v string) *ConfigBuilder

type ConfigItem

type ConfigItem[T any] struct {
	// contains filtered or unexported fields
}

func NewConfigItem

func NewConfigItem[T any](defaultValue T) *ConfigItem[T]

func (*ConfigItem[T]) Default

func (s *ConfigItem[T]) Default() T

func (*ConfigItem[T]) Get

func (s *ConfigItem[T]) Get() T

func (*ConfigItem[T]) IsModified

func (s *ConfigItem[T]) IsModified() bool

func (*ConfigItem[T]) Set

func (s *ConfigItem[T]) Set(value T)

type EnvVar

type EnvVar = internal.EnvVar

type FloatReceptor

type FloatReceptor = internal.FloatReceptor

type IntReceptor

type IntReceptor = internal.IntReceptor

type Merger

type Merger[T any] struct {
	*internal.Merger[T]
}
Example
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"

	"github.com/berquerant/structconfig"
)

func main() {
	type T struct {
		I  int    `default:"1"`
		S  string `default:"s"`
		II []int  `default:"[1]"`
	}

	callback := func(s structconfig.StructField, v string, fv func() reflect.Value) error {
		if s.Name() != "II" {
			return errors.New("unexpected field name")
		}
		var xs []int
		if err := json.Unmarshal([]byte(v), &xs); err != nil {
			return err
		}
		fv().Set(reflect.ValueOf(xs))
		return nil
	}

	eq := func(a, b any) (bool, error) {
		// expect only []int because int and string are supported by structconfig
		xs, ok := a.([]int)
		if !ok {
			return false, nil
		}
		ys, ok := b.([]int)
		if !ok {
			return false, nil
		}
		if len(xs) != len(ys) {
			return false, nil
		}
		for i, x := range xs {
			if x != ys[i] {
				return false, nil
			}
		}
		return true, nil
	}

	m := structconfig.NewMerger[T](
		structconfig.WithAnyCallback(callback),
		structconfig.WithAnyEqual(eq),
	)
	got, err := m.Merge(
		T{
			I:  100,
			S:  "s", // default
			II: []int{100},
		},
		T{
			I:  1, // default
			S:  "win",
			II: []int{1}, // default
		},
	)
	if err != nil {
		panic(err)
	}
	fmt.Println(got.I, got.S, got.II)
}
Output:

100 win [100]

func NewMerger

func NewMerger[T any](opt ...Option) *Merger[T]

NewMerger returns a new Merger.

AnyCallback parses "default" tag value and set it. AnyEqual reports true if left equals right when kind of arguments are not supported. Prefix adds a prefix to "default" tag name.

func (*Merger[T]) Merge

func (m *Merger[T]) Merge(left, right T) (T, error)

Merge values based on the 'default' tag values. For each field, if the right value is not the default, use it; if not, use the left value. If that is also the default, set the default value. Return this instance.

type Option

type Option func(*Config)

func WithAnyCallback

func WithAnyCallback(v AnyCallbackFunc) Option

func WithAnyEqual

func WithAnyEqual(v AnyEqualFunc) Option

func WithPrefix

func WithPrefix(v string) Option

type Receptor

type Receptor = internal.Receptor

type StringReceptor

type StringReceptor = internal.StringReceptor

type StructConfig

type StructConfig[T any] struct {
	// contains filtered or unexported fields
}

func New

func New[T any](opt ...Option) *StructConfig[T]

New returns a new StructConfig.

AnyCallback parses "default" tag value and set it. Prefix adds a prefix to "name", "default" and "usage" tag name.

func (StructConfig[T]) FromDefault

func (sc StructConfig[T]) FromDefault(v *T) error

FromDefault sets "default" tag values to v.

Example
package main

import (
	"fmt"

	"github.com/berquerant/structconfig"
)

func main() {
	type T struct {
		B bool `default:"false"`
		I int
		F float32 `default:"1.1"`
		S string  `default:"str"`
	}

	sc := structconfig.New[T]()
	var got T
	if err := sc.FromDefault(&got); err != nil {
		panic(err)
	}
	fmt.Println(got.B, got.I, got.F, got.S)
}
Output:

false 0 1.1 str

func (StructConfig[T]) FromEnv

func (sc StructConfig[T]) FromEnv(v *T) error

FromEnv sets environment variable values to v.

Environment variable name will be

NewEnvVar("name tag value").String()

All '.' and '-' will be replaced with '_', making it all uppsercase.

Example
package main

import (
	"fmt"
	"os"

	"github.com/berquerant/structconfig"
)

func main() {
	type T struct {
		B  bool   `name:"bool_value"`
		S  string `name:"string_value"`
		N  int    `name:"int_value"`
		N2 int
		N3 int `name:"-"`
	}

	envs := map[string]string{
		"BOOL_VALUE":   "true",
		"STRING_VALUE": "str",
	}
	for k, v := range envs {
		os.Setenv(k, v)
	}
	defer func() {
		for k := range envs {
			os.Unsetenv(k)
		}
	}()

	sc := structconfig.New[T]()
	var got T
	if err := sc.FromEnv(&got); err != nil {
		panic(err)
	}
	fmt.Println(got.B, got.S, got.N, got.N2, got.N3)
}
Output:

true str 0 0 0

func (StructConfig[T]) FromFlags

func (sc StructConfig[T]) FromFlags(v *T, fs *pflag.FlagSet) error

FromFlags set values tov from command-line flags.

Flag name is from "name" tag value.

Example
package main

import (
	"errors"
	"fmt"
	"reflect"
	"sort"
	"strings"

	"github.com/berquerant/structconfig"
	"github.com/spf13/pflag"
)

func main() {
	type T struct {
		B       bool   `name:"bool_value" usage:"BOOL"`
		S       string `name:"string_value" default:"str"`
		Ignore1 int
		Ignore2 int `name:"-"`
		V       struct {
			S string
		} `name:"struct_value"`
	}

	anyCallback := func(s structconfig.StructField, v string, fv func() reflect.Value) error {
		if x, ok := s.Tag().Name(); !ok || x != "struct_value" {
			// among T, only struct_value is not supported
			return errors.New("unexpected tag name")
		}
		fv().Set(reflect.ValueOf(struct {
			S string
		}{
			S: v,
		}))
		return nil
	}

	fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
	sc := structconfig.New[T](structconfig.WithAnyCallback(anyCallback))

	if err := sc.SetFlags(fs); err != nil {
		panic(err)
	}

	flagNames := []string{}
	fs.VisitAll(func(f *pflag.Flag) {
		flagNames = append(flagNames, f.Name)
	})

	if err := fs.Parse([]string{"--bool_value", "--struct_value", "sv"}); err != nil {
		panic(err)
	}

	var got T
	if err := sc.FromFlags(&got, fs); err != nil {
		panic(err)
	}

	sort.Strings(flagNames)
	fmt.Println(strings.Join(flagNames, ","))
	fmt.Println(got.B, got.S, got.Ignore1, got.Ignore2, got.V.S)
}
Output:

bool_value,string_value,struct_value
true str 0 0 sv
Example (Prefix)
package main

import (
	"fmt"
	"sort"
	"strings"

	"github.com/berquerant/structconfig"
	"github.com/spf13/pflag"
)

func main() {
	tagPrefix := "sc"
	type T struct {
		B bool   `scname:"bool_value" scusage:"BOOL"`
		S string `scname:"string_value" scdefault:"str"`
	}

	fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
	sc := structconfig.New[T](structconfig.WithPrefix(tagPrefix))

	if err := sc.SetFlags(fs); err != nil {
		panic(err)
	}

	flagNames := []string{}
	fs.VisitAll(func(f *pflag.Flag) {
		flagNames = append(flagNames, f.Name)
	})

	if err := fs.Parse([]string{"--bool_value", "--string_value", "sv"}); err != nil {
		panic(err)
	}

	var got T
	if err := sc.FromFlags(&got, fs); err != nil {
		panic(err)
	}

	sort.Strings(flagNames)
	fmt.Println(strings.Join(flagNames, ","))
	fmt.Println(got.B, got.S)
}
Output:

bool_value,string_value
true sv

func (StructConfig[T]) SetFlags

func (sc StructConfig[T]) SetFlags(fs *pflag.FlagSet) error

SetFlags sets command-line flags.

Flag name is from "name" tag value. Flag default value is from "default" tag value. Flag usage is from "usage" tag value.

type StructField

type StructField = internal.StructField

type Supported

type Supported = internal.Supported

type Tag

type Tag = internal.Tag

type Type

type Type = internal.Type

func NewType

func NewType(v any, prefix string) (*Type, error)

type UintReceptor

type UintReceptor = internal.UintReceptor

type Unsigned

type Unsigned = internal.Unsigned

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL