|
| 1 | +# Best practices for jldoctests |
| 2 | +This page describes how to write and maintain `jldoctest` blocks in the documentation. Following these guidelines helps keep doctests reliable and easy to read. |
| 3 | + |
| 4 | + |
| 5 | +## Filters |
| 6 | + |
| 7 | +Use `filter =` whenever output contains text that might vary across runs. |
| 8 | +The documentation relies on several recurring patterns: |
| 9 | + |
| 10 | +- `r"int.jl:\\d+"` — remove line numbers from introspection macros. |
| 11 | +- `r"Stacktrace:(\\n \\[0-9]+\\].*)*"` — hide stack traces when illustrating |
| 12 | + errors. |
| 13 | +- `r"Closest candidates.*\\n .*"` — skip the method suggestions printed by |
| 14 | + `MethodError`. |
| 15 | +- `r"@ .*"` — strip file locations from the output of `methods` or |
| 16 | + `@which`. |
| 17 | +- `r"\\@world\\(MyStruct, \\d+:\\d+\\)"` — filter world age numbers. |
| 18 | +- `r"with \\d+ methods"` — ignore method counts when redefining functions. |
| 19 | +- `r"[0-9\\.]+ seconds \\(.*?\\)"` — remove timing output with memory |
| 20 | + information. |
| 21 | +- `r"[0-9\\.]+ seconds"` — remove simple timing results. |
| 22 | +- `r"[0-9\\.]+"` — filter digits from names such as anonymous functions. |
| 23 | +- `r"([A-B] [0-5])"` and `r"[A-B] [X-Z] [0-5]"` — account for non-deterministic |
| 24 | + process output. |
| 25 | +- `r"(world\\nhello|hello\\nworld)"` — allow either ordering of interleaved |
| 26 | + output. |
| 27 | + |
| 28 | +If none of these match your situation, craft a regular expression that |
| 29 | +removes the varying text. Using filters keeps doctests stable across |
| 30 | +platforms and Julia versions. |
| 31 | + |
| 32 | +## Setup code |
| 33 | + |
| 34 | +Small setup expressions may be placed inline using the `setup =` option: |
| 35 | + |
| 36 | +```` |
| 37 | +```jldoctest; setup = :(using InteractiveUtils) |
| 38 | +... |
| 39 | +``` |
| 40 | +```` |
| 41 | + |
| 42 | +For longer setup code or if multiple blocks require the same environment, use the |
| 43 | +`DocTestSetup` meta block: |
| 44 | + |
| 45 | +```` |
| 46 | +```@meta |
| 47 | +DocTestSetup = :(import Random; Random.seed!(1234)) |
| 48 | +``` |
| 49 | +```` |
| 50 | + |
| 51 | +and disable it afterwards with |
| 52 | + |
| 53 | +```` |
| 54 | +```@meta |
| 55 | +DocTestSetup = nothing |
| 56 | +``` |
| 57 | +```` |
| 58 | + |
| 59 | +## Maintaining state between snippets |
| 60 | + |
| 61 | +Related doctest blocks can share state by giving them the same label after the |
| 62 | +`jldoctest` keyword. The manual uses this pattern to demonstrate mutation: |
| 63 | + |
| 64 | +```` |
| 65 | +```jldoctest mutation_vs_rebind |
| 66 | +julia> a = [1,2,3] |
| 67 | +... |
| 68 | +``` |
| 69 | +```` |
| 70 | + |
| 71 | +and later |
| 72 | + |
| 73 | +```` |
| 74 | +```jldoctest mutation_vs_rebind |
| 75 | +julia> a[1] = 42 |
| 76 | +... |
| 77 | +``` |
| 78 | +```` |
| 79 | + |
| 80 | +Blocks with the same name execute sequentially during doctesting, so variables |
| 81 | +created in the first block remain available in the following ones. |
| 82 | + |
| 83 | +When a snippet needs to preserve its result for later examples, give it a label |
| 84 | +and reuse that label. This avoids repeating setup code and mirrors a REPL |
| 85 | +session more closely. |
0 commit comments