xyerror

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Aug 21, 2022 License: MIT Imports: 3 Imported by: 0

README

Introduction

Xyerror contains special errors that are good for error comparison and debugging. This package is inspired by idea of Python Exception.

Features

Python Exception Idea

Xyerror defined an error type used to create other errors called Class, it is equivalent to Exception class in Python.

Class creates XyError objects by using New method. It looks like Exception class creates Exception instances. Example:

// xyerror
var xerr xyerror.XyError
xerr = xyerror.ValueError.New("value is invalid")
fmt.Println(xerr)
# python
print(ValueError("value is invalid"))

A Class can "inherits" from another Class. Example:

// xyerror
var ZeroDivisionError = xyerror.ValueError.NewClass("ZeroDivisionError")
fmt.Println(ZeroDivisionError.New("do not divide by zero"))
# python
class ZeroDivisionError(ValueError):
    ...
print(ZeroDivisionError("do not divide by zero"))

A Class also "inherits" from some Class instances. Example:

// xyerror
var ValueTypeError = xyerror.
    Combine(xyerror.ValueError, xyerror.TypeError).
    NewClass("ValueTypeError")
# python
class ValueTypeError(ValueError, TypeError):
    ...

A XyError created by Class can compare to this Class.

// xyerror
func foo() error {
    return xyerror.ValueError.New("value is invalid")
}

func bar() error {
    if xerr := foo(); errors.Is(xerr, xyerror.ValueError) {
        fmt.Println(xerr)
    } else {
        return xerr
    }
    return nil
}
# python
def foo():
    raise ValueError("value is invalid")

def bar():
    try:
        foo()
    except ValueError as e:
        print(e)

Error number

Every Class has its own unique number called Errno. This number is used to compare a XyError with a Class. All XyError instances created by the same Class have the same errno.

Module-oriented Error

Xyerror is tended to create module-oriented errors. Errno of all Class instances in a module need to be the same prefix.

For example, ValueError and TypeError are in Default module. So their errno should be 100001 and 100002, respectively. In this case, 100000 is the prefix number of Default module.

Every module needs to create an object called Generator to create its error Class instances. Prefix of module is a self-defined value, it must be divisible by 100000 and not equal to other modules' prefix.

var egen = xyerror.Register("XyExample", 200000)
var (
    FooError = egen.NewClass("FooError")
    BarError = egen.NewClass("BarError")
)

Visit pkg.go.dev for more details.

Example

package xyerror_test

import (
	"errors"
	"fmt"

	"github.com/xybor/xyplatform/xyerror"
)

var exampleGen = xyerror.Register("example", 400000)

func ExampleClass() {
	// To create a root Class, call Generator.NewClass with the name of Class.
	var RootError = exampleGen.NewClass("RootError")

	// You can create a class from another one.
	var ChildError = RootError.NewClass("ChildError")

	fmt.Println(RootError)
	fmt.Println(ChildError)

	// Output:
	// [400001] RootError
	// [400002] ChildError
}

func ExampleXyError() {
	// You can compare a XyError with an Class by using the built-in method
	// errors.Is.
	var NegativeIndexError = xyerror.IndexError.NewClass("NegativeIndexError")

	var err1 = xyerror.ValueError.New("some value error")
	if errors.Is(err1, xyerror.ValueError) {
		fmt.Println("err1 is a ValueError")
	}
	if !errors.Is(err1, NegativeIndexError) {
		fmt.Println("err1 is not a NegativeIndexError")
	}

	var err2 = NegativeIndexError.New("some negative index error")
	if errors.Is(err2, NegativeIndexError) {
		fmt.Println("err2 is a NegativeIndexError")
	}
	if errors.Is(err2, xyerror.IndexError) {
		fmt.Println("err2 is a IndexError")
	}
	if !errors.Is(err2, xyerror.ValueError) {
		fmt.Println("err2 is not a ValueError")
	}

	// Output:
	// err1 is a ValueError
	// err1 is not a NegativeIndexError
	// err2 is a NegativeIndexError
	// err2 is a IndexError
	// err2 is not a ValueError
}

func ExampleGroup() {
	// Group allows you to create a class with multiparents.
	var KeyValueError = xyerror.
		Combine(xyerror.KeyError, xyerror.ValueError).
		NewClass(exampleGen, "KeyValueError")

	var err = KeyValueError.New("something is wrong")

	if errors.Is(err, xyerror.KeyError) {
		fmt.Println("err is a KeyError")
	}

	if errors.Is(err, xyerror.ValueError) {
		fmt.Println("err is a ValueError")
	}

	// Output:
	// err is a KeyError
	// err is a ValueError
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	UnknownError        = defaultGen.NewClass("UnknownError")
	IOError             = defaultGen.NewClass("IOError")
	FloatingPointError  = defaultGen.NewClass("FloatingPointError")
	IndexError          = defaultGen.NewClass("IndexError")
	KeyError            = defaultGen.NewClass("KeyError")
	NotImplementedError = defaultGen.NewClass("NotImplementedError")
	ValueError          = defaultGen.NewClass("ValueError")
	ParameterError      = defaultGen.NewClass("ParameterError")
	TypeError           = defaultGen.NewClass("TypeError")
	AssertionError      = defaultGen.NewClass("AssertionError")
)

