### Go: Installation for 'with' Package
Source: https://github.com/spandigital/with/blob/develop/README.md
This command installs the 'with' package, a Go library for implementing the Functional Options Pattern. It requires a Go environment and standard package management.
```bash
go get github.com/spandigital/with
```
--------------------------------
### Go Pre-commit Hook Installation
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Installs pre-commit hooks for the repository, ensuring code formatting, linting, testing, dependency management, and commit message conventions are followed before committing.
```bash
pre-commit install
```
--------------------------------
### Go: Initialize Feature Flags with MustAddWith
Source: https://context7.com/spandigital/with/llms.txt
Initializes a FeatureFlags struct using `with.MustAddWith`. This function takes a base configuration and a slice of configuration functions. It panics if any configuration function returns an error, ensuring critical setup failures are immediately caught. The example defines development, production, and staging configurations.
```go
package main
import (
"fmt"
"github.com/spandigital/with"
)
type FeatureFlags struct {
EnableNewUI bool
EnableBetaAPI bool
EnableAnalytics bool
MaxUploadSizeMB int
}
func WithFeature(name string, enabled bool) with.Func[FeatureFlags] {
return func(o *FeatureFlags) error {
switch name {
case "newui":
o.EnableNewUI = enabled
case "betaapi":
o.EnableBetaAPI = enabled
case "analytics":
o.EnableAnalytics = enabled
}
return nil
}
}
func WithMaxUploadSize(sizeMB int) with.Func[FeatureFlags] {
return func(o *FeatureFlags) error {
o.MaxUploadSizeMB = sizeMB
return nil
}
}
// Development configuration
var DevFlags = with.MustAddWith(
&FeatureFlags{
EnableNewUI: true,
EnableBetaAPI: true,
EnableAnalytics: false,
MaxUploadSizeMB: 100,
},
[]with.Func[FeatureFlags]{},
)
// Production configuration
var ProdFlags = with.MustAddWith(
&FeatureFlags{
EnableNewUI: false,
EnableBetaAPI: false,
EnableAnalytics: true,
MaxUploadSizeMB: 50,
},
[]with.Func[FeatureFlags]{
WithMaxUploadSize(25),
},
)
// Staging with overrides
var StagingFlags = with.MustAddWith(
&FeatureFlags{
EnableNewUI: true,
EnableBetaAPI: true,
EnableAnalytics: true,
MaxUploadSizeMB: 75,
},
[]with.Func[FeatureFlags]{
WithFeature("newui", true),
WithFeature("analytics", true),
},
)
func main() {
fmt.Printf("Dev: NewUI=%v, BetaAPI=%v, Analytics=%v, MaxUpload=%dMB\n",
DevFlags.EnableNewUI, DevFlags.EnableBetaAPI,
DevFlags.EnableAnalytics, DevFlags.MaxUploadSizeMB)
// Output: Dev: NewUI=true, BetaAPI=true, Analytics=false, MaxUpload=100MB
fmt.Printf("Prod: NewUI=%v, BetaAPI=%v, Analytics=%v, MaxUpload=%dMB\n",
ProdFlags.EnableNewUI, ProdFlags.EnableBetaAPI,
ProdFlags.EnableAnalytics, ProdFlags.MaxUploadSizeMB)
// Output: Prod: NewUI=false, BetaAPI=false, Analytics=true, MaxUpload=25MB
fmt.Printf("Staging: NewUI=%v, BetaAPI=%v, Analytics=%v, MaxUpload=%dMB\n",
StagingFlags.EnableNewUI, StagingFlags.EnableBetaAPI,
StagingFlags.EnableAnalytics, StagingFlags.MaxUploadSizeMB)
// Output: Staging: NewUI=true, BetaAPI=true, Analytics=true, MaxUpload=75MB
}
```
--------------------------------
### Go: Traditional Constructor Pitfalls
Source: https://github.com/spandigital/with/blob/develop/README.md
Illustrates the drawbacks of traditional constructor patterns in Go, such as excessive parameters, verbose config structs requiring nil checks, and the ceremony of the builder pattern. These examples highlight the problems that the Functional Options Pattern aims to solve.
```go
// 😞 Too many parameters - hard to remember order
NewServer("localhost", 8080, 30*time.Second, true, false, "INFO")
// 😞 Config struct - requires nil checks, verbose for simple cases
NewServer(&Config{Host: "localhost", Port: 8080, ...})
// 😞 Builder pattern - too much ceremony
NewServer().WithHost("localhost").WithPort(8080).Build()
```
--------------------------------
### Go: Apply Defaults, Options, and Validation with DefaultThenAddWith
Source: https://context7.com/spandigital/with/llms.txt
Demonstrates the 'DefaultThenAddWith' function from the 'with' package in Go. This function applies default values (if 'Defaulted' interface is implemented), processes functional options, and then validates the configuration (if 'Validated' interface is implemented). It's ideal for constructors needing sensible defaults and flexible overrides. The example shows how to define options, apply them to a server configuration, and handle potential errors.
```go
package main
import (
"errors"
"fmt"
"time"
"github.com/spandigital/with"
)
type ServerOptions struct {
Host string
Port int
Timeout time.Duration
}
func (o *ServerOptions) SetDefaults() {
o.Host = "localhost"
o.Port = 8080
o.Timeout = 30 * time.Second
}
func (o *ServerOptions) Validate() error {
if o.Port < 1 || o.Port > 65535 {
return errors.New("port must be between 1 and 65535")
}
if o.Timeout < time.Second {
return errors.New("timeout must be at least 1 second")
}
return nil
}
func WithHost(host string) with.Func[ServerOptions] {
return func(o *ServerOptions) error {
if host == "" {
return errors.New("host cannot be empty")
}
o.Host = host
return nil
}
}
func WithPort(port int) with.Func[ServerOptions] {
return func(o *ServerOptions) error {
if port < 1 || port > 65535 {
return errors.New("port must be between 1 and 65535")
}
o.Port = port
return nil
}
}
func WithTimeout(timeout time.Duration) with.Func[ServerOptions] {
return func(o *ServerOptions) error {
o.Timeout = timeout
return nil
}
}
type Server struct {
host string
port int
timeout time.Duration
}
func NewServer(opts ...with.Func[ServerOptions]) (*Server, error) {
o := &ServerOptions{}
if err := with.DefaultThenAddWith(o, opts); err != nil {
return nil, err
}
return &Server{
host: o.Host,
port: o.Port,
timeout: o.Timeout,
}, nil
}
func main() {
// Use all defaults: localhost:8080, 30s timeout
server1, err := NewServer()
if err != nil {
panic(err)
}
fmt.Printf("Server 1: %s:%d (timeout: %v)\n",
server1.host, server1.port, server1.timeout)
// Output: Server 1: localhost:8080 (timeout: 30s)
// Override specific options
server2, err := NewServer(
WithHost("0.0.0.0"),
WithPort(3000),
)
if err != nil {
panic(err)
}
fmt.Printf("Server 2: %s:%d (timeout: %v)\n",
server2.host, server2.port, server2.timeout)
// Output: Server 2: 0.0.0.0:3000 (timeout: 30s)
// Override all options
server3, err := NewServer(
WithHost("example.com"),
WithPort(443),
WithTimeout(60 * time.Second),
)
if err != nil {
panic(err)
}
fmt.Printf("Server 3: %s:%d (timeout: %v)\n",
server3.host, server3.port, server3.timeout)
// Output: Server 3: example.com:443 (timeout: 1m0s)
// Error case: invalid port
_, err = NewServer(WithPort(99999))
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: cannot apply WithPort: port must be between 1 and 65535
}
// Error case: validation failure
_, err = NewServer(WithTimeout(500 * time.Millisecond))
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: validation failed: timeout must be at least 1 second
}
}
```
--------------------------------
### Go: Create Server with Functional Options
Source: https://github.com/spandigital/with/blob/develop/README.md
Demonstrates how to create a server instance using the Functional Options Pattern. This pattern allows for flexible and readable configuration by passing options functions to the constructor. It shows creating a server with default values, overriding specific options, and mixing struct initialization with options.
```go
// Create with defaults
server, _ := NewServer()
// Override specific options
server, _ := NewServer(
WithHost("0.0.0.0"),
WithPort(3000),
WithTimeout(60 * time.Second),
)
// Mix struct initialization with options
server, _ := NewServerFromOptions(
&Options{Host: "localhost", Port: 8080},
WithTimeout(30 * time.Second),
)
```
--------------------------------
### Go: Simple Server Constructor with 'with' Package
Source: https://github.com/spandigital/with/blob/develop/README.md
Demonstrates creating a type-safe server constructor using the 'with' package. It defines a ServerOptions struct, SetDefaults and Validate methods, option functions (WithHost, WithPort), and a NewServer constructor that applies options.
```go
package main
import (
"fmt"
"time"
"github.com/spandigital/with"
)
// 1. Define your options struct
type ServerOptions struct {
Host string
Port int
Timeout time.Duration
}
// 2. (Optional) Add defaults
func (o *ServerOptions) SetDefaults() {
o.Host = "localhost"
o.Port = 8080
o.Timeout = 30 * time.Second
}
// 3. (Optional) Add validation
func (o *ServerOptions) Validate() error {
if o.Port < 1 || o.Port > 65535 {
return fmt.Errorf("port must be between 1-65535")
}
return nil
}
// 4. Create option functions
func WithHost(host string) with.Func[ServerOptions] {
return func(o *ServerOptions) error {
o.Host = host
return nil
}
}
func WithPort(port int) with.Func[ServerOptions] {
return func(o *ServerOptions) error {
if port < 1 || port > 65535 {
return fmt.Errorf("invalid port: %d", port)
}
o.Port = port
return nil
}
}
// 5. Use in your constructor
func NewServer(opts ...with.Func[ServerOptions]) (*Server, error) {
o := &ServerOptions{}
if err := with.DefaultThenAddWith(o, opts); err != nil {
return nil, err
}
return &Server{options: o}, nil
}
// Usage - clean and readable!
func main() {
// Use defaults
server1, _ := NewServer()
// Override specific options
server2, _ := NewServer(
WithHost("0.0.0.0"),
WithPort(3000),
)
}
```
--------------------------------
### Go: Functional Options Pattern Solution
Source: https://github.com/spandigital/with/blob/develop/README.md
Presents the clean and readable implementation of the Functional Options Pattern. This code snippet shows how to define and use options functions for a more self-documenting and flexible constructor, contrasting with the problematic traditional approaches.
```go
// 😊 Clean, readable, self-documenting
server, _ := NewServer(
WithHost("localhost"),
WithPort(8080),
)
```
--------------------------------
### Go Functional Options Pattern with Nop
Source: https://context7.com/spandigital/with/llms.txt
Demonstrates the Functional Options Pattern in Go using the 'with' package. It shows how to create flexible service constructors with default options and conditional feature enablement using the `with.Nop` function for no-operation options.
```go
package main
import (
"fmt"
"os"
"time"
"github.com/spandigital/with"
)
type ServiceOptions struct {
EnableMetrics bool
EnableTracing bool
MetricsPort int
TracingURL string
}
func (o *ServiceOptions) SetDefaults() {
o.EnableMetrics = false
o.EnableTracing = false
o.MetricsPort = 9090
o.TracingURL = ""
}
func WithMetrics(port int) with.Func[ServiceOptions] {
return func(o *ServiceOptions) error {
o.EnableMetrics = true
o.MetricsPort = port
return nil
}
}
func WithTracing(url string) with.Func[ServiceOptions] {
return func(o *ServiceOptions) error {
o.EnableTracing = true
o.TracingURL = url
return nil
}
}
type Service struct {
options *ServiceOptions
}
func NewService(opts ...with.Func[ServiceOptions]) (*Service, error) {
o := &ServiceOptions{}
if err := with.DefaultThenAddWith(o, opts); err != nil {
return nil, err
}
return &Service{options: o}, nil
}
func main() {
// Conditionally enable features based on environment
isProd := os.Getenv("ENV") == "production"
isDebug := os.Getenv("DEBUG") == "true"
// Build options list with conditional logic
opts := []with.Func[ServiceOptions]{
// Always apply some base option
func(o *ServiceOptions) error {
fmt.Println("Base configuration applied")
return nil
},
}
// Conditionally add metrics
if isProd {
opts = append(opts, WithMetrics(9090))
} else {
opts = append(opts, with.Nop[ServiceOptions]())
}
// Conditionally add tracing
if isDebug {
opts = append(opts, WithTracing("http://localhost:16686"))
} else {
opts = append(opts, with.Nop[ServiceOptions]())
}
service, err := NewService(opts...)
if err != nil {
panic(err)
}
fmt.Printf("Service: Metrics=%v (port=%d), Tracing=%v (url=%s)\n",
service.options.EnableMetrics, service.options.MetricsPort,
service.options.EnableTracing, service.options.TracingURL)
// Output (if ENV != production and DEBUG != true):
// Base configuration applied
// Service: Metrics=false (port=9090), Tracing=false (url=)
// More practical example: timeout options
type TimeoutOptions struct {
ConnectTimeout time.Duration
ReadTimeout time.Duration
}
defaultTimeouts := func(o *TimeoutOptions) error {
o.ConnectTimeout = 5 * time.Second
o.ReadTimeout = 30 * time.Second
return nil
}
enableSlowMode := false
slowModeTimeout := func(o *TimeoutOptions) error {
o.ReadTimeout = 5 * time.Minute
return nil
}
// Use Nop to cleanly handle conditional option
timeoutOpt := with.Nop[TimeoutOptions]()
if enableSlowMode {
timeoutOpt = slowModeTimeout
}
to := &TimeoutOptions{}
with.AddWith(to, []with.Func[TimeoutOptions]{
defaultTimeouts,
timeoutOpt,
})
fmt.Printf("Timeouts: Connect=%v, Read=%v\n", to.ConnectTimeout, to.ReadTimeout)
// Output: Timeouts: Connect=5s, Read=30s
}
```
--------------------------------
### Go: Constructor with Defaults and Options using 'with'
Source: https://github.com/spandigital/with/blob/develop/README.md
Illustrates a Go constructor function that initializes a struct with default values and then applies provided functional options using `with.DefaultThenAddWith`. This is ideal for creating objects with sensible base configurations.
```go
func NewServer(opts ...with.Func[ServerOptions]) (*Server, error) {
o := &ServerOptions{}
if err := with.DefaultThenAddWith(o, opts); err != nil {
return nil, err
}
return &Server{options: o}, nil
}
```
--------------------------------
### Go: Initialize Logger with Default and Custom Options (Panic on Error)
Source: https://context7.com/spandigital/with/llms.txt
This Go code snippet demonstrates initializing a logger with default options and then applying custom configurations using the `with.MustDefaultThenAddWith` function. It panics if any error occurs during the configuration process, making it suitable for critical application startup.
```go
package main
import (
"fmt"
"time"
"github.com/spandigital/with"
)
type LoggerOptions struct {
Level string
Format string
Output string
BufferSize int
}
func (o *LoggerOptions) SetDefaults() {
o.Level = "INFO"
o.Format = "json"
o.Output = "stdout"
o.BufferSize = 256
}
func WithLogLevel(level string) with.Func[LoggerOptions] {
return func(o *LoggerOptions) error {
o.Level = level
return nil
}
}
func WithLogFormat(format string) with.Func[LoggerOptions] {
return func(o *LoggerOptions) error {
o.Format = format
return nil
}
}
type Logger struct {
options *LoggerOptions
}
// Package-level default logger using Must variant
var DefaultLogger = &Logger{
options: with.MustDefaultThenAddWith(&LoggerOptions{}, []with.Func[LoggerOptions]{
WithLogLevel("INFO"),
WithLogFormat("json"),
}),
}
// Alternative constructor that can return errors
func NewLogger(opts ...with.Func[LoggerOptions]) (*Logger, error) {
o := &LoggerOptions{}
if err := with.DefaultThenAddWith(o, opts); err != nil {
return nil, err
}
return &Logger{options: o}, nil
}
func (l *Logger) Info(msg string) {
fmt.Printf("[%s] %s (format: %s)\n", l.options.Level, msg, l.options.Format)
}
func main() {
// Use package-level default logger
DefaultLogger.Info("Application started")
// Output: [INFO] Application started (format: json)
// Create custom logger at runtime (error handling)
customLogger, err := NewLogger(
WithLogLevel("DEBUG"),
WithLogFormat("text"),
)
if err != nil {
panic(err)
}
customLogger.Info("Debug message")
// Output: [DEBUG] Debug message (format: text)
// Package-level initialization with custom config
var ProductionLogger = &Logger{
options: with.MustDefaultThenAddWith(&LoggerOptions{},
[]with.Func[LoggerOptions]{
WithLogLevel("ERROR"),
WithLogFormat("json"),
}),
}
ProductionLogger.Info("Production log")
// Output: [ERROR] Production log (format: json)
}
```
--------------------------------
### Go HTTP Client Configuration with Validation
Source: https://context7.com/spandigital/with/llms.txt
Defines `HTTPClientOptions` with default values and validation logic, along with constructor functions using the `with` library. It demonstrates creating an HTTP client with valid and invalid configurations, showcasing the validation process.
```go
package main
import (
"errors"
"fmt"
"github.com/spandigital/with"
)
type HTTPClientOptions struct {
MaxRetries int
RetryBackoff int // milliseconds
ConnectionTimeout int // seconds
RequestTimeout int // seconds
}
func (o *HTTPClientOptions) SetDefaults() {
o.MaxRetries = 3
o.RetryBackoff = 1000
o.ConnectionTimeout = 10
o.RequestTimeout = 30
}
func (o *HTTPClientOptions) Validate() error {
if o.MaxRetries < 0 {
return errors.New("max retries cannot be negative")
}
if o.RetryBackoff < 100 {
return errors.New("retry backoff must be at least 100ms")
}
if o.ConnectionTimeout < 1 {
return errors.New("connection timeout must be at least 1 second")
}
if o.RequestTimeout < o.ConnectionTimeout {
return errors.New("request timeout must be >= connection timeout")
}
if o.MaxRetries > 10 {
return errors.New("max retries cannot exceed 10")
}
return nil
}
func WithMaxRetries(retries int) with.Func[HTTPClientOptions] {
return func(o *HTTPClientOptions) error {
o.MaxRetries = retries
return nil
}
}
func WithConnectionTimeout(seconds int) with.Func[HTTPClientOptions] {
return func(o *HTTPClientOptions) error {
o.ConnectionTimeout = seconds
return nil
}
}
func WithRequestTimeout(seconds int) with.Func[HTTPClientOptions] {
return func(o *HTTPClientOptions) error {
o.RequestTimeout = seconds
return nil
}
}
type HTTPClient struct {
options *HTTPClientOptions
}
func NewHTTPClient(opts ...with.Func[HTTPClientOptions]) (*HTTPClient, error) {
o := &HTTPClientOptions{}
if err := with.DefaultThenAddWith(o, opts); err != nil {
return nil, err
}
return &HTTPClient{options: o}, nil
}
func main() {
// Valid configuration with defaults
client1, err := NewHTTPClient()
if err != nil {
panic(err)
}
fmt.Printf("Client1: Retries=%d, ConnTimeout=%ds, ReqTimeout=%ds\n",
client1.options.MaxRetries,
client1.options.ConnectionTimeout,
client1.options.RequestTimeout)
// Output: Client1: Retries=3, ConnTimeout=10s, ReqTimeout=30s
// Valid configuration with overrides
client2, err := NewHTTPClient(
WithMaxRetries(5),
WithConnectionTimeout(5),
WithRequestTimeout(20),
)
if err != nil {
panic(err)
}
fmt.Printf("Client2: Retries=%d, ConnTimeout=%ds, ReqTimeout=%ds\n",
client2.options.MaxRetries,
client2.options.ConnectionTimeout,
client2.options.RequestTimeout)
// Output: Client2: Retries=5, ConnTimeout=5s, ReqTimeout=20s
// Error case: too many retries
_, err = NewHTTPClient(WithMaxRetries(20))
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: validation failed: max retries cannot exceed 10
}
// Error case: request timeout < connection timeout
_, err = NewHTTPClient(
WithConnectionTimeout(30),
WithRequestTimeout(10),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: validation failed: request timeout must be >= connection timeout
}
// Error case: negative retries
_, err = NewHTTPClient(WithMaxRetries(-1))
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: validation failed: max retries cannot be negative
}
}
```
--------------------------------
### Go Build Command
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Builds all Go packages in the current directory and its subdirectories. The `-v` flag enables verbose output, showing which packages are being built.
```bash
go build -v ./...
```
--------------------------------
### Go: Constructor Applying Options to Existing Struct with 'with'
Source: https://github.com/spandigital/with/blob/develop/README.md
Shows a Go constructor function that takes an existing struct and applies additional functional options to it using `with.AddWith`. This pattern is useful for modifying pre-configured objects or applying runtime settings.
```go
func NewServerFromConfig(config *ServerOptions, opts ...with.Func[ServerOptions]) (*Server, error) {
if err := with.AddWith(config, opts); err != nil {
return nil, err
}
return &Server{options: config}, nil
}
```
--------------------------------
### Go Test Commands
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Runs Go tests. Supports running all tests, including those tagged with 'samples', and tests with code coverage. Verbose output is enabled with `-v`.
```bash
# Run all tests (main package has no tests, only samples have tests)
go test -v ./...
# Run tests including samples
go test -v -tags samples ./...
# Run tests with coverage
go test -v -cover ./...
go test -v -cover -tags samples ./...
```
--------------------------------
### Go: Main Functions of 'with' Package
Source: https://github.com/spandigital/with/blob/develop/README.md
Lists the primary functions provided by the 'with' Go package for managing functional options. These include applying defaults, adding options, validation, and panic-on-error variants.
```go
///
/// Apply defaults, then options, then validate
///
func DefaultThenAddWith[T any](opts T, funcs []Func[T]) error
///
/// Apply options and validate (no defaults)
///
func AddWith[T any](opts T, funcs []Func[T]) error
///
/// Like `DefaultThenAddWith` but panics on error
///
func MustDefaultThenAddWith[T any](opts T, funcs []Func[T])
///
/// Like `AddWith` but panics on error
///
func MustAddWith[T any](opts T, funcs []Func[T])
///
/// Returns a no-op option function
///
func Nop[T any]() Func[T]
```
--------------------------------
### Go Lint Command
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Runs the golangci-lint tool to perform static analysis and linting on the Go code. This command helps maintain code quality and identify potential issues.
```bash
golangci-lint run
```
--------------------------------
### Apply functional options to a struct in Go
Source: https://context7.com/spandigital/with/llms.txt
This Go code demonstrates how to use the `with.AddWith` function to apply a series of functional options to an existing struct. It defines a `DatabaseOptions` struct with a `Validate` method and then creates specific functional options like `WithDatabaseHost` and `WithMaxConnections`. The `NewDatabaseFromConfig` function utilizes `with.AddWith` to merge base configurations with provided functional options, ensuring validation is performed.
```go
package main
import (
"errors"
"fmt"
"time"
"github.com/spandigital/with"
)
type DatabaseOptions struct {
Host string
Port int
Username string
Password string
MaxConns int
}
func (o *DatabaseOptions) Validate() error {
if o.Host == "" {
return errors.New("host is required")
}
if o.Port < 1 || o.Port > 65535 {
return errors.New("port must be between 1 and 65535")
}
if o.Username == "" {
return errors.New("username is required")
}
if o.MaxConns < 1 {
return errors.New("max connections must be at least 1")
}
return nil
}
func WithDatabaseHost(host string) with.Func[DatabaseOptions] {
return func(o *DatabaseOptions) error {
o.Host = host
return nil
}
}
func WithDatabasePort(port int) with.Func[DatabaseOptions] {
return func(o *DatabaseOptions) error {
o.Port = port
return nil
}
}
func WithMaxConnections(max int) with.Func[DatabaseOptions] {
return func(o *DatabaseOptions) error {
if max < 1 {
return errors.New("max connections must be at least 1")
}
o.MaxConns = max
return nil
}
}
type Database struct {
options *DatabaseOptions
}
func NewDatabaseFromConfig(baseConfig *DatabaseOptions, opts ...with.Func[DatabaseOptions]) (*Database, error) {
if err := with.AddWith(baseConfig, opts); err != nil {
return nil, err
}
return &Database{options: baseConfig},
}
func main() {
// Start with a struct, apply additional options
baseConfig := &DatabaseOptions{
Host: "db.example.com",
Port: 5432,
Username: "admin",
Password: "secret",
MaxConns: 10,
}
db1, err := NewDatabaseFromConfig(baseConfig)
if err != nil {
panic(err)
}
fmt.Printf("DB1: %s:%d (max conns: %d)\n",
db1.options.Host, db1.options.Port, db1.options.MaxConns)
// Output: DB1: db.example.com:5432 (max conns: 10)
// Override specific fields from struct
baseConfig2 := &DatabaseOptions{
Host: "localhost",
Port: 5432,
Username: "dev",
Password: "dev123",
MaxConns: 5,
}
db2, err := NewDatabaseFromConfig(
baseConfig2,
WithDatabaseHost("staging.example.com"),
WithMaxConnections(50),
)
if err != nil {
panic(err)
}
fmt.Printf("DB2: %s:%d (max conns: %d)\n",
db2.options.Host, db2.options.Port, db2.options.MaxConns)
// Output: DB2: staging.example.com:5432 (max conns: 50)
// Error case: validation fails with incomplete config
incompleteConfig := &DatabaseOptions{
Host: "example.com",
Port: 5432,
// Missing username
}
_, err = NewDatabaseFromConfig(incompleteConfig)
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: validation failed: username is required
}
// Error case: invalid option
_, err = NewDatabaseFromConfig(
baseConfig,
WithMaxConnections(0),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: cannot apply WithMaxConnections: max connections must be at least 1
}
}
```
--------------------------------
### Go: Implementing Functional Options with Generic Type
Source: https://context7.com/spandigital/with/llms.txt
This Go code defines a generic functional option pattern for configuring an `EmailOptions` struct. It includes functions to set the sender, add recipients, set the subject, and define the body, with built-in validation for each option and the overall struct. The `SendEmail` function applies these options using the `with.AddWith` helper.
```go
package main
import (
"errors"
"fmt"
"strings"
"github.com/spandigital/with"
)
type EmailOptions struct {
From string
To []string
Subject string
Body string
}
func (o *EmailOptions) Validate() error {
if o.From == "" {
return errors.New("from address is required")
}
if len(o.To) == 0 {
return errors.New("at least one recipient is required")
}
return nil
}
// Simple option function
func WithFrom(from string) with.Func[EmailOptions] {
return func(o *EmailOptions) error {
if !strings.Contains(from, "@") {
return errors.New("invalid email address")
}
o.From = from
return nil
}
}
// Option function that appends to a slice
func WithRecipient(to string) with.Func[EmailOptions] {
return func(o *EmailOptions) error {
if !strings.Contains(to, "@") {
return errors.New("invalid email address")
}
o.To = append(o.To, to)
return nil
}
}
// Option function with complex validation
func WithSubject(subject string) with.Func[EmailOptions] {
return func(o *EmailOptions) error {
if len(subject) > 200 {
return errors.New("subject too long (max 200 characters)")
}
if subject == "" {
return errors.New("subject cannot be empty")
}
o.Subject = subject
return nil
}
}
// Option function that modifies data
func WithBody(body string) with.Func[EmailOptions] {
return func(o *EmailOptions) error {
// Process body (e.g., sanitize, format)
o.Body = strings.TrimSpace(body)
return nil
}
}
func SendEmail(opts ...with.Func[EmailOptions]) error {
o := &EmailOptions{}
if err := with.AddWith(o, opts); err != nil {
return err
}
fmt.Printf("Sending email:\nFrom: %s\nTo: %v\nSubject: %s\nBody: %s\n",
o.From, o.To, o.Subject, o.Body)
return nil
}
func main() {
// Successful email with multiple recipients
err := SendEmail(
WithFrom("sender@example.com"),
WithRecipient("recipient1@example.com"),
WithRecipient("recipient2@example.com"),
WithSubject("Important Update"),
WithBody("This is the email body."),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
// Output:
// Sending email:
// From: sender@example.com
// To: [recipient1@example.com recipient2@example.com]
// Subject: Important Update
// Body: This is the email body.
// Error case: invalid email format
err = SendEmail(
WithFrom("invalid-email"),
WithRecipient("user@example.com"),
WithSubject("Test"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: cannot apply WithFrom: invalid email address
}
// Error case: subject too long
longSubject := strings.Repeat("A", 201)
err = SendEmail(
WithFrom("sender@example.com"),
WithRecipient("user@example.com"),
WithSubject(longSubject),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: cannot apply WithSubject: subject too long (max 200 characters)
}
// Error case: validation fails (missing recipient)
err = SendEmail(
WithFrom("sender@example.com"),
WithSubject("Test"),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
// Output: Error: validation failed: at least one recipient is required
}
}
```
--------------------------------
### Go: Implement Defaulted Interface for Cache Options
Source: https://context7.com/spandigital/with/llms.txt
This Go code defines a CacheOptions struct that implements the Defaulted interface. The SetDefaults method initializes default values for TTL, MaxSize, and EvictionPolicy. It also provides functional options (WithTTL, WithMaxSize, WithEvictionPolicy) to modify these options.
```go
package main
import (
"fmt"
"time"
"github.com/spandigital/with"
)
type CacheOptions struct {
TTL time.Duration
MaxSize int
EvictionPolicy string
}
func (o *CacheOptions) SetDefaults() {
o.TTL = 5 * time.Minute
o.MaxSize = 1000
o.EvictionPolicy = "LRU"
}
func WithTTL(ttl time.Duration) with.Func[CacheOptions] {
return func(o *CacheOptions) error {
o.TTL = ttl
return nil
}
}
func WithMaxSize(size int) with.Func[CacheOptions] {
return func(o *CacheOptions) error {
o.MaxSize = size
return nil
}
}
func WithEvictionPolicy(policy string) with.Func[CacheOptions] {
return func(o *CacheOptions) error {
o.EvictionPolicy = policy
return nil
}
}
type Cache struct {
ttl time.Duration
maxSize int
evictionPolicy string
}
func NewCache(opts ...with.Func[CacheOptions]) (*Cache, error) {
o := &CacheOptions{}
if err := with.DefaultThenAddWith(o, opts); err != nil {
return nil, err
}
return &Cache{
ttl: o.TTL,
maxSize: o.MaxSize,
evictionPolicy: o.EvictionPolicy,
},
nil
}
func main() {
// Use all defaults
cache1, _ := NewCache()
fmt.Printf("Cache1: TTL=%v, MaxSize=%d, Policy=%s\n",
cache1.ttl, cache1.maxSize, cache1.evictionPolicy)
// Output: Cache1: TTL=5m0s, MaxSize=1000, Policy=LRU
// Override just TTL, keep other defaults
cache2, _ := NewCache(WithTTL(10 * time.Minute))
fmt.Printf("Cache2: TTL=%v, MaxSize=%d, Policy=%s\n",
cache2.ttl, cache2.maxSize, cache2.evictionPolicy)
// Output: Cache2: TTL=10m0s, MaxSize=1000, Policy=LRU
// Override multiple options
cache3, _ := NewCache(
WithTTL(1 * time.Hour),
WithMaxSize(5000),
WithEvictionPolicy("LFU"),
)
fmt.Printf("Cache3: TTL=%v, MaxSize=%d, Policy=%s\n",
cache3.ttl, cache3.maxSize, cache3.evictionPolicy)
// Output: Cache3: TTL=1h0m0s, MaxSize=5000, Policy=LFU
// Last option wins for the same field
cache4, _ := NewCache(
WithMaxSize(100),
WithMaxSize(200),
)
fmt.Printf("Cache4: MaxSize=%d\n", cache4.maxSize)
// Output: Cache4: MaxSize=200
}
```
--------------------------------
### Go DefaultThenAddWith Function
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Applies default values to an options struct if it implements the `Defaulted` interface, and then applies functional options. Supports generic type `O`.
```go
func DefaultThenAddWith[O any](opts *O, options ...Func[O]) error {
if d, ok := any(opts).(Defaulted); ok {
if err := d.SetDefaults(); err != nil {
return fmt.Errorf("failed to set defaults: %w", err)
}
}
return AddWith(opts, options...)
}
```
--------------------------------
### Go AddWith Function
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Applies functional options to an options struct and performs validation if the struct implements the `Validated` interface. Supports generic type `O`.
```go
func AddWith[O any](opts *O, options ...Func[O]) error {
for _, opt := range options {
if err := opt(opts); err != nil {
// Automatically extract function name for better debugging
// Uses reflection, could be optimized if performance critical
return fmt.Errorf("failed to apply option %q: %w", getFuncName(opt), err)
}
}
if v, ok := any(opts).(Validated); ok {
if err := v.Validate(); err != nil {
return fmt.Errorf("failed to validate options: %w", err)
}
}
return nil
}
```
--------------------------------
### Go Nop Function
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Returns a no-operation functional option function for a given generic type `O`. This function does nothing and returns no error.
```go
func Nop[O any]() Func[O] {
return func(_ *O) error { return nil }
}
```
--------------------------------
### Go Generic Option Function Type
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Defines a generic function type `Func` that accepts a type parameter `O` and returns an error. This is used for implementing functional options in Go.
```go
type Func[O any] func(o *O) error
```
--------------------------------
### Go Defaulted Interface
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Defines an optional interface `Defaulted` for types that can set their own default values. Implementations must provide a `SetDefaults()` method.
```go
type Defaulted interface {
SetDefaults() error
}
```
--------------------------------
### Go Validated Interface
Source: https://github.com/spandigital/with/blob/develop/CLAUDE.md
Defines an optional interface `Validated` for types that require validation after options have been applied. Implementations must provide a `Validate()` method.
```go
type Validated interface {
Validate() error
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.