From 8f27c5e552a8e6641266ae86d57dcf3373f1d5b1 Mon Sep 17 00:00:00 2001 From: luxick Date: Thu, 2 Jul 2020 19:59:01 +0200 Subject: [PATCH] Add fail templates --- doc/op.html | 55 ++++++++++++++------- src/op.nim | 31 ++++++------ tests/tests.nim | 125 ++++++++++++++++++++++++++++-------------------- 3 files changed, 127 insertions(+), 84 deletions(-) diff --git a/doc/op.html b/doc/op.html index 689f4ee..4007e72 100644 --- a/doc/op.html +++ b/doc/op.html @@ -102,7 +102,7 @@ function main() { Types +
  • + Templates + +
  • @@ -142,7 +150,7 @@ function main() {

    Basic Usage

    proc divide(a, b: int): OP[float] =
       ## This could fail
       if b == 0:
    -    return fail(float, "Cannot divide by zero!")
    +    return fail "Cannot divide by zero!"
       else:
         return ok a / b   # Wrap the result
     
    @@ -153,7 +161,7 @@ function main() {
     

    Types

    -
    OP[T] = object of RootObj
    +
    OP[T] = object
       case isOk*: bool
       of true:
           val*: T
    @@ -164,7 +172,9 @@ function main() {
       
    -Object to wrap the result of an operation
    • isOk: Indicates if the operation was successful
    • +

      Object to wrap the result of an operation.

      +

      The type is discriminated by the isOK bool. So it is an compiler error to try to access the value without checking if the operation was successful.

      +
      • isOk: Indicates if the operation was successful
      • val: If successful, this will hold the real result value
      • error: Otherwise this will hold an error message
      @@ -177,14 +187,14 @@ Object to wrap the result of an operation
      • Procs
        -
        proc ok[T](val: T): OP[T]
        +
        proc ok[T](val: T): OP[T] {...}{.inline.}
        Wraps the given value in a successful operation result.
        -
        proc fail(op: OP; msg: string): OP
        +
        proc fail(op: OP; msg: string): OP {...}{.inline.}
        Will create a new operation result with the given error message. The type for the operation result is taken from the op argument. @@ -197,26 +207,35 @@ Will create a new operation result with the given error message. The type for th assert data.error == "Not implemented!"
    - -
    proc fail[T](msg: string): OP[T]
    + +
    proc fail(T: typedesc; msg: string): OP[T] {...}{.inline.}

    Will create a new operation result with the given error message. The type for the operation result is given explicitly.

    See Also:

    -

    Examples:

    -
    let res = fail[seq[float]] "Something is wrong!"
    -assert res.isOk == false
    -assert res.error == "Something is wrong!"
    - -
    proc fail(T: typedesc; msg: string): OP[T]
    + +
    +
    +

    Templates

    +
    + +
    template fail[T; ](O: type OP[T]; msg: string): O:type
    -Alias for fail[T](string) + + +
    + +
    template fail(msg: static[string]): auto
    +
    + +
    @@ -229,7 +248,7 @@ Alias for fail[T](string)
    diff --git a/src/op.nim b/src/op.nim index 67999a5..33c3135 100644 --- a/src/op.nim +++ b/src/op.nim @@ -17,7 +17,7 @@ ## proc divide(a, b: int): OP[float] = ## ## This could fail ## if b == 0: -## return fail(float, "Cannot divide by zero!") +## return fail "Cannot divide by zero!" ## else: ## return ok a / b # Wrap the result ## @@ -26,8 +26,12 @@ ## assert r.error == "Cannot divide by zero!" type - OP*[T] = object of RootObj - ## Object to wrap the result of an operation + OP*[T] = object + ## Object to wrap the result of an operation. + ## + ## The type is discriminated by the `isOK` bool. + ## So it is an compiler error to try to access the value without checking + ## if the operation was successful. ## ## - `isOk`: Indicates if the operation was successful ## - `val`: If successful, this will hold the real result value @@ -38,11 +42,11 @@ type of false: error*: string -proc ok*[T](val: T): OP[T] = +proc ok*[T](val: T): OP[T] {.inline.} = ## Wraps the given value in a successful operation result. OP[T](isOK: true, val: val) -proc fail*(op: OP, msg: string): OP = +proc fail*(op: OP, msg: string): OP {.inline.} = ## Will create a new operation result with the given error message. ## The type for the operation result is taken from the `op` argument. runnableExamples: @@ -54,20 +58,17 @@ proc fail*(op: OP, msg: string): OP = assert data.error == "Not implemented!" OP(isOK: false, error: msg) -proc fail*[T](msg: string): OP[T] = +proc fail*(T: typedesc, msg: string): OP[T] {.inline.} = ## Will create a new operation result with the given error message. ## The type for the operation result is given explicitly. ## ## **See Also:** - ## - `fail proc - ## <#fail,OP,string>`_ - runnableExamples: - let res = fail[seq[float]] "Something is wrong!" - assert res.isOk == false - assert res.error == "Something is wrong!" + ## - `fail proc<#fail,OP,string>`_ + ## - `fail template<#fail.t,static[string]>`_ OP[T](isOK: false, error: msg) -proc fail*(T: typedesc, msg: string): OP[T] = - ## Alias for `fail[T](string)<#fail,string>`_ - fail[T] msg +template fail*[T](O: type OP[T], msg: string): O = O(isOK: false, error: msg) + +template fail*(msg: static[string]): auto = fail(typeof(result), msg) + diff --git a/tests/tests.nim b/tests/tests.nim index faacbf6..0b031e2 100644 --- a/tests/tests.nim +++ b/tests/tests.nim @@ -3,66 +3,89 @@ import unittest import op -test "Check OK": - let test = ok 1 - check test.isOk == true +suite "Basic tests": + test "Check OK": + let test = ok 1 + check test.isOk == true -test "Check fail": - let test = op.fail[int] "no data here" - check test.isOk == false + test "Check fail": + let test = fail(void, "no data here") + check test.isOk == false -test "Check proc results": - proc createValue: OP[string] = - let myString = "This is test code!" - ok myString - let data = createValue() - check data.isOk - check data.val == "This is test code!" + test "Check proc results": + proc createValue: OP[string] = + let myString = "This is test code!" + ok myString + let data = createValue() + check data.isOk + check data.val == "This is test code!" -test "Check failing result proc": - proc someProc(): OP[int] = - result.fail "Not implemented!" + test "Check failing result proc": + proc someProc(): OP[int] = + result.fail "Not implemented!" - let data = someProc() - assert data.isOk == false - assert data.error == "Not implemented!" + let data = someProc() + assert data.isOk == false + assert data.error == "Not implemented!" -test "Check failing typedesc proc ": - proc someProc(): OP[int] = - fail(int, "Not implemented!") + test "Check failing typedesc proc ": + proc someProc(): OP[int] = + op.fail(int, "Not implemented!") - let data = someProc() - assert data.isOk == false - assert data.error == "Not implemented!" + let data = someProc() + assert data.isOk == false + assert data.error == "Not implemented!" -test "Check failing type param proc ": - proc someProc(): OP[int] = - op.fail[int]("Not implemented!") + test "Check failing type param proc ": + proc someProc(): OP[int] = + fail(int, "Not implemented!") - let data = someProc() - assert data.isOk == false - assert data.error == "Not implemented!" + let data = someProc() + assert data.isOk == false + assert data.error == "Not implemented!" -test "Check changing result": - proc checker(): OP[int] = - result = ok 42 - # something happend here - result = result.fail "data got corrupted" + test "Check changing result": + proc checker(): OP[int] = + result = ok 42 + # something happend here + result = result.fail "data got corrupted" - let data = checker() - check data.isOk == false - check data.error == "data got corrupted" + let data = checker() + check data.isOk == false + check data.error == "data got corrupted" -test "Check divider proc": - proc divide(a, b: int): OP[float] = - if b == 0: - return fail(float, "Cannot divide by zero!") - else: - return ok a / b + test "Check divider proc": + proc divide(a, b: int): OP[float] = + if b == 0: + return fail(float, "Cannot divide by zero!") + else: + return ok a / b - let - a = 42 - b = 0 - let r = divide(a, b) - check r.isOk == false - check r.error == "Cannot divide by zero!" \ No newline at end of file + let + a = 42 + b = 0 + let r = divide(a, b) + check r.isOk == false + check r.error == "Cannot divide by zero!" + + test "Check implicit fail type": + proc divide(a, b: int): OP[float] = + if b == 0: + return fail "Cannot divide by zero!" + else: + return ok a / b + + let r = divide(1, 0) + check r.isOk == false + check r.error == "Cannot divide by zero!" + + test "Check type of impolicit fail": + proc divide(a, b: int): OP[float] = + if b == 0: + return fail "Cannot divide by zero!" + else: + return ok a / b + + let r = divide(1, 0) + check r.isOk == false + check r.error == "Cannot divide by zero!"