summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/docgen.nim24
-rw-r--r--lib/pure/uri.nim4
-rw-r--r--lib/system.nim10
-rw-r--r--tests/magics/trunnableexamples.nim60
4 files changed, 81 insertions, 17 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 2e03c0d4d..28cbcbd8d 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -415,12 +415,6 @@ proc runAllExamples(d: PDoc) =
     rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
     removeFile(outp.changeFileExt(ExeExt))
 
-proc extractImports(n: PNode; result: PNode) =
-  if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
-    result.add copyTree(n)
-    n.kind = nkEmpty
-    return
-  for i in 0..<n.safeLen: extractImports(n[i], result)
 
 proc prepareExamples(d: PDoc; n: PNode) =
   var docComment = newTree(nkCommentStmt)
@@ -430,12 +424,20 @@ proc prepareExamples(d: PDoc; n: PNode) =
       docComment,
       newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
   runnableExamples.info = n.info
-  let imports = newTree(nkStmtList)
-  var savedLastSon = copyTree n.lastSon
-  extractImports(savedLastSon, imports)
-  for imp in imports: runnableExamples.add imp
-  runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
+  for a in n.lastSon: runnableExamples.add a
   testExample(d, runnableExamples)
+  when false:
+    proc extractImports(n: PNode; result: PNode) =
+      if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}:
+        result.add copyTree(n)
+        n.kind = nkEmpty
+        return
+      for i in 0..<n.safeLen: extractImports(n[i], result)
+    let imports = newTree(nkStmtList)
+    var savedLastSon = copyTree n.lastSon
+    extractImports(savedLastSon, imports)
+    for imp in imports: runnableExamples.add imp
+    runnableExamples.add newTree(nkBlockStmt, newNode(nkEmpty), copyTree savedLastSon)
 
 proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
   if n.info.fileIndex != orig.info.fileIndex: return
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index c0c78d735..088786f25 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -198,8 +198,8 @@ proc initUri*(): Uri =
   ## **See also:**
   ## * `Uri type <#Uri>`_ for available fields in the URI type
   runnableExamples:
-    var uri: Uri
-    assert initUri() == uri
+    var uri2: Uri
+    assert initUri() == uri2
   result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
                 path: "", query: "", anchor: "")
 
diff --git a/lib/system.nim b/lib/system.nim
index a588a85b9..28eb1a1ef 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -128,7 +128,7 @@ when defined(nimHasRunnableExamples):
     ##   a ``runnableExamples`` section is ignored.
     ## - The documentation generator is aware of these examples and considers them
     ##   part of the ``##`` doc comment. As the last step of documentation
-    ##   generation the examples are put into an ``$file_example.nim`` file,
+    ##   generation each runnableExample is put in its own file ``$file_examples$i.nim``,
     ##   compiled and tested. The collected examples are
     ##   put into their own module to ensure the examples do not refer to
     ##   non-exported symbols.
@@ -136,12 +136,14 @@ when defined(nimHasRunnableExamples):
     ## Usage:
     ##
     ## .. code-block:: Nim
-    ##   proc double(x: int): int =
+    ##   proc double*(x: int): int =
     ##     ## This proc doubles a number.
     ##     runnableExamples:
+    ##       ## at module scope
     ##       assert double(5) == 10
-    ##       assert double(21) == 42
-    ##
+    ##       block: ## at block scope
+    ##         defer: echo "done"
+    ##   
     ##     result = 2 * x
 else:
   template runnableExamples*(body: untyped) =
diff --git a/tests/magics/trunnableexamples.nim b/tests/magics/trunnableexamples.nim
new file mode 100644
index 000000000..e6b2b70f8
--- /dev/null
+++ b/tests/magics/trunnableexamples.nim
@@ -0,0 +1,60 @@
+discard """
+cmd: "nim doc $file"
+action: "compile"
+nimout: '''
+foo1
+foo2
+foo3
+foo5
+foo6
+foo7
+foo8
+foo9
+'''
+joinable: false
+"""
+
+proc fun*() =
+  runnableExamples:
+    block: # `defer` only allowed inside a block
+      defer: echo "foo1"
+
+  runnableExamples:
+    # `fun*` only allowed at top level
+    proc fun*()=echo "foo2"
+    fun()
+    block:
+      defer: echo "foo3"
+
+  runnableExamples:
+    # ditto
+    proc fun*()=echo "foo5"
+    fun()
+
+  runnableExamples:
+    # `codeReordering` only allowed at top level
+    {.experimental: "codeReordering".}
+    proc fun1() = fun2()
+    proc fun2() = echo "foo6"
+    fun1()
+
+  runnableExamples:
+    # only works at top level
+    import std/macros
+    macro myImport(a: static string): untyped =
+      newTree(nnkImportStmt, [newLit a])
+    myImport "str" & "utils"
+    doAssert declared(isAlphaAscii)
+    echo "foo7"
+
+# also check for runnableExamples at module scope
+runnableExamples:
+  block:
+    defer: echo "foo8"
+
+runnableExamples:
+  proc fun*()=echo "foo9"
+  fun()
+
+# note: there are yet other examples where putting runnableExamples at module
+# scope is needed, for example when using an `include` before an `import`, etc.