options
packageAPI reference for the options
package.
Imports
(3)Option
Option is a functional option for configuration.
type Option func(*T)
Apply
Apply applies functional options to a config struct.
Parameters
func Apply[T any](cfg *T, opts ...Option[T])
{
for _, opt := range opts {
opt(cfg)
}
}
Example
cfg := &Config{}
options.Apply(cfg, WithHost("localhost"))
Builder
Builder provides a fluent interface for building config with options.
type Builder struct
Example
cfg := options.NewBuilder(defaultCfg).
With(WithHost("localhost")).
Build()
Fields
| Name | Type | Description |
|---|---|---|
| cfg | T | |
| opts | []Option[T] |
NewBuilder
NewBuilder creates a new options builder with default config.
Parameters
Returns
func NewBuilder[T any](defaults T) *Builder[T]
{
return &Builder[T]{cfg: defaults}
}
Merge
Merge combines multiple configurations of the same type.
Later values always overwrite earlier ones (LastWins semantics).
For SkipZero semantics, use MergeConfig from options_ext.go.
Parameters
Returns
func Merge[T any](cfgs ...T) T
{
var result T
resultVal := reflect.ValueOf(&result).Elem()
resultType := resultVal.Type()
for _, cfg := range cfgs {
cfgVal := reflect.ValueOf(cfg)
for i := 0; i < resultType.NumField(); i++ {
resultVal.Field(i).Set(cfgVal.Field(i))
}
}
return result
}
Example
cfg := options.Merge(defaultCfg, userCfg)
Options
Options wraps a validated configuration section for DI consumption.
Similar to .NET IOptions
type Options struct
Fields
| Name | Type | Description |
|---|---|---|
| Value | T |
Configure
Configure registers an Options[T] in the DI container by binding
from the given configuration section at startup.
Usage:
di.ConfigureAppOptions)
Parameters
Returns
func Configure[T any](value T) Options[T]
{
return Options[T]{Value: value}
}
MergeWithSemantics
MergeWithSemantics controls how Merge handles zero values.
type MergeWithSemantics int
MergeConfig
MergeConfig combines configs with explicit merge semantics.
Parameters
Returns
func MergeConfig[T any](semantics MergeWithSemantics, cfgs ...T) T
{
var result T
resultVal := reflect.ValueOf(&result).Elem()
resultType := resultVal.Type()
for _, cfg := range cfgs {
cfgVal := reflect.ValueOf(cfg)
for i := 0; i < resultType.NumField(); i++ {
field := cfgVal.Field(i)
switch semantics {
case LastWins:
resultVal.Field(i).Set(field)
case SkipZero:
if !field.IsZero() {
resultVal.Field(i).Set(field)
}
}
}
}
return result
}
MustValidate
MustValidate panics if the struct contains zero-valued required fields.
Required fields are marked with required:"true" tag.
Parameters
func MustValidate[T any](cfg T)
{
val := reflect.ValueOf(cfg)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
if field.Tag.Get("required") == "true" {
if val.Field(i).IsZero() {
panic(fmt.Sprintf("options: required field %s is zero", field.Name))
}
}
}
}
TestMergeConfig_LastWins
Parameters
func TestMergeConfig_LastWins(t *testing.T)
{
type Config struct {
Debug bool
Port int
}
defaults := Config{Debug: true, Port: 8080}
override := Config{Debug: false, Port: 0}
result := MergeConfig(LastWins, defaults, override)
if result.Debug != false {
t.Errorf("Debug: got %v, want false", result.Debug)
}
if result.Port != 0 {
t.Errorf("Port: got %d, want 0", result.Port)
}
}
TestMergeConfig_SkipZero
Parameters
func TestMergeConfig_SkipZero(t *testing.T)
{
type Config struct {
Port int
Host string
}
defaults := Config{Port: 8080, Host: "localhost"}
override := Config{Port: 0, Host: "overridden"}
result := MergeConfig(SkipZero, defaults, override)
if result.Port != 8080 {
t.Errorf("Port: got %d, want 8080 (zero should not overwrite)", result.Port)
}
if result.Host != "overridden" {
t.Errorf("Host: got %q, want %q", result.Host, "overridden")
}
}
TestConfigure
Parameters
func TestConfigure(t *testing.T)
{
type AppOptions struct {
Host string `config:"host" required:"true"`
Port int `config:"port"`
}
opts := Configure(AppOptions{Host: "localhost", Port: 8080})
if opts.Value.Host != "localhost" {
t.Errorf("Configure: got %q, want %q", opts.Value.Host, "localhost")
}
}
TestMustValidate
Parameters
func TestMustValidate(t *testing.T)
{
type Config struct {
Name string `required:"true"`
Port int
}
t.Run("valid", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("should not panic: %v", r)
}
}()
MustValidate(Config{Name: "app"})
})
t.Run("missing required", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("should panic for missing required field")
}
}()
MustValidate(Config{Name: ""})
})
}
ServerConfig
type ServerConfig struct
Fields
| Name | Type | Description |
|---|---|---|
| Host | string | |
| Port | int | |
| Timeout | int |
WithHost
Parameters
Returns
func WithHost(h string) func(*ServerConfig)
{
return func(c *ServerConfig) { c.Host = h }
}
WithPort
Parameters
Returns
func WithPort(p int) func(*ServerConfig)
{
return func(c *ServerConfig) { c.Port = p }
}
WithTimeout
Parameters
Returns
func WithTimeout(t int) func(*ServerConfig)
{
return func(c *ServerConfig) { c.Timeout = t }
}
TestApply
Parameters
func TestApply(t *testing.T)
{
cfg := &ServerConfig{Host: "localhost", Port: 8080}
Apply(cfg, WithHost("0.0.0.0"), WithPort(9000))
if cfg.Host != "0.0.0.0" {
t.Errorf("Host: got %q, want %q", cfg.Host, "0.0.0.0")
}
if cfg.Port != 9000 {
t.Errorf("Port: got %d, want %d", cfg.Port, 9000)
}
}
TestBuilder
Parameters
func TestBuilder(t *testing.T)
{
defaults := ServerConfig{Host: "localhost", Port: 8080, Timeout: 30}
cfg := NewBuilder(defaults).
With(WithHost("127.0.0.1")).
With(WithTimeout(60)).
Build()
if cfg.Host != "127.0.0.1" {
t.Errorf("Host: got %q, want %q", cfg.Host, "127.0.0.1")
}
if cfg.Port != 8080 {
t.Errorf("Port should remain default: got %d, want %d", cfg.Port, 8080)
}
if cfg.Timeout != 60 {
t.Errorf("Timeout: got %d, want %d", cfg.Timeout, 60)
}
}
TestBuilder_Ptr
Parameters
func TestBuilder_Ptr(t *testing.T)
{
defaults := ServerConfig{Port: 3000}
cfg := NewBuilder(defaults).
With(WithHost("api.example.com")).
Ptr()
if cfg.Host != "api.example.com" {
t.Errorf("Host: got %q, want %q", cfg.Host, "api.example.com")
}
if cfg.Port != 3000 {
t.Errorf("Port: got %d, want %d", cfg.Port, 3000)
}
}