Skip to content

Commit fd7b890

Browse files
committed
cleanup
1 parent 848d840 commit fd7b890

File tree

1 file changed

+93
-59
lines changed

1 file changed

+93
-59
lines changed

README.md

Lines changed: 93 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
# err2
2+
13
[![test](https://github.com/lainio/err2/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/lainio/err2/actions/workflows/test.yml)
24
![Go Version](https://img.shields.io/badge/go%20version-%3E=1.18-61CFDD.svg?style=flat-square)
35
[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/lainio/err2)](https://pkg.go.dev/mod/github.com/lainio/err2)
46
[![Go Report Card](https://goreportcard.com/badge/github.com/lainio/err2?style=flat-square)](https://goreportcard.com/report/github.com/lainio/err2)
57

6-
# err2
8+
<img src="https://github.com/lainio/err2/raw/bench-tests/logo/logo.png" width="100">
9+
10+
----
711

812
The package extends Go's error handling with **fully automatic error checking
913
and propagation** like other modern programming languages: **Zig**, Rust, Swift,
@@ -28,6 +32,8 @@ func CopyFile(src, dst string) (err error) {
2832
}
2933
```
3034

35+
----
36+
3137
`go get github.com/lainio/err2`
3238

3339
- [Structure](#structure)
@@ -37,7 +43,6 @@ func CopyFile(src, dst string) (err error) {
3743
- [Error Stack Tracing](#error-stack-tracing)
3844
- [Error Checks](#error-checks)
3945
- [Filters for non-errors like io.EOF](#filters-for-non-errors-like-ioeof)
40-
- [Backwards Compatibility Promise for the API](#backwards-compatibility-promise-for-the-api)
4146
- [Assertion](#assertion)
4247
- [Asserters](#asserters)
4348
- [Assertion Package for Runtime Use](#assertion-package-for-runtime-use)
@@ -75,17 +80,15 @@ run `benchmarks` in the project repo and see yourself.
7580
7681
## Automatic Error Propagation
7782

78-
The current version of Go tends to produce too much error checking and too
79-
little error handling. But most importantly, it doesn't help developers with
80-
**automatic** error propagation, which would have the same benefits as, e.g.,
81-
**automated** garbage collection or automatic testing:
82-
8383
Automatic error propagation is crucial because it makes your *code change
84-
tolerant*. And, of course, it helps to make your code error-safe:
84+
tolerant*. And, of course, it helps to make your code error-safe.
8585

8686
![Never send a human to do a machine's job](https://www.magicalquote.com/wp-content/uploads/2013/10/Never-send-a-human-to-do-a-machines-job.jpg)
8787

88-
The err2 package is your automation buddy:
88+
89+
<details>
90+
<summary>The err2 package is your automation buddy:</summary>
91+
<br/>
8992

9093
1. It helps to declare error handlers with `defer`. If you're familiar with [Zig
9194
language](https://ziglang.org/), you can think `defer err2.Handle(&err,...)`
@@ -101,31 +104,47 @@ You can use all of them or just the other. However, if you use `try` for error
101104
checks, you must remember to use Go's `recover()` by yourself, or your error
102105
isn't transformed to an `error` return value at any point.
103106

104-
## Error handling
107+
</details>
105108

106-
The `err2` relies on Go's declarative programming structure `defer`. The
107-
`err2` helps to set deferred functions (error handlers) which are only called if
108-
`err != nil`.
109+
## Error Handling
109110

110-
Every function which uses err2 for error-checking should have at least one error
111-
handler. The current function panics if there are no error handlers and an error
112-
occurs. However, if *any* function above in the call stack has an err2 error
113-
handler, it will catch the error.
111+
The err2 relies on Go's declarative programming structure `defer`. The
112+
err2 helps to set deferred error handlers which are only called if an error
113+
occurs.
114114

115-
This is the simplest form of `err2` automatic error handler:
115+
This is the simplest form of an automatic error handler:
116116

117117
```go
118118
func doSomething() (err error) {
119-
// below: if err != nil { return ftm.Errorf("%s: %w", CUR_FUNC_NAME, err) }
120119
defer err2.Handle(&err)
121120
```
122121
122+
<details>
123+
<summary>The explanation of the above code and its error handler:</summary>
124+
<br/>
125+
126+
Simplest rule for err2 error handlers are:
127+
1. Use named error return value: `(..., err error)`
128+
1. Add at least one error handler at the beginning of your function (see the
129+
above code block). *Handlers are called only if error ≠ nil.*
130+
1. Use `err2.handle` functions different calling schemes to achieve needed
131+
behaviour. For example, without no extra arguments `err2.Handle`
132+
automatically annotates your errors by building annotations string from the
133+
function's current name: `doSomething → "do something"`. Default is decamel
134+
and add spaces. See `err2.SetFormatter` for more information.
135+
1. Every function which uses err2 for error-checking should have at least one
136+
error handler. The current function panics if there are no error handlers and
137+
an error occurs. However, if *any* function above in the call stack has an
138+
err2 error handler, it will catch the error.
139+
123140
See more information from `err2.Handle`'s documentation. It supports several
124141
error-handling scenarios. And remember that you can have as many error handlers
125142
per function as you need, as well as you can chain error handling functions per
126143
`err2.Handle` that allows you to build new error handling middleware for your
127144
own purposes.
128145
146+
</details>
147+
129148
#### Error Stack Tracing
130149
131150
The err2 offers optional stack tracing. It's automatic and optimized. Optimized
@@ -134,7 +153,10 @@ trace starts from where the actual error/panic is occurred, not where the error
134153
is caught. You don't need to search for the line where the pointer was nil or
135154
received an error. That line is in the first one you are seeing:
136155
137-
```console
156+
<details>
157+
<summary>The example of the optimized call stack:</summary>
158+
159+
```sh
138160
---
139161
runtime error: index out of range [0] with length 0
140162
---
@@ -145,6 +167,8 @@ main.main()
145167
/home/.../go/src/github.com/lainio/ic/main.go:77 +0x248
146168
```
147169
170+
</details><br/>
171+
148172
Just set the `err2.SetErrorTracer` or `err2.SetPanicTracer` to the stream you
149173
want traces to be written:
150174
@@ -197,7 +221,7 @@ handling.
197221
198222
Nevertheless, there might be cases where you might want to:
199223
1. Suppress the error and use some default value.
200-
1. Just write a logline and continue without a break.
224+
1. Just write logging output and continue without breaking the execution.
201225
1. Annotate the specific error value even when you have a general error handler.
202226
1. You want to handle the specific error value, let's say, at the same line
203227
or statement.
@@ -229,6 +253,7 @@ actual errors we have functions like `try.Is` and even `try.IsEOF` for
229253
convenience.
230254
231255
With these you can write code where error is translated to boolean value:
256+
232257
```go
233258
notExist := try.Is(r2.err, plugin.ErrNotExist)
234259

@@ -245,23 +270,8 @@ notExist := try.Is(r2.err, plugin.ErrNotExist)
245270
> 3. Finally, it calls `try.To` for the non nil error, and we already know what then
246271
> happens: nearest `err2.Handle` gets it first.
247272
248-
These `try.Is` functions help cleanup mess idiomatic Go, i.e. mixing happy and
249-
error path, leads to.
250-
251273
For more information see the examples in the documentation of both functions.
252274
253-
## Backwards Compatibility Promise for the API
254-
255-
The `err2` package's API will be **backward compatible**. Before version
256-
1.0.0 is released, the API changes occasionally, but **we promise to offer
257-
automatic conversion scripts for your repos to update them for the latest API.**
258-
We also mark functions deprecated before they become obsolete. Usually, one
259-
released version before. We have tested this with a large code base in our
260-
systems, and it works wonderfully.
261-
262-
More information can be found in the `scripts/` directory [readme
263-
file](./scripts/README.md).
264-
265275
## Assertion
266276
267277
The `assert` package is meant to be used for *design-by-contract-* type of
@@ -282,17 +292,15 @@ assert.SetDefault(assert.Production)
282292
```
283293
284294
If you want to suppress the caller info (source file name, line number, etc.)
285-
and get just the plain panics from the asserts, you should set the
286-
default asserter with the following line:
295+
from certain asserts, you can do that per a goroutine or a function. You should
296+
set the asserter with the following line for the current function:
287297
288298
```go
289-
assert.SetDefault(assert.Debug)
299+
defer assert.PushAsserter(assert.Plain)()
290300
```
291301
292-
For certain type of programs this is the best way. It allows us to keep all the
293-
error messages as simple as possible. And by offering option to turn additional
294-
information on, which allows super users and developers get more technical
295-
information when needed.
302+
This is especially good if you want to use assert functions for CLI's flag
303+
validation or you want your app behave like legacy Go programs.
296304
297305
> [!NOTE]
298306
> Since v0.9.5 you can set these asserters through Go's standard flag package
@@ -305,10 +313,10 @@ Following is example of use of the assert package:
305313
306314
```go
307315
func marshalAttestedCredentialData(json []byte, data *protocol.AuthenticatorData) []byte {
308-
assert.SLen(data.AttData.AAGUID, 16, "wrong AAGUID length")
309-
assert.NotEmpty(data.AttData.CredentialID, "empty credential id")
310-
assert.SNotEmpty(data.AttData.CredentialPublicKey, "empty credential public key")
311-
...
316+
assert.SLen(data.AttData.AAGUID, 16, "wrong AAGUID length")
317+
assert.NotEmpty(data.AttData.CredentialID, "empty credential id")
318+
assert.SNotEmpty(data.AttData.CredentialPublicKey, "empty credential public key")
319+
...
312320
```
313321
314322
We have now described design-by-contract for development and runtime use. What
@@ -317,7 +325,11 @@ automatic testing as well.
317325
318326
#### Assertion Package for Unit Testing
319327
320-
The same asserts can be used **and shared** during the unit tests:
328+
The same asserts can be used **and shared** during the unit tests.
329+
330+
<details>
331+
<summary>The unit test code example:</summary>
332+
321333
322334
```go
323335
func TestWebOfTrustInfo(t *testing.T) {
@@ -345,6 +357,8 @@ of the actual Test function, **it's reported as a standard test failure.** That
345357
means we don't need to open our internal pre- and post-conditions just for
346358
testing.
347359
360+
</details><br/>
361+
348362
**We can share the same assertions between runtime and test execution.**
349363
350364
The err2 `assert` package integration to the Go `testing` package is completed at
@@ -365,9 +379,12 @@ have an option to automatically support for err2 configuration flags through
365379
Go's standard `flag` package. See more information about err2 settings from
366380
[Error Stack Tracing](#error-stack-tracing) and [Asserters](#asserters).
367381
368-
Now you can always deploy your applications and services with the simple
369-
end-user friendly error messages and no stack traces, **but you can switch them
370-
on when ever you need**.
382+
You can deploy your applications and services with the simple *end-user friendly
383+
error messages and no stack traces.*
384+
385+
<details>
386+
<summary>You can switch them on when ever you need them again.</summary>
387+
<br/>
371388
372389
Let's say you have build CLI (`your-app`) tool with the support for Go's flag
373390
package, and the app returns an error. Let's assume you're a developer. You can
@@ -389,12 +406,17 @@ That adds more information to the assertion statement, which in default is in
389406
production (`Prod`) mode, i.e., outputs a single-line assertion message.
390407
391408
All you need to do is to add `flag.Parse` to your `main` function.
409+
</details>
392410
393411
#### Support for Cobra Flags
394412
395413
If you are using [cobra](https://github.com/spf13/cobra) you can still easily
396414
support packages like `err2` and `glog` and their flags.
397415
416+
<details>
417+
<summary>Add cobra support:</summary>
418+
<br/>
419+
398420
1. Add std flag package to imports in `cmd/root.go`:
399421
400422
```go
@@ -442,17 +464,28 @@ Flags:
442464
...
443465
```
444466
467+
</details>
468+
445469
## Code Snippets
446470
447-
Most of the repetitive code blocks are offered as code snippets. They are in
448-
`./snippets` in VC code format, which is well supported e.g. neovim, etc.
471+
<details>
472+
<summary>Most of the repetitive code blocks are offered as code snippets.</summary>
473+
<br/>
474+
475+
They are in `./snippets` in VC code format, which is well supported e.g. neovim,
476+
etc.
449477
450478
The snippets must be installed manually to your preferred IDE/editor. During the
451479
installation you can modify the according your style or add new ones. We would
452480
prefer if you could contribute some of the back to the err2 package.
481+
</details>
453482
454483
## Background
455484
485+
<details>
486+
<summary>Why this repo exists?</summary>
487+
<br/>
488+
456489
`err2` implements similar error handling mechanism as drafted in the original
457490
[check/handle
458491
proposal](https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md).
@@ -492,14 +525,15 @@ help:
492525
background) to projects,
493526
- and most importantly, **it keeps your code more refactorable** because you
494527
don't have to repeat yourself.
495-
496-
<details>
497-
<summary>Learnings...</summary>
528+
</details>
498529
499530
## Learnings by so far
500531
501-
We have used the `err2` and `assert` packages in several projects. The results
502-
have been so far very encouraging:
532+
<details>
533+
<summary>We have used the err2 and assert packages in several projects. </summary>
534+
<br/>
535+
536+
The results have been so far very encouraging:
503537
504538
- If you forget to use handler, but you use checks from the package, you will
505539
get panics on errors (and optimized stack traces that can be suppressed). That
@@ -517,7 +551,7 @@ been much easier.** There is an excellent [blog post](https://jesseduffield.com/
517551
about the issues you are facing with Go's error handling without the help of
518552
the err2 package.
519553
520-
</details><br/>
554+
</details>
521555
522556
## Support And Contributions
523557

0 commit comments

Comments
 (0)