Functions

func Or

func Or(errs ...error) error

Or returns the first not-nil error. If all errors are nil, return nil.

Types

type Class

type Class struct {
	// contains filtered or unexported fields
}

Class is a special error with error number and error name. Error number is a unique number of Class and helps to determine which module the error Class belongs to.

The main purpose of error Class is creating a XyError, so that it should not be used for returning.

A Class can be created by one or many parent Classes. The Class without parent is called root Class..

Example
package main

import (
	"fmt"

	"github.com/xybor/xyplatform/xyerror"
)

var exampleGen = xyerror.Register("example", 400000)

func main() {
	// To create a root Class, call Generator.NewClass with the name of Class.
	var RootError = exampleGen.NewClass("RootError")

	// You can create a class from another one.
	var ChildError = RootError.NewClass("ChildError")

	fmt.Println(RootError)
	fmt.Println(ChildError)

}
Output:

[400001] RootError
[400002] ChildError

func (Class) Error

func (c Class) Error() string

Error is the method to treat Class as an error.

func (Class) New

func (c Class) New(msg string, a ...any) XyError

New creates a XyError with an error message.

func (Class) NewClass

func (c Class) NewClass(name string, args ...any) Class

NewClass creates a new Class with called Class as parent.

func (Class) NewClassM

func (c Class) NewClassM(gen Generator) Class

NewClassM creates a new error class with this class as parent. It has another errorid and the same name.

type Generator

type Generator struct {
	// contains filtered or unexported fields
}

Generator is used to generate root Class for every module. It is determined by the identifier of module.

func Register

func Register(name string, id int) Generator

Register adds a Module with its identifier to managing pool for creating new Classes.

func (Generator) NewClass

func (gen Generator) NewClass(name string, args ...any) Class

NewClass creates a root Class with error number will be determined by module's id in Generator.

type Group

type Group []Class
Example
package main

import (
	"errors"
	"fmt"

	"github.com/xybor/xyplatform/xyerror"
)

var exampleGen = xyerror.Register("example", 400000)

func main() {
	// Group allows you to create a class with multiparents.
	var KeyValueError = xyerror.
		Combine(xyerror.KeyError, xyerror.ValueError).
		NewClass(exampleGen, "KeyValueError")

	var err = KeyValueError.New("something is wrong")

	if errors.Is(err, xyerror.KeyError) {
		fmt.Println("err is a KeyError")
	}

	if errors.Is(err, xyerror.ValueError) {
		fmt.Println("err is a ValueError")
	}

}
Output:

err is a KeyError
err is a ValueError

func Combine

func Combine(cs ...Class) Group

Combine supports creating a group of error classes. This group can be used to create the Class with multiparents.

func (Group) NewClass

func (g Group) NewClass(gen Generator, name string, a ...any) Class

NewClass creates a Class with multiparents.

type XyError

type XyError struct {
	// contains filtered or unexported fields
}

XyError is an error supporting to check if an error belongs to a class or not.

errors.Is(err, cls) returns true if err is created by cls itself or cls's child class.

Example
package main

import (
	"errors"
	"fmt"

	"github.com/xybor/xyplatform/xyerror"
)

func main() {
	// You can compare a XyError with an Class by using the built-in method
	// errors.Is.
	var NegativeIndexError = xyerror.IndexError.NewClass("NegativeIndexError")

	var err1 = xyerror.ValueError.New("some value error")
	if errors.Is(err1, xyerror.ValueError) {
		fmt.Println("err1 is a ValueError")
	}
	if !errors.Is(err1, NegativeIndexError) {
		fmt.Println("err1 is not a NegativeIndexError")
	}

	var err2 = NegativeIndexError.New("some negative index error")
	if errors.Is(err2, NegativeIndexError) {
		fmt.Println("err2 is a NegativeIndexError")
	}
	if errors.Is(err2, xyerror.IndexError) {
		fmt.Println("err2 is a IndexError")
	}
	if !errors.Is(err2, xyerror.ValueError) {
		fmt.Println("err2 is not a ValueError")
	}

}
Output:

err1 is a ValueError
err1 is not a NegativeIndexError
err2 is a NegativeIndexError
err2 is a IndexError
err2 is not a ValueError

func (XyError) Error

func (xerr XyError) Error() string

Error is the method to treat XyError as an error.

func (XyError) Is

func (xerr XyError) Is(target error) bool

Is is the method used to customize errors.Is method.

Jump to

Keyboard shortcuts

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