From 214cac7f11b599242f8f43303e788a315806e2ad Mon Sep 17 00:00:00 2001 From: huykingsofm Date: Fri, 2 Sep 2022 18:28:53 +0000 Subject: [PATCH] PLF-110 Rename Class and XyError --- CHANGELOG.md | 1 + README.md | 57 ++++++++-------- class.go | 81 ---------------------- default.go | 21 +++--- error.go | 27 +++----- error_test.go | 26 +++---- example_test.go | 22 +++--- exception.go | 106 +++++++++++++++++++++++++++++ class_test.go => exception_test.go | 6 +- group.go | 18 ----- 10 files changed, 180 insertions(+), 185 deletions(-) delete mode 100644 class.go create mode 100644 exception.go rename class_test.go => exception_test.go (69%) delete mode 100644 group.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a6b2a9..e9b1eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Developing - Make it simple by removing Generator. +- Rename some structs to make the package more popular. # v0.0.1 (Sep 02, 2022) diff --git a/README.md b/README.md index cfa12b5..3975157 100644 --- a/README.md +++ b/README.md @@ -10,25 +10,22 @@ # Introduction -Package xyerror supports to define error types conveniently. +Package xyerror supports to define and compare errors conveniently. -The error is inspired by the idea of Python `Exception`. +The error is inspired by Python `Exception`. # Features -## Python Exception Idea - Package xyerror defined an error type used to create other errors called -`Class`, it is equivalent to `Exception` class in Python. +`Exception`, 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: +`Exception` creates `Error` objects by using `New` or `Newf` method. It looks +like `Exception` class creates `Exception` instances. Example: ```golang // xyerror -var xerr xyerror.XyError -xerr = xyerror.ValueError.New("value is invalid") -fmt.Println(xerr) +var err xyerror.Error = xyerror.ValueError.New("value is invalid") +fmt.Println(err) ``` ```python @@ -36,11 +33,11 @@ fmt.Println(xerr) print(ValueError("value is invalid")) ``` -A `Class` can "inherits" from another `Class`. Example: +An `Exception` can "inherits" from another `Exception`. Example: ```golang // xyerror -var ZeroDivisionError = xyerror.ValueError.NewClass("ZeroDivisionError") +var ZeroDivisionError = xyerror.ValueError.NewException("ZeroDivisionError") fmt.Println(ZeroDivisionError.New("do not divide by zero")) ``` @@ -51,13 +48,13 @@ class ZeroDivisionError(ValueError): print(ZeroDivisionError("do not divide by zero")) ``` -A `Class` also "inherits" from some `Class` instances. Example: +An `Exception` also "inherits" from many `Exception` instances. Example: ```golang // xyerror var ValueTypeError = xyerror. Combine(xyerror.ValueError, xyerror.TypeError). - NewClass("ValueTypeError") + NewException("ValueTypeError") ``` ```python @@ -66,7 +63,7 @@ class ValueTypeError(ValueError, TypeError): ... ``` -A `XyError` created by `Class` can compare to this `Class`. +An `Error` created by an `Exception` can compare to that `Exception`. ```golang // xyerror @@ -75,10 +72,10 @@ func foo() error { } func bar() error { - if xerr := foo(); errors.Is(xerr, xyerror.ValueError) { - fmt.Println(xerr) + if err := foo(); errors.Is(err, xyerror.ValueError) { + fmt.Println(err) } else { - return xerr + return err } return nil } @@ -108,12 +105,12 @@ import ( "github.com/xybor-x/xyerror" ) -func ExampleClass() { - // To create a root Class, call xyerror.NewClass with the its name. - var RootError = xyerror.NewClass("RootError") +func ExampleException() { + // To create a root Exception, call xyerror.NewException with the its name. + var RootError = xyerror.NewException("RootError") - // You can create a class by inheriting from another one. - var ChildError = RootError.NewClass("ChildError") + // You can create an Exception by inheriting from another one. + var ChildError = RootError.NewException("ChildError") fmt.Println(RootError) fmt.Println(ChildError) @@ -123,14 +120,14 @@ func ExampleClass() { // ChildError } -func ExampleXyError() { - // You can compare a XyError with an Class by using the built-in method +func ExampleError() { + // You can compare an Error with an Exception by using the built-in method // errors.Is. - var NegativeIndexError = xyerror.IndexError.NewClass("NegativeIndexError") + var NegativeIndexError = xyerror.IndexError.NewException("NegativeIndexError") var err1 = xyerror.ValueError.New("some value error") if errors.Is(err1, xyerror.ValueError) { - fmt.Println("err1 is a ValueError") + fmt.Println("err1 is a ValueError") } if !errors.Is(err1, NegativeIndexError) { fmt.Println("err1 is not a NegativeIndexError") @@ -155,11 +152,11 @@ func ExampleXyError() { // err2 is not a ValueError } -func ExampleGroup() { - // Group allows you to create a class with multiparents. +func ExampleCombinedException() { + // CombinedException allows you to create an Exception with multiparents. var KeyValueError = xyerror. Combine(xyerror.KeyError, xyerror.ValueError). - NewClass("KeyValueError") + NewException("KeyValueError") var err = KeyValueError.New("something is wrong") diff --git a/class.go b/class.go deleted file mode 100644 index f27494c..0000000 --- a/class.go +++ /dev/null @@ -1,81 +0,0 @@ -package xyerror - -import ( - "fmt" - - "github.com/xybor-x/xylock" -) - -var counter = 0 -var classes []string -var lock = xylock.Lock{} - -// Class is the generic type for XyError. -type Class struct { - // The unique number of each Class. - errno int - - // The error name - name string - - // The parent classes - parent []Class -} - -// NewClass creates a root Class. -func NewClass(name string) Class { - lock.Lock() - defer lock.Unlock() - - for i := range classes { - if classes[i] == name { - panic("Do not use an existed error class name: " + name) - } - } - counter++ - classes = append(classes, name) - - return Class{ - errno: counter, - name: name, - parent: nil, - } -} - -// NewClass creates a new Class by inheriting the called Class. -func (c Class) NewClass(name string) Class { - var class = NewClass(name) - class.parent = []Class{c} - return class -} - -// Newf creates a XyError with a formatting message. -func (c Class) Newf(msg string, a ...any) XyError { - return XyError{c: c, msg: fmt.Sprintf(msg, a...)} -} - -// New creates a XyError with default formatting objects. -func (c Class) New(a ...any) XyError { - return XyError{c: c, msg: fmt.Sprint(a...)} -} - -// belongsTo checks if a Class is inherited from a target class. A class belongs -// to the target Class if it is created by the target itself or target's child. -func (c Class) belongsTo(t Class) bool { - if c.errno == t.errno { - return true - } - - for i := range c.parent { - if c.parent[i].belongsTo(t) { - return true - } - } - - return false -} - -// Error is the method to treat Class as an error. -func (c Class) Error() string { - return c.name -} diff --git a/default.go b/default.go index 8f92996..6f7b244 100644 --- a/default.go +++ b/default.go @@ -1,15 +1,14 @@ package xyerror -// Default predefined errors. +// Predefined Exceptions. var ( - Error = NewClass("Error") - IOError = NewClass("IOError") - FloatingPointError = NewClass("FloatingPointError") - IndexError = NewClass("IndexError") - KeyError = NewClass("KeyError") - NotImplementedError = NewClass("NotImplementedError") - ValueError = NewClass("ValueError") - ParameterError = NewClass("ParameterError") - TypeError = NewClass("TypeError") - AssertionError = NewClass("AssertionError") + BaseException = NewException("BaseException") + IOError = NewException("IOError") + FloatingPointError = NewException("FloatingPointError") + IndexError = NewException("IndexError") + KeyError = NewException("KeyError") + ValueError = NewException("ValueError") + ParameterError = NewException("ParameterError") + TypeError = NewException("TypeError") + AssertionError = NewException("AssertionError") ) diff --git a/error.go b/error.go index 57ff8a4..dde4f55 100644 --- a/error.go +++ b/error.go @@ -5,29 +5,20 @@ import ( "fmt" ) -// XyError is a special error belongs to a generic error class. -type XyError struct { - // error class - c Class - - // error message +// Error is a special error belongs to a generic error class. +type Error struct { + exc Exception msg string } -// Error is the method to treat XyError as an error. -func (xerr XyError) Error() string { - return fmt.Sprintf("%s: %s", xerr.c.name, xerr.msg) +// Error returns the Exception name along with the Error message. +func (err Error) Error() string { + return fmt.Sprintf("%s: %s", err.exc.name, err.msg) } -// Is is the method used to customize errors.Is method. -func (xerr XyError) Is(target error) bool { - if !errors.As(target, &Class{}) { - return false - } - - var tc = target.(Class) - - return xerr.c.belongsTo(tc) +// Is returns true if Error is created by the target Exception. +func (err Error) Is(target error) bool { + return errors.Is(err.exc, target) } // Or returns the first not-nil error. If all errors are nil, return nil. diff --git a/error_test.go b/error_test.go index eee3934..6985021 100644 --- a/error_test.go +++ b/error_test.go @@ -7,16 +7,16 @@ import ( "github.com/xybor-x/xyerror" ) -func TestXyError(t *testing.T) { - var c = xyerror.NewClass("XError") - var xerr1 = c.Newf("error-%d", 1) - var xerr2 = c.New("error-2") +func TestError(t *testing.T) { + var exc = xyerror.NewException("Error") + var err1 = exc.Newf("error-%d", 1) + var err2 = exc.New("error-2") - xycond.ExpectEqual(xerr1.Error(), "XError: error-1").Test(t) - xycond.ExpectEqual(xerr2.Error(), "XError: error-2").Test(t) + xycond.ExpectEqual(err1.Error(), "Error: error-1").Test(t) + xycond.ExpectEqual(err2.Error(), "Error: error-2").Test(t) } -func TestXyErrorIs(t *testing.T) { +func TestErrorIs(t *testing.T) { var err1 = xyerror.ValueError.New("err1") var err2 = xyerror.TypeError.New("err2") @@ -39,11 +39,11 @@ func TestOr(t *testing.T) { } func TestCombine(t *testing.T) { - var c = xyerror.Combine(xyerror.ValueError, xyerror.TypeError). - NewClass("ValueTypeError") - var xerr = c.New("foo") + var exc = xyerror.Combine(xyerror.ValueError, xyerror.TypeError). + NewException("ValueTypeError") + var err = exc.New("foo") - xycond.ExpectError(xerr, xyerror.ValueError).Test(t) - xycond.ExpectError(xerr, xyerror.TypeError).Test(t) - xycond.ExpectErrorNot(xerr, xyerror.IndexError).Test(t) + xycond.ExpectError(err, xyerror.ValueError).Test(t) + xycond.ExpectError(err, xyerror.TypeError).Test(t) + xycond.ExpectErrorNot(err, xyerror.IndexError).Test(t) } diff --git a/example_test.go b/example_test.go index 99679ad..7ffc4f0 100644 --- a/example_test.go +++ b/example_test.go @@ -7,12 +7,12 @@ import ( "github.com/xybor-x/xyerror" ) -func ExampleClass() { - // To create a root Class, call xyerror.NewClass with the its name. - var RootError = xyerror.NewClass("RootError") +func ExampleException() { + // To create a root Exception, call xyerror.NewException with the its name. + var RootError = xyerror.NewException("RootError") - // You can create a class by inheriting from another one. - var ChildError = RootError.NewClass("ChildError") + // You can create an Exception by inheriting from another one. + var ChildError = RootError.NewException("ChildError") fmt.Println(RootError) fmt.Println(ChildError) @@ -22,10 +22,10 @@ func ExampleClass() { // ChildError } -func ExampleXyError() { - // You can compare a XyError with an Class by using the built-in method +func ExampleError() { + // You can compare an Error with an Exception by using the built-in method // errors.Is. - var NegativeIndexError = xyerror.IndexError.NewClass("NegativeIndexError") + var NegativeIndexError = xyerror.IndexError.NewException("NegativeIndexError") var err1 = xyerror.ValueError.New("some value error") if errors.Is(err1, xyerror.ValueError) { @@ -54,11 +54,11 @@ func ExampleXyError() { // err2 is not a ValueError } -func ExampleGroup() { - // Group allows you to create a class with multiparents. +func ExampleCombinedException() { + // CombinedException allows you to create an Exception with multiparents. var KeyValueError = xyerror. Combine(xyerror.KeyError, xyerror.ValueError). - NewClass("KeyValueError") + NewException("KeyValueError") var err = KeyValueError.New("something is wrong") diff --git a/exception.go b/exception.go new file mode 100644 index 0000000..cf98b39 --- /dev/null +++ b/exception.go @@ -0,0 +1,106 @@ +package xyerror + +import ( + "errors" + "fmt" + + "github.com/xybor-x/xylock" +) + +var counter = 0 +var exceptions []string +var lock = xylock.Lock{} + +// Exception is the generic type of Errors. It does not contain the error +// message. You should use an Error by creating from Exception, instead of using +// Exception directly. +type Exception struct { + // The unique number is used to differentiate Exceptions. + id int + + // The Exception name + name string + + // The parent Exceptions + parent []Exception +} + +// NewException creates a root Exception. +func NewException(name string) Exception { + lock.Lock() + defer lock.Unlock() + + for i := range exceptions { + if exceptions[i] == name { + panic("Do not use an existed Exception name: " + name) + } + } + counter++ + exceptions = append(exceptions, name) + + return Exception{ + id: counter, + name: name, + parent: nil, + } +} + +// NewException creates a new Exception by inheriting the called Exception. +func (exc Exception) NewException(name string) Exception { + var class = NewException(name) + class.parent = []Exception{exc} + return class +} + +// Newf creates an Error with a formatting message. +func (exc Exception) Newf(msg string, a ...any) Error { + return Error{exc: exc, msg: fmt.Sprintf(msg, a...)} +} + +// New creates an Error with default formatting objects. +func (exc Exception) New(a ...any) Error { + return Error{exc: exc, msg: fmt.Sprint(a...)} +} + +// Is returns true if the Exception is inherited from the target. +func (exc Exception) Is(target error) bool { + if !errors.As(target, &Exception{}) { + return false + } + + var exception = target.(Exception) + + if exc.id == exception.id { + return true + } + + for i := range exc.parent { + if errors.Is(exc.parent[i], target) { + return true + } + } + + return false +} + +// Error returns the Exception name. +func (exc Exception) Error() string { + return exc.name +} + +// CombinedException is an array of Exception. It supports to creates an +// Exception inherited from many parents. +type CombinedException []Exception + +// Combine supports creating a group of Exceptions. This group can be used to +// create the Exception with multiparents. +func Combine(cs ...Exception) CombinedException { + return cs +} + +// NewException creates an Exception with multiparents. +func (combined CombinedException) NewException(name string) Exception { + var child = NewException(name) + child.parent = combined + return child +} diff --git a/class_test.go b/exception_test.go similarity index 69% rename from class_test.go rename to exception_test.go index 06cde73..05103d7 100644 --- a/class_test.go +++ b/exception_test.go @@ -8,9 +8,9 @@ import ( "github.com/xybor-x/xyerror" ) -func TestClassNewClass(t *testing.T) { - var c1 = xyerror.NewClass("class1") - var c2 = c1.NewClass("class2") +func TestException(t *testing.T) { + var c1 = xyerror.NewException("class1") + var c2 = c1.NewException("class2") xycond.ExpectTrue(strings.Contains(c1.Error(), "class1")).Test(t) xycond.ExpectTrue(strings.Contains(c2.Error(), "class2")).Test(t) } diff --git a/group.go b/group.go deleted file mode 100644 index 32effa8..0000000 --- a/group.go +++ /dev/null @@ -1,18 +0,0 @@ -package xyerror - -// Group is an array of class. It supports to creates a Class inherited from -// many parents. -type Group []Class - -// Combine supports creating a group of error classes. This group can be used -// to create the Class with multiparents. -func Combine(cs ...Class) Group { - return cs -} - -// NewClass creates a Class with multiparents. -func (g Group) NewClass(name string) Class { - var child = NewClass(name) - child.parent = g - return child -}