sure enhances existing Go code with assertions and crash handling. It asserts conditions and crashes when issues happen, improving issue management in code without adding repetitive checks.
sure is a code generation package that transforms existing Go code into assertion-enhanced versions. Instead of adding repetitive checks throughout the codebase, sure generates wrapping code with built-in assertion logic, making issue detection and handling seamless.
The package provides three distinct generators, each serving different code transformation needs:
- sure_cls_gen: Creates assertion-enabled class wrappers
- sure_pkg_gen: Generates assertion-enabled package wrappers
- cls_stub_gen: Produces singleton wrapping functions
π― Three Assertion Modes
- Must: Crash on issues (panic-based)
- Soft: Log warnings and continue execution
- Omit: Silent mode - ignore issues
β‘ Automatic Code Generation
- Transform existing code without modification
- Generate type-safe wrappers with assertions
- Preserve function signatures and documentation
π§ Flexible Integration
- Works with existing Go projects
- No runtime dependencies in generated code
- Compatible with standard Go packages
π¦ Multiple Generation Strategies
- Class-based: Wrap object methods
- Package-based: Wrap package functions
- Singleton-based: Wrap instance methods as package functions
Standard issue handling in Go requires repetitive checks:
result, err := SomeOperation()
if err != nil {
log.Printf("operation failed: %v", err)
return err
}
data, err := AnotherOperation(result)
if err != nil {
log.Printf("another operation failed: %v", err)
return err
}This becomes verbose and repetitive across large codebases.
With sure, generate assertion-enabled wrappers:
// Source function
func ReadConfig(path string) (*Config, error)
// Generated wrapping (Must mode)
func (s *SureConfig) ReadConfig(path string) *Config
// Usage - crashes on issues, no manual checks needed
config := sureConfig.ReadConfig("config.json")The generated code handles assertions, enabling clean business logic.
Purpose: Creates wrapping classes from existing objects, embedding assertion logic in each method.
Use Case: When working with objects that have multiple methods returning issues, generate a wrapping class that handles all assertions.
How It Works:
- Takes an existing struct/interface
- Analyzes all methods with issue returns
- Generates wrapping class with assertion methods
- Each wrapping method removes issue returns, adding assertion logic
Example:
Source database client:
type DB struct { }
func (db *DB) Connect(dsn string) error
func (db *DB) Query(sql string) (*Result, error)
func (db *DB) Close() errorGenerated assertion wrapping:
type SureDB struct {
db *DB
}
func (s *SureDB) Connect(dsn string) // panics on issue
func (s *SureDB) Query(sql string) *Result // panics on issue
func (s *SureDB) Close() // panics on issueBenefits:
- No hand-written assertion code needed
- Type-safe wrappers
- Clean business logic code
- Consistent issue handling across methods
Code Generation:
See: sure_cls_gen example
Purpose: Extracts functions from existing packages and generates new assertion-enabled package versions.
Use Case: When a package has multiple functions returning issues, generate a companion package with assertion versions.
How It Works:
- Scans target package functions
- Identifies functions with issue returns
- Generates new package with assertion wrappers
- Maintains function signatures (minus issue returns)
Example:
Source package functions:
package config
func Load(path string) (*Config, error)
func Parse(data []byte) (*Config, error)
func Validate(cfg *Config) errorGenerated assertion package:
package sureconfig
func Load(path string) *Config // panics on issue
func Parse(data []byte) *Config // panics on issue
func Validate(cfg *Config) // panics on issueBenefits:
- Entire package gets assertion versions
- No modification to source package
- Use assertion package when appropriate
- Mix and match with source package
Code Generation:
See: sure_pkg_gen example
Purpose: Generates package-scope functions that wrap methods of a singleton instance.
Use Case: When working with singleton patterns, provide package-scope functions as convenient wrappers.
How It Works:
- Takes a struct with methods
- Assumes a singleton instance exists
- Generates package-scope functions
- Each function delegates to singleton instance
Example:
Singleton object with methods:
type Logger struct { }
func (l *Logger) Debug(msg string)
func (l *Logger) Info(msg string)
func (l *Logger) Warn(msg string)
func (l *Logger) Error(msg string)
var defaultLogger = &Logger{}Generated package functions:
func Debug(msg string) {
defaultLogger.Debug(msg)
}
func Info(msg string) {
defaultLogger.Info(msg)
}
func Warn(msg string) {
defaultLogger.Warn(msg)
}
func Error(msg string) {
defaultLogger.Error(msg)
}Benefits:
- Simple API - no instance needed
- Package-scope convenience functions
- Consistent with standard Go package design
- Maintains singleton pattern benefits
Code Generation:
See: cls_stub_gen example
go get github.com/yyle88/sureimport "github.com/yyle88/sure/sure_cls_gen"
// Generate assertion wrapping with Must mode
options := sure_cls_gen.NewOptions().
WithPackageName("mypackage").
WithClassName("SureClient")
code := sure_cls_gen.GenerateClassMethods(
originalObject,
options,
sure.MUST, // crash on issues
)import "github.com/yyle88/sure/sure_pkg_gen"
// Generate assertion package
config := sure_pkg_gen.NewSurePackageConfig(
projectPath,
sure.MUST,
"original/package/path",
)
functions := sure_pkg_gen.GenerateSureFunctions(t, config, outputPath)import "github.com/yyle88/sure/cls_stub_gen"
// Generate package-level wrapping
stubConfig := &cls_stub_gen.StubGenConfig{
SourceRootPath: projectPath,
TargetPackageName: "api",
OutputPath: outputPath,
}
code := cls_stub_gen.GenerateStubMethods(
stubConfig,
cls_stub_gen.NewStubParam(singletonInstance, "instance"),
)Source code with repetitive checks:
conn, err := db.Connect(dsn)
if err != nil { return err }
result, err := conn.Query(sql)
if err != nil { return err }
err = conn.Close()
if err != nil { return err }With sure_cls_gen:
sureDB := NewSureDB(db)
sureDB.Connect(dsn)
result := sureDB.Query(sql)
sureDB.Close()Source code:
cfg, err := config.Load("app.json")
if err != nil { return err }
err = config.Validate(cfg)
if err != nil { return err }With sure_pkg_gen:
cfg := sureconfig.Load("app.json")
sureconfig.Validate(cfg)Source singleton:
client.SetEndpoint(url)
response, err := client.Get("/api/data")
if err != nil { return err }With cls_stub_gen:
SetEndpoint(url)
response := Get("/api/data")Use sure.MUST when:
- Issues are unrecoverable
- Application cannot continue with issues
- During initialization and setup
- In test code
Use sure.SOFT when:
- Issues should be logged but not crash
- Smooth degradation is acceptable
- In production with fallback logic
- When monitoring issues without interruption
Use sure.OMIT when:
- Issues are expected and acceptable
- Silent failure is desired
- Performance-sensitive paths
- When issues are handled elsewhere
sure is designed to complement the done package:
- done: Provides inline assertion functions (
done.Done(),done.VAE()) - sure: Generates wrapping code with built-in assertions
Use done when writing new code, use sure to wrap existing code.
Example with done:
config := done.VAE(LoadConfig()).Nice()Example with sure:
config := sureConfig.Load() // generated wrappingBoth approaches reduce boilerplate, choose based on context.
Comprehensive examples demonstrating each generation approach:
- sure_cls_gen Example - Class wrapping generation
- sure_pkg_gen Example - Package wrapping generation
- cls_stub_gen Example - Singleton wrapping generation
Each example includes:
- Source code setup
- Generation configuration
- Generated code output
- Usage demonstrations
MIT License. See LICENSE.
Contributions are welcome! Report bugs, suggest features, and contribute code:
- π Found a mistake? Open an issue on GitHub with reproduction steps
- π‘ Have a feature idea? Create an issue to discuss the suggestion
- π Documentation confusing? Report it so we can improve
- π Need new features? Share the use cases to help us understand requirements
- β‘ Performance issue? Help us optimize through reporting slow operations
- π§ Configuration problem? Ask questions about complex setups
- π’ Follow project progress? Watch the repo to get new releases and features
- π Success stories? Share how this package improved the workflow
- π¬ Feedback? We welcome suggestions and comments
New code contributions, follow this process:
- Fork: Fork the repo on GitHub (using the webpage UI).
- Clone: Clone the forked project (
git clone https://github.com/yourname/repo-name.git). - Navigate: Navigate to the cloned project (
cd repo-name) - Branch: Create a feature branch (
git checkout -b feature/xxx). - Code: Implement the changes with comprehensive tests
- Testing: (Golang project) Ensure tests pass (
go test ./...) and follow Go code style conventions - Documentation: Update documentation to support client-facing changes and use significant commit messages
- Stage: Stage changes (
git add .) - Commit: Commit changes (
git commit -m "Add feature xxx") ensuring backward compatible code - Push: Push to the branch (
git push origin feature/xxx). - PR: Open a merge request on GitHub (on the GitHub webpage) with detailed description.
Please ensure tests pass and include relevant documentation updates.
Welcome to contribute to this project via submitting merge requests and reporting issues.
Project Support:
- β Give GitHub stars if this project helps you
- π€ Share with teammates and (golang) programming friends
- π Write tech blogs about development tools and workflows - we provide content writing support
- π Join the ecosystem - committed to supporting open source and the (golang) development scene
Have Fun Coding with this package! πππ