Skip to content

Commit

Permalink
run runnableExamples in the module scope (#11732) [feature]
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour authored and Araq committed Jul 22, 2019
1 parent 30f2cec commit 8c93c69
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 17 deletions.
24 changes: 13 additions & 11 deletions compiler/docgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/pure/uri.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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: "")

Expand Down
10 changes: 6 additions & 4 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -128,20 +128,22 @@ 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.
##
## 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) =
Expand Down
60 changes: 60 additions & 0 deletions tests/magics/trunnableexamples.nim
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit 8c93c69

Please sign in to comment.