configure

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Nov 27, 2025 License: MIT Imports: 3 Imported by: 11

Documentation

Overview

Package configure provides utilities for applying functional options to objects.

Package configure provides a robust, type-safe, and flexible implementation of the Functional Options Pattern for Go. It is designed to simplify the initialization of complex objects by allowing optional parameters to be passed in a clean and readable way.

This pattern is ideal for constructors where many parameters are optional, have sensible defaults, or where you want to avoid a large number of arguments.

Usage

The core of the pattern involves defining an `Option` type and functions that return these options.

## Basic Example: Configuring a Logger

Imagine you are creating a `Logger` that can be configured with different logging levels and output writers. The default is to log at the "info" level to standard output.

// 1. Define the object to be configured.
type Logger struct {
	level string
	out   io.Writer
}

// 2. Create functions that return an `Option` for each configurable field.
func WithLevel(level string) configure.Option[Logger] {
	return configure.OptionFunc[Logger](func(l *Logger) error {
		l.level = level
		return nil
	})
}

func WithOutput(w io.Writer) configure.Option[Logger] {
	return configure.OptionFunc[Logger](func(l *Logger) error {
		l.out = w
		return nil
	})
}

// 3. Create a constructor that applies the options to a default instance.
func NewLogger(options ...configure.Option[Logger]) (*Logger, error) {
	// Start with default values.
	l := &Logger{
		level: "info",
		out:   os.Stdout,
	}

	// Apply any provided options.
	configure.ApplyWith(l, options...)

	// You can also perform validation after applying options.
	if l.level == "" {
		return nil, fmt.Errorf("log level cannot be empty")
	}

	return l, nil
}

Now, you can create loggers with different configurations easily:

// A default logger (info level, stdout).
logger1, _ := NewLogger()

// A debug-level logger.
logger2, _ := NewLogger(WithLevel("debug"))

// A logger that writes to a file.
file, _ := os.Create("app.log")
logger3, _ := NewLogger(WithLevel("error"), WithOutput(file))

For more advanced usage, including stateful builders and compilation, refer to the function-specific documentation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Apply

func Apply[T any, O OptionFunc[T]](target *T, opts []O) *T

Apply applies a slice of options to the target object. It is the core, high-performance function for applying a homogeneous set of type-safe options. Its generic constraint allows for custom-defined option types, such as `type MyOption func(*T)`.

The `opts` parameter is a slice of options. If you have a variadic list of options (e.g., `WithFoo(), WithBar()`), use the `ApplyWith` convenience wrapper instead.

For handling mixed option types, see ApplyAny.

func ApplyAny

func ApplyAny[T any](target *T, opts []any) (*T, error)

ApplyAny applies a slice of options of various types (any) to the target object. This function provides flexibility by using reflection to handle heterogeneous options, at the cost of compile-time type safety and a minor performance overhead.

The `opts` parameter is a slice of options. If you have a variadic list of options (e.g., `WithFoo(), WithBar()`), use the `ApplyAnyWith` convenience wrapper instead.

For type-safe, high-performance application, see Apply or ApplyE.

func ApplyAnyWith

func ApplyAnyWith[T any](target *T, opts ...any) (*T, error)

ApplyAnyWith is the variadic convenience wrapper for ApplyAny.

func ApplyE

func ApplyE[T any, O OptionFuncE[T]](target *T, opts []O) (*T, error)

ApplyE applies a slice of error-returning options to the target object. It is the core, high-performance function for applying a homogeneous set of type-safe, error-returning options. Its generic constraint allows for custom-defined option types.

The `opts` parameter is a slice of options. If you have a variadic list of options (e.g., `WithFoo(), WithBar()`), use the `ApplyWithE` convenience wrapper instead.

For handling mixed option types, see ApplyAny.

func ApplyWith

func ApplyWith[T any](target *T, opts ...Option[T]) *T

ApplyWith is the variadic convenience wrapper for Apply. It is useful for applying a short, explicit list of options.

Example:

ApplyWith(config, WithTimeout(5*time.Second), WithPort(8080))

func ApplyWithE

func ApplyWithE[T any](target *T, opts ...OptionE[T]) (*T, error)

ApplyWithE is the variadic convenience wrapper for ApplyE. It is useful for applying a short, explicit list of options.

func Chain added in v0.9.0

