Compare commits
	
		
			1 commit
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 750635bd1a | 
					 10 changed files with 63 additions and 676 deletions
				
			
		
							
								
								
									
										30
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,35 +1,7 @@ | ||||||
| # gotry | # gotry | ||||||
| 
 | 
 | ||||||
| This package is a fork of lainio's [err2](https://github.com/lainio/err2) | This package is a fork of lainio's [err2](https://github.com/lainio/err2) | ||||||
| package with an improved code generator. | package. | ||||||
| 
 |  | ||||||
| ## Add custom try package to your project |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| go install code.thetadev.de/ThetaDev/gotry/gotry_generate |  | ||||||
| 
 |  | ||||||
| gotry_generate -init |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### Add type definitions |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| 📂 try/types.csv |  | ||||||
| 
 |  | ||||||
| <Handler method name>;<Type>;<Import#1>;<Import#2>;... |  | ||||||
| 
 |  | ||||||
| # Example: |  | ||||||
| DB;*gorm.DB;gorm.io/gorm |  | ||||||
| 
 |  | ||||||
| # Add +s to the method name to generate 2 handlers for single values and slices |  | ||||||
| String+s;string |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### Generate |  | ||||||
| 
 |  | ||||||
| ```sh |  | ||||||
| go generate ./try |  | ||||||
| ``` |  | ||||||
| 
 | 
 | ||||||
| ## Handle errors | ## Handle errors | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								embed.go
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								embed.go
									
										
									
									
									
								
							|  | @ -1,11 +0,0 @@ | ||||||
| package gotry |  | ||||||
| 
 |  | ||||||
| import "embed" |  | ||||||
| 
 |  | ||||||
| //go:generate go run ./gotry_generate -of std_types |  | ||||||
| 
 |  | ||||||
| //go:embed try/*.go |  | ||||||
| var TryFiles embed.FS |  | ||||||
| 
 |  | ||||||
| //go:embed try/types.tmpl |  | ||||||
| var TypesTemplate string |  | ||||||
							
								
								
									
										2
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -1,3 +1,3 @@ | ||||||
| module code.thetadev.de/ThetaDev/gotry | module code.thetadev.de/ThetaDev/gotry | ||||||
| 
 | 
 | ||||||
| go 1.16 | go 1.18 | ||||||
|  |  | ||||||
|  | @ -1,150 +0,0 @@ | ||||||
| package main |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"bufio" |  | ||||||
| 	"flag" |  | ||||||
| 	"fmt" |  | ||||||
| 	"os" |  | ||||||
| 	"os/exec" |  | ||||||
| 	"path" |  | ||||||
| 	"regexp" |  | ||||||
| 	"strings" |  | ||||||
| 	"text/template" |  | ||||||
| 
 |  | ||||||
| 	"code.thetadev.de/ThetaDev/gotry" |  | ||||||
| 	"code.thetadev.de/ThetaDev/gotry/try" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| var variablePattern = regexp.MustCompile(`^(\w[\w\d]*)(\+s)?$`) |  | ||||||
| 
 |  | ||||||
| type line struct { |  | ||||||
| 	Name      string |  | ||||||
| 	WithSlice bool |  | ||||||
| 	Types     []string |  | ||||||
| 	UseExt    bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func parseDefinitions(defFileName, outFileName, pkgName string) (err try.Err) { |  | ||||||
| 	defer try.Annotate(&err, "error parsing definitions") |  | ||||||
| 
 |  | ||||||
| 	defFile := try.File(os.Open(defFileName)) |  | ||||||
| 	useExt := pkgName != "try" |  | ||||||
| 
 |  | ||||||
| 	fileScanner := bufio.NewScanner(defFile) |  | ||||||
| 	fileScanner.Split(bufio.ScanLines) |  | ||||||
| 
 |  | ||||||
| 	ln := 0 |  | ||||||
| 	var lines []line |  | ||||||
| 	imports := map[string]bool{} |  | ||||||
| 
 |  | ||||||
| 	for fileScanner.Scan() { |  | ||||||
| 		lineStr := strings.TrimSpace(fileScanner.Text()) |  | ||||||
| 		ln++ |  | ||||||
| 
 |  | ||||||
| 		if lineStr == "" || strings.HasPrefix(lineStr, "#") || |  | ||||||
| 			strings.HasPrefix(lineStr, "/") { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		lineData, err := parseLine(lineStr, imports) |  | ||||||
| 		if err != nil { |  | ||||||
| 			fmt.Printf("[Err] line %d, %s: \"%s\n", ln, err.Error(), lineStr) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		lineData.UseExt = useExt |  | ||||||
| 
 |  | ||||||
| 		lines = append(lines, *lineData) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fmt.Printf("Parsed %d definitions\n", len(lines)) |  | ||||||
| 
 |  | ||||||
| 	outFile := try.File(os.Create(outFileName)) |  | ||||||
| 
 |  | ||||||
| 	tmpl := template.Must(template.New("templ").Parse(gotry.TypesTemplate)) |  | ||||||
| 
 |  | ||||||
| 	try.Check(tmpl.Execute(outFile, struct { |  | ||||||
| 		Definitions []line |  | ||||||
| 		Imports     map[string]bool |  | ||||||
| 		PkgName     string |  | ||||||
| 		UseExt      bool |  | ||||||
| 	}{ |  | ||||||
| 		Definitions: lines, |  | ||||||
| 		Imports:     imports, |  | ||||||
| 		PkgName:     pkgName, |  | ||||||
| 		UseExt:      useExt, |  | ||||||
| 	})) |  | ||||||
| 
 |  | ||||||
| 	try.Check(defFile.Close()) |  | ||||||
| 	try.Check(outFile.Close()) |  | ||||||
| 
 |  | ||||||
| 	try.Check(goFmt(outFileName)) |  | ||||||
| 
 |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func parseLine(lineStr string, imports map[string]bool) (*line, try.Err) { |  | ||||||
| 	lineParts := strings.Split(lineStr, ";") |  | ||||||
| 	lineData := line{} |  | ||||||
| 
 |  | ||||||
| 	if len(lineParts) < 2 { |  | ||||||
| 		return nil, try.NewErr("missing type name") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Parse variable name |  | ||||||
| 	variableRaw := strings.TrimSpace(lineParts[0]) |  | ||||||
| 	if match := variablePattern.FindStringSubmatch(variableRaw); match != nil { |  | ||||||
| 		lineData.Name = match[1] |  | ||||||
| 		lineData.WithSlice = match[2] != "" |  | ||||||
| 	} else { |  | ||||||
| 		return nil, try.NewErr("invalid variable name") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Parse type name(s) |  | ||||||
| 	for _, typeStr := range strings.Split(lineParts[1], ",") { |  | ||||||
| 		typeStr = strings.TrimSpace(typeStr) |  | ||||||
| 		if typeStr != "" { |  | ||||||
| 			lineData.Types = append(lineData.Types, typeStr) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if len(lineData.Types) == 0 { |  | ||||||
| 		return nil, try.NewErr("invalid type name") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Parse imports |  | ||||||
| 	for i := 2; i < len(lineParts); i++ { |  | ||||||
| 		pkgName := strings.TrimSpace(lineParts[i]) |  | ||||||
| 		imports[pkgName] = true |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return &lineData, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func goFmt(goFile string) error { |  | ||||||
| 	return exec.Command("gofmt", "-s", "-w", goFile).Run() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func main() { |  | ||||||
| 	defer try.CatchTrace(1) |  | ||||||
| 
 |  | ||||||
| 	// Read flags |  | ||||||
| 	var definitionFile string |  | ||||||
| 	var targetDir string |  | ||||||
| 	var typeFile string |  | ||||||
| 
 |  | ||||||
| 	flag.StringVar(&definitionFile, "def", path.Join("try", "types.csv"), |  | ||||||
| 		"Definition file") |  | ||||||
| 	flag.StringVar(&targetDir, "o", "try", "Target directory") |  | ||||||
| 	flag.StringVar(&typeFile, "of", "types", "Name of generated type definition file") |  | ||||||
| 	flag.Parse() |  | ||||||
| 
 |  | ||||||
| 	try.Check(os.MkdirAll(targetDir, 0o777)) |  | ||||||
| 
 |  | ||||||
| 	// Generate types |  | ||||||
| 	if _, e := os.Stat(definitionFile); os.IsNotExist(e) { |  | ||||||
| 		try.Check(try.NewErr("Definition file does not exist")) |  | ||||||
| 	} else { |  | ||||||
| 		try.Check( |  | ||||||
| 			parseDefinitions(definitionFile, path.Join(targetDir, typeFile+".go"), |  | ||||||
| 				path.Base(targetDir))) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										290
									
								
								try/std_types.go
									
										
									
									
									
								
							
							
						
						
									
										290
									
								
								try/std_types.go
									
										
									
									
									
								
							|  | @ -1,290 +0,0 @@ | ||||||
| package try |  | ||||||
| 
 |  | ||||||
| // gotry auto-generated type definitions. DO NOT EDIT. |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"io" |  | ||||||
| 	"net/http" |  | ||||||
| 	"net/url" |  | ||||||
| 	"os" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // Bool is a helper method to handle errors of |  | ||||||
| // func() (bool, error) functions. |  | ||||||
| func Bool(v bool, err error) bool { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Bools is a helper method to handle errors of |  | ||||||
| // func() ([]bool, error) functions. |  | ||||||
| func Bools(v []bool, err error) []bool { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Byte is a helper method to handle errors of |  | ||||||
| // func() (byte, error) functions. |  | ||||||
| func Byte(v byte, err error) byte { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Bytes is a helper method to handle errors of |  | ||||||
| // func() ([]byte, error) functions. |  | ||||||
| func Bytes(v []byte, err error) []byte { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Rune is a helper method to handle errors of |  | ||||||
| // func() (rune, error) functions. |  | ||||||
| func Rune(v rune, err error) rune { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Runes is a helper method to handle errors of |  | ||||||
| // func() ([]rune, error) functions. |  | ||||||
| func Runes(v []rune, err error) []rune { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // String is a helper method to handle errors of |  | ||||||
| // func() (string, error) functions. |  | ||||||
| func String(v string, err error) string { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Strings is a helper method to handle errors of |  | ||||||
| // func() ([]string, error) functions. |  | ||||||
| func Strings(v []string, err error) []string { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int is a helper method to handle errors of |  | ||||||
| // func() (int, error) functions. |  | ||||||
| func Int(v int, err error) int { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Ints is a helper method to handle errors of |  | ||||||
| // func() ([]int, error) functions. |  | ||||||
| func Ints(v []int, err error) []int { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int8 is a helper method to handle errors of |  | ||||||
| // func() (int8, error) functions. |  | ||||||
| func Int8(v int8, err error) int8 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int8s is a helper method to handle errors of |  | ||||||
| // func() ([]int8, error) functions. |  | ||||||
| func Int8s(v []int8, err error) []int8 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int16 is a helper method to handle errors of |  | ||||||
| // func() (int16, error) functions. |  | ||||||
| func Int16(v int16, err error) int16 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int16s is a helper method to handle errors of |  | ||||||
| // func() ([]int16, error) functions. |  | ||||||
| func Int16s(v []int16, err error) []int16 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int32 is a helper method to handle errors of |  | ||||||
| // func() (int32, error) functions. |  | ||||||
| func Int32(v int32, err error) int32 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int32s is a helper method to handle errors of |  | ||||||
| // func() ([]int32, error) functions. |  | ||||||
| func Int32s(v []int32, err error) []int32 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int64 is a helper method to handle errors of |  | ||||||
| // func() (int64, error) functions. |  | ||||||
| func Int64(v int64, err error) int64 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Int64s is a helper method to handle errors of |  | ||||||
| // func() ([]int64, error) functions. |  | ||||||
| func Int64s(v []int64, err error) []int64 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint is a helper method to handle errors of |  | ||||||
| // func() (uint, error) functions. |  | ||||||
| func Uint(v uint, err error) uint { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uints is a helper method to handle errors of |  | ||||||
| // func() ([]uint, error) functions. |  | ||||||
| func Uints(v []uint, err error) []uint { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint8 is a helper method to handle errors of |  | ||||||
| // func() (uint8, error) functions. |  | ||||||
| func Uint8(v uint8, err error) uint8 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint8s is a helper method to handle errors of |  | ||||||
| // func() ([]uint8, error) functions. |  | ||||||
| func Uint8s(v []uint8, err error) []uint8 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint16 is a helper method to handle errors of |  | ||||||
| // func() (uint16, error) functions. |  | ||||||
| func Uint16(v uint16, err error) uint16 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint16s is a helper method to handle errors of |  | ||||||
| // func() ([]uint16, error) functions. |  | ||||||
| func Uint16s(v []uint16, err error) []uint16 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint32 is a helper method to handle errors of |  | ||||||
| // func() (uint32, error) functions. |  | ||||||
| func Uint32(v uint32, err error) uint32 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint32s is a helper method to handle errors of |  | ||||||
| // func() ([]uint32, error) functions. |  | ||||||
| func Uint32s(v []uint32, err error) []uint32 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint64 is a helper method to handle errors of |  | ||||||
| // func() (uint64, error) functions. |  | ||||||
| func Uint64(v uint64, err error) uint64 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Uint64s is a helper method to handle errors of |  | ||||||
| // func() ([]uint64, error) functions. |  | ||||||
| func Uint64s(v []uint64, err error) []uint64 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Float32 is a helper method to handle errors of |  | ||||||
| // func() (float32, error) functions. |  | ||||||
| func Float32(v float32, err error) float32 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Float32s is a helper method to handle errors of |  | ||||||
| // func() ([]float32, error) functions. |  | ||||||
| func Float32s(v []float32, err error) []float32 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Float64 is a helper method to handle errors of |  | ||||||
| // func() (float64, error) functions. |  | ||||||
| func Float64(v float64, err error) float64 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Float64s is a helper method to handle errors of |  | ||||||
| // func() ([]float64, error) functions. |  | ||||||
| func Float64s(v []float64, err error) []float64 { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // StrStr is a helper method to handle errors of |  | ||||||
| // func() (string, string, error) functions. |  | ||||||
| func StrStr(v string, v1 string, err error) (string, string) { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v, v1 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // X is a helper method to handle errors of |  | ||||||
| // func() (interface{}, error) functions. |  | ||||||
| func X(v interface{}, err error) interface{} { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // File is a helper method to handle errors of |  | ||||||
| // func() (*os.File, error) functions. |  | ||||||
| func File(v *os.File, err error) *os.File { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Reader is a helper method to handle errors of |  | ||||||
| // func() (io.Reader, error) functions. |  | ||||||
| func Reader(v io.Reader, err error) io.Reader { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Writer is a helper method to handle errors of |  | ||||||
| // func() (io.Writer, error) functions. |  | ||||||
| func Writer(v io.Writer, err error) io.Writer { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Request is a helper method to handle errors of |  | ||||||
| // func() (*http.Request, error) functions. |  | ||||||
| func Request(v *http.Request, err error) *http.Request { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Response is a helper method to handle errors of |  | ||||||
| // func() (*http.Response, error) functions. |  | ||||||
| func Response(v *http.Response, err error) *http.Response { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Url is a helper method to handle errors of |  | ||||||
| // func() (*url.URL, error) functions. |  | ||||||
| func Url(v *url.URL, err error) *url.URL { |  | ||||||
| 	Check(err) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
|  | @ -1,68 +0,0 @@ | ||||||
| package try |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"os" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestStrHelper_noThrow(t *testing.T) { |  | ||||||
| 	s := String(noThrow()) |  | ||||||
| 	if s != "test" { |  | ||||||
| 		t.Fail() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestStrHelper_throw(t *testing.T) { |  | ||||||
| 	var err Err |  | ||||||
| 	defer Return(&err) |  | ||||||
| 
 |  | ||||||
| 	String(throw()) |  | ||||||
| 
 |  | ||||||
| 	t.Fail() // If everything works we are never here |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestStrStrHelper(t *testing.T) { |  | ||||||
| 	s1, s2 := StrStr(twoStrNoThrow()) |  | ||||||
| 	if s1 != "test" || s2 != "test" { |  | ||||||
| 		t.Fail() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func Example_copyFile() { |  | ||||||
| 	copyFile := func(src, dst string) (err Err) { |  | ||||||
| 		defer Annotate(&err, fmt.Sprintf("copy %s %s", src, dst)) |  | ||||||
| 
 |  | ||||||
| 		// These helpers are as fast as Check() calls |  | ||||||
| 		r := File(os.Open(src)) |  | ||||||
| 		defer Check(r.Close()) |  | ||||||
| 
 |  | ||||||
| 		w := File(os.Create(dst)) |  | ||||||
| 		defer Handle(&err, func() { |  | ||||||
| 			os.Remove(dst) |  | ||||||
| 		}) |  | ||||||
| 		defer Check(w.Close()) |  | ||||||
| 		Empty(io.Copy(w, r)) |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err := copyFile("/notfound/path/file.go", "/notfound/path/file.bak") |  | ||||||
| 	if err != nil { |  | ||||||
| 		fmt.Println(err) |  | ||||||
| 	} |  | ||||||
| 	//nolint:lll |  | ||||||
| 	// Output: copy /notfound/path/file.go /notfound/path/file.bak: open /notfound/path/file.go: no such file or directory |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func BenchmarkTry_StringHelper(b *testing.B) { |  | ||||||
| 	for n := 0; n < b.N; n++ { |  | ||||||
| 		_ = String(noThrow()) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func BenchmarkTry_XHelper(b *testing.B) { |  | ||||||
| 	for n := 0; n < b.N; n++ { |  | ||||||
| 		_ = X(noThrow()).(string) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										68
									
								
								try/try.go
									
										
									
									
									
								
							
							
						
						
									
										68
									
								
								try/try.go
									
										
									
									
									
								
							|  | @ -46,8 +46,8 @@ type call struct { | ||||||
| 	Line     int    `json:"l"` | 	Line     int    `json:"l"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FromErr wraps a standard error into a try-compatible one with extended stack info. | // fromErr wraps a standard error into a try-compatible one with extended stack info. | ||||||
| func FromErr(err error) Err { | func fromErr(err error) Err { | ||||||
| 	// If the error is already try-compatible, return | 	// If the error is already try-compatible, return | ||||||
| 	//nolint:errorlint | 	//nolint:errorlint | ||||||
| 	cterr, ok := err.(Err) | 	cterr, ok := err.(Err) | ||||||
|  | @ -88,9 +88,9 @@ func FromErr(err error) Err { | ||||||
| 	return terr | 	return terr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewErr creates a new try-compatible error with extended stack info. | // newErr creates a new try-compatible error with extended stack info. | ||||||
| func NewErr(msg string) Err { | func newErr(msg string) Err { | ||||||
| 	return FromErr(errors.New(msg)) | 	return fromErr(errors.New(msg)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Error returns the standard go error message (initial message + annotations). | // Error returns the standard go error message (initial message + annotations). | ||||||
|  | @ -144,41 +144,37 @@ func (e *tryErr) Annotate(msg string) { | ||||||
| 	e.annotations = append(e.annotations, msg) | 	e.annotations = append(e.annotations, msg) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Empty is a helper method to handle errors of func() (string, error) functions. | // To is a helper function to call functions which returns (error) | ||||||
| func Empty(_ interface{}, err error) { | // and check the error value. If error occurs it panics the error where err2 | ||||||
| 	Check(err) | // handlers can catch it if needed. | ||||||
| } | func To(err error) { | ||||||
| 
 |  | ||||||
| // Any is as similar as proposed Go2 Try macro, but it's a function and it |  | ||||||
| // returns slice of interfaces. It has quite big performance penalty when |  | ||||||
| // compared to Check function. |  | ||||||
| func Any(args ...interface{}) []interface{} { |  | ||||||
| 	check(args) |  | ||||||
| 	return args |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Check performs the error check for the given argument. If the err is nil, |  | ||||||
| // it does nothing. According the measurements, it's as fast as if err != nil |  | ||||||
| // {return err} on happy path. |  | ||||||
| func Check(err error) { |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(FromErr(err)) | 		panic(fromErr(err)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Checks the error status of the last argument. It panics with "wrong | // To1 is a helper function to call functions which returns (any, error) | ||||||
| // signature" if the last calling parameter is not error. In case of error it | // and check the error value. If error occurs it panics the error where err2 | ||||||
| // delivers it by panicking. | // handlers can catch it if needed. | ||||||
| func check(args []interface{}) { | func To1[T any](v T, err error) T { | ||||||
| 	argCount := len(args) | 	To(err) | ||||||
| 	last := argCount - 1 | 	return v | ||||||
| 	if args[last] != nil { | } | ||||||
| 		err, ok := args[last].(error) | 
 | ||||||
| 		if !ok { | // To2 is a helper function to call functions which returns (any, any, error) | ||||||
| 			panic("wrong signature") | // and check the error value. If error occurs it panics the error where err2 | ||||||
| 		} | // handlers can catch it if needed. | ||||||
| 		panic(FromErr(err)) | func To2[T, U any](v1 T, v2 U, err error) (T, U) { | ||||||
| 	} | 	To(err) | ||||||
|  | 	return v1, v2 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // To3 is a helper function to call functions which returns (any, any, any, error) | ||||||
|  | // and check the error value. If error occurs it panics the error where err2 | ||||||
|  | // handlers can catch it if needed. | ||||||
|  | func To3[T, U, V any](v1 T, v2 U, v3 V, err error) (T, U, V) { | ||||||
|  | 	To(err) | ||||||
|  | 	return v1, v2, v3 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Handle is for adding an error handler to a function by defer. It's for | // Handle is for adding an error handler to a function by defer. It's for | ||||||
|  |  | ||||||
|  | @ -21,14 +21,12 @@ func twoStrNoThrow() (string, string, error) { return "test", "test", nil } | ||||||
| 
 | 
 | ||||||
| func noThrow() (string, error) { return "test", nil } | func noThrow() (string, error) { return "test", nil } | ||||||
| 
 | 
 | ||||||
| func wrongSignature() (int, int) { return 0, 0 } |  | ||||||
| 
 |  | ||||||
| func recursion(a int) int { | func recursion(a int) int { | ||||||
| 	if a == 0 { | 	if a == 0 { | ||||||
| 		return 0 | 		return 0 | ||||||
| 	} | 	} | ||||||
| 	s, err := noThrow() | 	s, err := noThrow() | ||||||
| 	Check(err) | 	To(err) | ||||||
| 	_ = s | 	_ = s | ||||||
| 	return a + recursion(a-1) | 	return a + recursion(a-1) | ||||||
| } | } | ||||||
|  | @ -53,14 +51,14 @@ func noErr() error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestAny_noError(t *testing.T) { | func Test_noError(t *testing.T) { | ||||||
| 	d := Any(noThrow()) | 	x := To1(noThrow()) | ||||||
| 	if d[0].(string) != "test" { | 	if x != "test" { | ||||||
| 		t.Fail() | 		t.Fail() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	d = Any(twoStrNoThrow()) | 	x, y := To2(twoStrNoThrow()) | ||||||
| 	if d[0].(string) != "test" || d[1].(string) != "test" { | 	if x != "test" || y != "test" { | ||||||
| 		t.Fail() | 		t.Fail() | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -69,7 +67,7 @@ func TestDefault_Error(t *testing.T) { | ||||||
| 	var err Err | 	var err Err | ||||||
| 	defer Return(&err) | 	defer Return(&err) | ||||||
| 
 | 
 | ||||||
| 	Any(throw()) | 	To1(throw()) | ||||||
| 
 | 
 | ||||||
| 	t.Fail() // If everything works we are never here | 	t.Fail() // If everything works we are never here | ||||||
| } | } | ||||||
|  | @ -78,7 +76,7 @@ func TestAny_Error(t *testing.T) { | ||||||
| 	var err Err | 	var err Err | ||||||
| 	defer Handle(&err, func() {}) | 	defer Handle(&err, func() {}) | ||||||
| 
 | 
 | ||||||
| 	Any(throw()) | 	To1(throw()) | ||||||
| 
 | 
 | ||||||
| 	t.Fail() // If everything works we are never here | 	t.Fail() // If everything works we are never here | ||||||
| } | } | ||||||
|  | @ -87,13 +85,13 @@ func panickingHandle() { | ||||||
| 	var err Err | 	var err Err | ||||||
| 	defer Handle(&err, func() {}) | 	defer Handle(&err, func() {}) | ||||||
| 
 | 
 | ||||||
| 	Any(wrongSignature()) | 	panic("test") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestPanickingCarryOn_Handle(t *testing.T) { | func TestPanickingCarryOn_Handle(t *testing.T) { | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if recover() == nil { | 		if recover() == nil { | ||||||
| 			t.Error("panics should went thru when not our errors") | 			t.Error("panics should go through when not our errors") | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| 	panickingHandle() | 	panickingHandle() | ||||||
|  | @ -102,7 +100,7 @@ func TestPanickingCarryOn_Handle(t *testing.T) { | ||||||
| func panickingCatchAll() { | func panickingCatchAll() { | ||||||
| 	defer CatchAll(func(err Err) {}, func(v interface{}) {}) | 	defer CatchAll(func(err Err) {}, func(v interface{}) {}) | ||||||
| 
 | 
 | ||||||
| 	Any(wrongSignature()) | 	panickingHandle() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestPanickingCatchAll(t *testing.T) { | func TestPanickingCatchAll(t *testing.T) { | ||||||
|  | @ -118,7 +116,7 @@ func panickingReturn() { | ||||||
| 	var err Err | 	var err Err | ||||||
| 	defer Return(&err) | 	defer Return(&err) | ||||||
| 
 | 
 | ||||||
| 	Any(wrongSignature()) | 	panickingHandle() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestPanicking_Return(t *testing.T) { | func TestPanicking_Return(t *testing.T) { | ||||||
|  | @ -133,7 +131,7 @@ func TestPanicking_Return(t *testing.T) { | ||||||
| func panickingCatch() { | func panickingCatch() { | ||||||
| 	defer Catch(func(err Err) {}) | 	defer Catch(func(err Err) {}) | ||||||
| 
 | 
 | ||||||
| 	Any(wrongSignature()) | 	panickingHandle() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestPanicking_Catch(t *testing.T) { | func TestPanicking_Catch(t *testing.T) { | ||||||
|  | @ -150,13 +148,13 @@ func TestCatch_Error(t *testing.T) { | ||||||
| 		// fmt.Printf("error and defer handling:%s\n", err) | 		// fmt.Printf("error and defer handling:%s\n", err) | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	Any(throw()) | 	To1(throw()) | ||||||
| 
 | 
 | ||||||
| 	t.Fail() // If everything works we are never here | 	t.Fail() // If everything works we are never here | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestNewTryErr(t *testing.T) { | func TestNewTryErr(t *testing.T) { | ||||||
| 	tryErr := NewErr("I f*cked up") | 	tryErr := newErr("I f*cked up") | ||||||
| 	callStack := tryErr.CallStackString() | 	callStack := tryErr.CallStackString() | ||||||
| 
 | 
 | ||||||
| 	if !strings.HasPrefix(callStack, "ERROR: I f*cked up\n") { | 	if !strings.HasPrefix(callStack, "ERROR: I f*cked up\n") { | ||||||
|  | @ -172,7 +170,7 @@ func TestNewTryErr(t *testing.T) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestGetData(t *testing.T) { | func TestGetData(t *testing.T) { | ||||||
| 	tryErr := NewErr("I f*cked up") | 	tryErr := newErr("I f*cked up") | ||||||
| 	tryErr.Annotate("test1") | 	tryErr.Annotate("test1") | ||||||
| 	tryErr.Annotate("test2") | 	tryErr.Annotate("test2") | ||||||
| 	data := tryErr.GetData() | 	data := tryErr.GetData() | ||||||
|  | @ -199,7 +197,7 @@ func TestGetData(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| func TestErrCompare(t *testing.T) { | func TestErrCompare(t *testing.T) { | ||||||
| 	err := errors.New("TestError") | 	err := errors.New("TestError") | ||||||
| 	tryErr := FromErr(err) | 	tryErr := fromErr(err) | ||||||
| 
 | 
 | ||||||
| 	if !errors.Is(tryErr, err) { | 	if !errors.Is(tryErr, err) { | ||||||
| 		t.Fail() | 		t.Fail() | ||||||
|  | @ -209,7 +207,7 @@ func TestErrCompare(t *testing.T) { | ||||||
| func TestReturnStd(t *testing.T) { | func TestReturnStd(t *testing.T) { | ||||||
| 	tf := func() (err error) { | 	tf := func() (err error) { | ||||||
| 		defer ReturnStd(&err) | 		defer ReturnStd(&err) | ||||||
| 		String(throw()) | 		To1(throw()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -221,11 +219,11 @@ func TestReturnStd(t *testing.T) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestCheckTryErr(t *testing.T) { | func TestCheckTryErr(t *testing.T) { | ||||||
| 	testErr := NewErr("TestErr") | 	testErr := newErr("TestErr") | ||||||
| 
 | 
 | ||||||
| 	tf := func() (err Err) { | 	tf := func() (err Err) { | ||||||
| 		defer Return(&err) | 		defer Return(&err) | ||||||
| 		Check(testErr) | 		To(testErr) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -239,14 +237,14 @@ func TestCheckTryErr(t *testing.T) { | ||||||
| func ExampleReturn() { | func ExampleReturn() { | ||||||
| 	var err Err | 	var err Err | ||||||
| 	defer Return(&err) | 	defer Return(&err) | ||||||
| 	Any(noThrow()) | 	To1(noThrow()) | ||||||
| 	// Output: | 	// Output: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ExampleAnnotate() { | func ExampleAnnotate() { | ||||||
| 	annotated := func() (err Err) { | 	annotated := func() (err Err) { | ||||||
| 		defer Annotate(&err, "annotated") | 		defer Annotate(&err, "annotated") | ||||||
| 		Any(throw()) | 		To1(throw()) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	err := annotated() | 	err := annotated() | ||||||
|  | @ -258,7 +256,7 @@ func ExampleAnnotate_deferStack() { | ||||||
| 	annotated := func() (err Err) { | 	annotated := func() (err Err) { | ||||||
| 		defer Annotate(&err, "annotated 2nd") | 		defer Annotate(&err, "annotated 2nd") | ||||||
| 		defer Annotate(&err, "annotated 1st") | 		defer Annotate(&err, "annotated 1st") | ||||||
| 		Any(throw()) | 		To1(throw()) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	err := annotated() | 	err := annotated() | ||||||
|  | @ -271,7 +269,7 @@ func ExampleHandle() { | ||||||
| 		defer Handle(&err, func() { | 		defer Handle(&err, func() { | ||||||
| 			err.Annotate(fmt.Sprintf("error with (%d, %d)", a, b)) | 			err.Annotate(fmt.Sprintf("error with (%d, %d)", a, b)) | ||||||
| 		}) | 		}) | ||||||
| 		Any(throw()) | 		To1(throw()) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	err := doSomething(1, 2) | 	err := doSomething(1, 2) | ||||||
|  | @ -290,34 +288,34 @@ func BenchmarkOldErrorCheckingWithIfClause(b *testing.B) { | ||||||
| 
 | 
 | ||||||
| func BenchmarkAny(b *testing.B) { | func BenchmarkAny(b *testing.B) { | ||||||
| 	for n := 0; n < b.N; n++ { | 	for n := 0; n < b.N; n++ { | ||||||
| 		Any(noThrow()) | 		To1(noThrow()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func BenchmarkAny_ErrVar(b *testing.B) { | func BenchmarkAny_ErrVar(b *testing.B) { | ||||||
| 	for n := 0; n < b.N; n++ { | 	for n := 0; n < b.N; n++ { | ||||||
| 		_, err := noThrow() | 		_, err := noThrow() | ||||||
| 		Any(err) | 		To(err) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func BenchmarkCheckInsideCall(b *testing.B) { | func BenchmarkCheckInsideCall(b *testing.B) { | ||||||
| 	for n := 0; n < b.N; n++ { | 	for n := 0; n < b.N; n++ { | ||||||
| 		Check(noErr()) | 		To(noErr()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func BenchmarkCheckVarCall(b *testing.B) { | func BenchmarkCheckVarCall(b *testing.B) { | ||||||
| 	for n := 0; n < b.N; n++ { | 	for n := 0; n < b.N; n++ { | ||||||
| 		err := noErr() | 		err := noErr() | ||||||
| 		Check(err) | 		To(err) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func BenchmarkCheck_ErrVar(b *testing.B) { | func BenchmarkCheck_ErrVar(b *testing.B) { | ||||||
| 	for n := 0; n < b.N; n++ { | 	for n := 0; n < b.N; n++ { | ||||||
| 		_, err := noThrow() | 		_, err := noThrow() | ||||||
| 		Check(err) | 		To(err) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,29 +0,0 @@ | ||||||
| Bool+s;bool |  | ||||||
| Byte+s;byte |  | ||||||
| Rune+s;rune |  | ||||||
| String+s;string |  | ||||||
| 
 |  | ||||||
| Int+s;int |  | ||||||
| Int8+s;int8 |  | ||||||
| Int16+s;int16 |  | ||||||
| Int32+s;int32 |  | ||||||
| Int64+s;int64 |  | ||||||
| 
 |  | ||||||
| Uint+s;uint |  | ||||||
| Uint8+s;uint8 |  | ||||||
| Uint16+s;uint16 |  | ||||||
| Uint32+s;uint32 |  | ||||||
| Uint64+s;uint64 |  | ||||||
| 
 |  | ||||||
| Float32+s;float32 |  | ||||||
| Float64+s;float64 |  | ||||||
| 
 |  | ||||||
| StrStr;string, string |  | ||||||
| X;interface{} |  | ||||||
| 
 |  | ||||||
| File;*os.File;os |  | ||||||
| Reader;io.Reader;io |  | ||||||
| Writer;io.Writer;io |  | ||||||
| Request;*http.Request;net/http |  | ||||||
| Response;*http.Response;net/http |  | ||||||
| Url;*url.URL;net/url |  | ||||||
| Can't render this file because it has a wrong number of fields in line 24. | 
|  | @ -1,31 +0,0 @@ | ||||||
| package {{.PkgName}} |  | ||||||
| 
 |  | ||||||
| // gotry auto-generated type definitions. DO NOT EDIT. |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| {{- if .UseExt }} |  | ||||||
| "code.thetadev.de/ThetaDev/gotry/try" |  | ||||||
| {{- end}} |  | ||||||
| {{- range $pkg, $b := .Imports}} |  | ||||||
| 	"{{$pkg}}" |  | ||||||
| {{- end}} |  | ||||||
| ) |  | ||||||
| {{range $d := .Definitions }} |  | ||||||
| // {{$d.Name}} is a helper method to handle errors of |  | ||||||
| // func() ({{range $i, $t := $d.Types}}{{$t}}, {{end}}error) functions. |  | ||||||
| func {{$d.Name}}({{range $i, $t := $d.Types}}v{{if $i}}{{$i}}{{end}} {{$t}}, {{end}}err error) ( |  | ||||||
| {{- range $i, $t := $d.Types}}{{if $i}}, {{end}}{{$t}}{{end}}) { |  | ||||||
| 	{{if .UseExt}}try.{{end}}Check(err) |  | ||||||
| 	return {{range $i, $t := $d.Types}}{{if $i}}, v{{$i}}{{else}}v{{end}}{{end}} |  | ||||||
| } |  | ||||||
| {{- if $d.WithSlice}} |  | ||||||
| 
 |  | ||||||
| // {{$d.Name}}s is a helper method to handle errors of |  | ||||||
| // func() ({{range $i, $t := $d.Types}}[]{{$t}}, {{end}}error) functions. |  | ||||||
| func {{$d.Name}}s({{range $i, $t := $d.Types}}v{{if $i}}{{$i}}{{end}} []{{$t}}, {{end}}err error) ( |  | ||||||
| {{- range $i, $t := $d.Types}}{{if $i}}, {{end}}[]{{$t}}{{end}}) { |  | ||||||
| 	{{if .UseExt}}try.{{end}}Check(err) |  | ||||||
| 	return {{range $i, $t := $d.Types}}{{if $i}}, v{{$i}}{{else}}v{{end}}{{end}} |  | ||||||
| } |  | ||||||
| {{- end}} |  | ||||||
| {{end}} |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue