mirror of
https://github.com/logos-storage/questionable.git
synced 2026-01-07 00:03:10 +00:00
Without statement for Results provides access to errors
This commit is contained in:
parent
91a38040ea
commit
ef29000f94
14
Readme.md
14
Readme.md
@ -194,6 +194,20 @@ let value = fails() |? @[]
|
|||||||
let sum = works()[3] + 40
|
let sum = works()[3] + 40
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Without statement
|
||||||
|
|
||||||
|
The `without` statement can also be used with Results. It provides access to any
|
||||||
|
errors that may arise:
|
||||||
|
|
||||||
|
```nim
|
||||||
|
proc someProc(r: ?!int) =
|
||||||
|
without value =? r, error:
|
||||||
|
# use `error` to get the error from r
|
||||||
|
return
|
||||||
|
|
||||||
|
# use value
|
||||||
|
```
|
||||||
|
|
||||||
### Catching errors
|
### Catching errors
|
||||||
|
|
||||||
When you want to use Results, but need to call a proc that may raise an
|
When you want to use Results, but need to call a proc that may raise an
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import ./chaining
|
|||||||
import ./indexing
|
import ./indexing
|
||||||
import ./operators
|
import ./operators
|
||||||
import ./without
|
import ./without
|
||||||
|
import ./withoutresult
|
||||||
|
|
||||||
include ./errorban
|
include ./errorban
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ export binding
|
|||||||
export chaining
|
export chaining
|
||||||
export indexing
|
export indexing
|
||||||
export without
|
export without
|
||||||
|
export withoutresult
|
||||||
|
|
||||||
type ResultFailure* = object of CatchableError
|
type ResultFailure* = object of CatchableError
|
||||||
|
|
||||||
|
|||||||
22
questionable/withoutresult.nim
Normal file
22
questionable/withoutresult.nim
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import ./binding
|
||||||
|
import ./without
|
||||||
|
|
||||||
|
template without*(expression, errorname, body) =
|
||||||
|
## Used to place guards that ensure that a Result contains a value.
|
||||||
|
## Exposes error when Result does not contain a value.
|
||||||
|
|
||||||
|
var error: ref CatchableError
|
||||||
|
|
||||||
|
# override =? operator such that it stores the error if there is one
|
||||||
|
template `=?`(name, result): bool =
|
||||||
|
when result is Result:
|
||||||
|
if result.isFailure:
|
||||||
|
error = result.error
|
||||||
|
when result is Option:
|
||||||
|
if result.isNone:
|
||||||
|
error = newException(ValueError, "Option is set to `none`")
|
||||||
|
binding.`=?`(name, result)
|
||||||
|
|
||||||
|
without expression:
|
||||||
|
template errorname: ref CatchableError = error
|
||||||
|
body
|
||||||
@ -180,6 +180,69 @@ suite "result":
|
|||||||
test1()
|
test1()
|
||||||
test2()
|
test2()
|
||||||
|
|
||||||
|
test "without statement can expose error":
|
||||||
|
proc test =
|
||||||
|
without a =? int.failure "some error", error:
|
||||||
|
check error.msg == "some error"
|
||||||
|
return
|
||||||
|
fail
|
||||||
|
|
||||||
|
test()
|
||||||
|
|
||||||
|
test "without statement only exposes error variable inside block":
|
||||||
|
proc test =
|
||||||
|
without a =? 42.success, errorvar:
|
||||||
|
fail
|
||||||
|
discard errorvar # fixes warning about unused variable "errorvar"
|
||||||
|
return
|
||||||
|
check not compiles errorvar
|
||||||
|
|
||||||
|
test()
|
||||||
|
|
||||||
|
test "without statements with multiple bindings exposes first error":
|
||||||
|
proc test1 =
|
||||||
|
without (a =? int.failure "error 1") and
|
||||||
|
(b =? int.failure "error 2"),
|
||||||
|
error:
|
||||||
|
check error.msg == "error 1"
|
||||||
|
return
|
||||||
|
fail
|
||||||
|
|
||||||
|
proc test2 =
|
||||||
|
without (a =? 42.success) and (b =? int.failure "error 2"), error:
|
||||||
|
check error.msg == "error 2"
|
||||||
|
return
|
||||||
|
fail
|
||||||
|
|
||||||
|
test1()
|
||||||
|
test2()
|
||||||
|
|
||||||
|
test "without statement with error evaluates result only once":
|
||||||
|
proc test =
|
||||||
|
var count = 0
|
||||||
|
without a =? (inc count; int.failure "error"):
|
||||||
|
check count == 1
|
||||||
|
return
|
||||||
|
fail
|
||||||
|
|
||||||
|
test()
|
||||||
|
|
||||||
|
test "without statement with error handles options as well":
|
||||||
|
proc test1 =
|
||||||
|
without a =? int.none and b =? int.failure "error", error:
|
||||||
|
check error.msg == "Option is set to `none`"
|
||||||
|
return
|
||||||
|
fail
|
||||||
|
|
||||||
|
proc test2 =
|
||||||
|
without a =? 42.some and b =? int.failure "error", error:
|
||||||
|
check error.msg == "error"
|
||||||
|
return
|
||||||
|
fail
|
||||||
|
|
||||||
|
test1()
|
||||||
|
test2()
|
||||||
|
|
||||||
test "catch can be used to convert exceptions to results":
|
test "catch can be used to convert exceptions to results":
|
||||||
check parseInt("42").catch == 42.success
|
check parseInt("42").catch == 42.success
|
||||||
check parseInt("foo").catch.error of ValueError
|
check parseInt("foo").catch.error of ValueError
|
||||||
@ -286,6 +349,18 @@ suite "result":
|
|||||||
let converted = works().option
|
let converted = works().option
|
||||||
check (converted == @[1, 1, 2, 2, 2].some)
|
check (converted == @[1, 1, 2, 2, 2].some)
|
||||||
|
|
||||||
|
# Without statement
|
||||||
|
proc someProc(r: ?!int) =
|
||||||
|
without value =? r, error:
|
||||||
|
check error.msg == "some error"
|
||||||
|
return
|
||||||
|
|
||||||
|
check value == 42
|
||||||
|
|
||||||
|
someProc(42.success)
|
||||||
|
someProc(int.failure "some error")
|
||||||
|
|
||||||
|
|
||||||
import pkg/questionable/resultsbase
|
import pkg/questionable/resultsbase
|
||||||
|
|
||||||
suite "result compatibility":
|
suite "result compatibility":
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user