func Chain[S any, T OptionFunc[S]](opts ...T) T

Chain combines multiple options (of any type satisfying OptionFunc[S]) into a single option. The returned option will apply all provided options in sequence.

func ChainE added in v0.9.0

func ChainE[S any, T OptionFuncE[S]](opts ...T) T

ChainE combines multiple error-returning options (of any type satisfying OptionFuncE[S]) into a single option. The returned option will apply all provided options in sequence. If any option returns an error, the chain stops and that error is returned.

func Compile

func Compile[C any, P any](factory func(c *C) (*P, error), builder *Builder[C]) (*P, error)

Compile creates a final product `P` by first building a configuration `C` using the provided `builder`, and then passing the result to a `factory` function. This function acts as the primary top-level entry point for the Config -> Product workflow, emphasizing the factory's role in producing the final product from the configuration.

func IsConfigError

func IsConfigError(err error) bool

IsConfigError checks if the given error is a *ConfigError.

func IsEmptyTargetValueError

func IsEmptyTargetValueError(err error) bool

IsEmptyTargetValueError checks if the error is a ConfigError with the code ErrEmptyTargetValue.

func IsExecutionFailedError

func IsExecutionFailedError(err error) bool

IsExecutionFailedError checks if the error is a ConfigError with the code ErrExecutionFailed.

func IsUnsupportedTypeError

func IsUnsupportedTypeError(err error) bool

IsUnsupportedTypeError checks if the error is a ConfigError with the code ErrUnsupportedType.

func New

func New[T any, O OptionFunc[T]](opts []O) *T

New creates a new instance of T and applies the given options. It is a convenient, type-safe constructor for creating objects with homogeneous options. For mixed-type or error-returning options, see NewAny or NewE.

func NewAny added in v0.5.0

func NewAny[T any](opts ...any) (*T, error)

NewAny creates a new instance of T, applies the given options of any type, and returns it. It is a convenient top-level constructor for simple object creation where the configuration type and the product type are the same.

It uses ApplyAny for maximum flexibility in accepting options.

func NewE added in v0.5.0

func NewE[T any, O OptionFuncE[T]](opts []O) (*T, error)

NewE creates a new instance of T, applies the error-returning options, and returns the configured instance or an error. It is a convenient, type-safe constructor for creating objects with homogeneous, error-returning options.

func NewWith added in v0.5.0

func NewWith[T any](opts ...Option[T]) *T

NewWith is the variadic convenience wrapper for New.

func NewWithE added in v0.5.0

func NewWithE[T any](opts ...OptionE[T]) (*T, error)

NewWithE is the variadic convenience wrapper for NewE.

Types

type Applier

type Applier[T any] interface {
	Apply(*T)
}

Applier is an interface for types that can apply a configuration to an object. It provides an extension point for ApplyAny, allowing custom types to be used as options without reflection.

type ApplierE

type ApplierE[T any] interface {
	Apply(*T) error
}

ApplierE is an interface for types that can apply a configuration and return an error. It provides an extension point for ApplyAny, allowing custom types to be used as options without reflection.

type Builder

type Builder[C any] struct {
	// contains filtered or unexported fields
}

Builder provides a fluent interface for collecting and applying options. It is ideal for scenarios where configuration options are gathered progressively from different parts of an application.

The generic type C represents the configuration type being built, and is expected to be a struct type. Using a pointer type for C as the generic parameter (e.g., Builder[*MyConfig]) is not recommended as it can lead to unexpected behavior and double-pointers.

func NewBuilder

func NewBuilder[C any](base ...*C) *Builder[C]

NewBuilder creates a new configuration builder. It can optionally take a base configuration object. If provided, this base configuration will be cloned and used as the starting point for applying options when `Build` is called. If no base is provided, a zero-value instance of C will be used.

Panics if the generic type C is itself a pointer type (e.g., Builder[*MyConfig]), as this is an unsupported and likely unintended usage pattern that leads to double-pointers.

func (*Builder[C]) Add

func (b *Builder[C]) Add(opts ...any) *Builder[C]

Add adds one or more options to the builder. It supports a fluent, chainable API.

func (*Builder[C]) AddWhen

func (b *Builder[C]) AddWhen(condition bool, optIfTrue any, optIfFalse ...any) *Builder[C]

