go-options-gen

📁 metalagman/agent-skills 📅 5 days ago
1
总安装量
1
周安装量
#52231
全站排名
安装命令
npx skills add https://github.com/metalagman/agent-skills --skill go-options-gen

Agent 安装分布

amp 1
opencode 1
kimi-cli 1
codex 1
github-copilot 1
claude-code 1

Skill 文档

go-options-gen

You are an expert in using the options-gen library (https://github.com/kazhuravlev/options-gen) to create robust, type-safe functional options for Go components. You prioritize unexported option fields to maintain encapsulation while providing a clean, exported API for configuration.

Core Mandates

  • File Naming:
    • Single Option Set: Struct definition MUST be in options.go, and generated code MUST be in options_generated.go.
    • Multiple Option Sets: For a component named MyService, the struct (e.g., MyServiceOptions) MUST be in myservice_options.go, and generated code MUST be in myservice_options_generated.go.
  • Encapsulation:
    • Options fields within the struct SHOULD be unexported (start with a lowercase letter) to prevent direct modification from outside the package.
  • Tooling:
    • Always run the tool using go tool options-gen.
    • Install and track the tool in go.mod using:
      go get -tool github.com/kazhuravlev/options-gen/cmd/options-gen@latest
      
  • Validation:
    • Always include validation tags (using go-playground/validator syntax) for configuration fields.
    • ALWAYS call the generated Validate() method within the component’s constructor.
  • Component Integration:
    • Store the resulting options struct in an unexported field named opts within your component struct.

Developer Workflow

  1. Installation: Ensure the tool is tracked in your project:

    go get -tool github.com/kazhuravlev/options-gen/cmd/options-gen@latest
    
  2. Define Options (options.go): Define your options struct with unexported fields. Use the //go:generate directive to specify the output filename and the target struct.

    package mypackage
    
    import "time"
    
    //go:generate go tool options-gen -from-struct=Options -out-filename=options_generated.go
    type Options struct {
        timeout    time.Duration `option:"mandatory" validate:"required"`
        maxRetries int           `default:"3" validate:"min=1"`
        endpoints  []string      `option:"variadic=true"`
    }
    
  3. Generate: Run the generator:

    go generate ./options.go
    
  4. Integration: Use the generated types in your component’s constructor and store them in an opts field.

    type Component struct {
        opts Options
    }
    
    func New(setters ...OptionOptionsSetter) (*Component, error) {
        opts := NewOptions(setters...)
        if err := opts.Validate(); err != nil {
            return nil, fmt.Errorf("invalid options: %w", err)
        }
        return &Component{opts: opts}, nil
    }
    

Expert Guidance

Mandatory vs. Default

  • Use option:"mandatory" for fields that have no safe default (e.g., API keys, target URLs). These become required arguments in NewOptions().
  • Use default:"value" for sensible defaults. options-gen supports basic types and time.Duration.

Advanced Defaults

For complex types (like maps or nested structs), use -defaults-from=func in the generate directive and define a provider function:

//go:generate go tool options-gen -from-struct=Options -out-filename=options_generated.go -defaults-from=func
func defaultOptions() Options {
    return Options{
        headers: map[string]string{"User-Agent": "my-client"},
    }
}

Validation Best Practices

  • Use validate:"required" for any field that must not be zero-valued.
  • Use validate:"oneof=tcp udp" for enum-like string fields.
  • Use validate:"min=1" for counters or sizes.

Variadic Setters

For slice fields, use option:"variadic=true" to generate a setter that accepts multiple arguments (e.g., WithEndpoints("a", "b")) instead of a single slice (e.g., WithEndpoints([]string{"a", "b"})).

Avoiding Exported Fields

By keeping fields unexported in options.go, you ensure that the only way to configure the component is through the generated With* setters, which can include validation logic.

Multiple Options in One Package

When a package contains multiple components (e.g., Client and Server), use prefixes to avoid name collisions in generated types and functions.

  1. Filenames: Use <prefix>_options.go and <prefix>_options_generated.go.
  2. Generator Flag: Use -out-prefix to prefix the generated NewOptions and Option...Setter types.

Example for MyService (myservice_options.go):

//go:generate go tool options-gen -from-struct=MyServiceOptions -out-filename=myservice_options_generated.go -out-prefix=MyService
type MyServiceOptions struct {
    timeout time.Duration `option:"mandatory"`
}

This will generate NewMyServiceOptions and OptionMyServiceOptionsSetter, allowing them to coexist with other options in the same package.

Resources

  • Examples: Complete implementations showing unexported fields, validation, and component integration can be found in the assets directory.