AddWhen conditionally adds an option to the builder based on a condition. If `condition` is true, `optIfTrue` is added. If `condition` is false and `optIfFalse` is provided (as the first element of the variadic parameter), then `optIfFalse` is added instead. It supports a fluent, chainable API.

func (*Builder[C]) Apply

func (b *Builder[C]) Apply(target *C) error

Apply implements the ApplierE interface. This allows a Builder instance to be passed directly as an option to other functions like New or ApplyAny, acting as a "super option".

func (*Builder[C]) Build

func (b *Builder[C]) Build() (*C, error)

Build creates a new configuration object C and applies all collected options to it. It starts with a clone of the base configuration (if set via `NewBuilder`), or a zero-value instance of C if no base is provided.

type ConfigError

type ConfigError struct {
	// Code is the category of the error.
	Code ErrorCode
	// TypeString is the string representation of the option's type.
	TypeString string
	// Err is the underlying error, if any.
	Err error
}

ConfigError is a custom error type for the configure package. It wraps an original error while providing additional context, such as the type of option that caused the failure and a specific error code.

func (*ConfigError) Error

func (e *ConfigError) Error() string

Error implements the standard error interface.

func (*ConfigError) Unwrap

func (e *ConfigError) Unwrap() error

Unwrap makes ConfigError compatible with the standard library's errors.Is and errors.As functions, allowing for proper error chain inspection.

type ErrorCode

type ErrorCode int

ErrorCode defines the specific category of a configuration error.

const (
	// ErrUnsupportedType indicates that an option's type is not supported by
	// the ApplyAny function.
	ErrUnsupportedType ErrorCode = iota

	// ErrExecutionFailed indicates that an option function returned an error
	// during its execution.
	ErrExecutionFailed

	// ErrEmptyTargetValue indicates that a nil pointer was passed as the target
	// for configuration.
	ErrEmptyTargetValue
)

Error codes for specific configuration failures.

type Option

type Option[T any] func(*T)

Option represents a function that configures an object of type T. It is the primary, non-error-returning type for the Functional Options Pattern.

func OptionSet deprecated

func OptionSet[T any](opts ...Option[T]) Option[T]

OptionSet bundles multiple options into a single option. This allows for creating reusable and modular sets of configurations.

Deprecated: Use Chain instead for more generic and flexible option chaining.

func (Option[T]) Apply

func (o Option[T]) Apply(target *T)

Apply implements the Applier[T] interface, allowing an Option[T] to be used as a flexible option type with functions like ApplyAny.

type OptionE

type OptionE[T any] func(*T) error

OptionE represents a function that configures an object of type T and may return an error. The 'E' suffix is a convention for "Error".

func OptionSetE deprecated

func OptionSetE[T any](opts ...OptionE[T]) OptionE[T]

OptionSetE bundles multiple error-returning options into a single option. If any option in the set returns an error, the application stops and the error is returned.

Deprecated: Use ChainE instead for more generic and flexible error-returning option chaining.

func WithValidation

func WithValidation[T any](validator func(*T) error) OptionE[T]

WithValidation creates an option that validates the target object. If the validator function returns an error, the configuration process will stop.

func (OptionE[T]) Apply

func (o OptionE[T]) Apply(target *T) error

Apply implements the ApplierE[T] interface, allowing an OptionE[T] to be used as a flexible option type with functions like ApplyAny.

type OptionFunc added in v0.9.0

type OptionFunc[T any] interface {
	~func(*T)
}

OptionFunc is a generic constraint that permits any function type whose underlying type is func(*T). This enables the top-level Apply function to accept custom-defined option types, such as `type MyOption func(*T)`.

type OptionFuncAny added in v0.9.0

type OptionFuncAny[T any] interface {
	OptionFuncE[T] | OptionFunc[T] | any
}

OptionFuncAny is a generic constraint that permits any function type whose underlying type is either func(*T) or func(*T) error. This provides a convenient way to create functions that can accept both error-returning and non-error-returning function options.

type OptionFuncE added in v0.9.0

type OptionFuncE[T any] interface {
	~func(*T) error
}

OptionFuncE is a generic constraint that permits any function type whose underlying type is func(*T) error. This enables the top-level ApplyE function to accept custom-defined, error-returning option types.

Jump to

Keyboard shortcuts

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