From c9f6903da83136730f67ccb5e01af1616062f15e Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 23 May 2025 03:33:25 -0400 Subject: [PATCH] Revise jldoctest best practices --- doc/make.jl | 1 + doc/src/devdocs/jldoctests.md | 85 +++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 doc/src/devdocs/jldoctests.md diff --git a/doc/make.jl b/doc/make.jl index b8e908a42c3ea..9d547187ad594 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -217,6 +217,7 @@ DevDocs = [ "devdocs/functions.md", "devdocs/cartesian.md", "devdocs/meta.md", + "devdocs/jldoctests.md", "devdocs/subarrays.md", "devdocs/isbitsunionarrays.md", "devdocs/sysimg.md", diff --git a/doc/src/devdocs/jldoctests.md b/doc/src/devdocs/jldoctests.md new file mode 100644 index 0000000000000..07f2ec4c75f81 --- /dev/null +++ b/doc/src/devdocs/jldoctests.md @@ -0,0 +1,85 @@ +# Best practices for jldoctests +This page describes how to write and maintain `jldoctest` blocks in the documentation. Following these guidelines helps keep doctests reliable and easy to read. + + +## Filters + +Use `filter =` whenever output contains text that might vary across runs. +The documentation relies on several recurring patterns: + +- `r"int.jl:\\d+"` — remove line numbers from introspection macros. +- `r"Stacktrace:(\\n \\[0-9]+\\].*)*"` — hide stack traces when illustrating + errors. +- `r"Closest candidates.*\\n .*"` — skip the method suggestions printed by + `MethodError`. +- `r"@ .*"` — strip file locations from the output of `methods` or + `@which`. +- `r"\\@world\\(MyStruct, \\d+:\\d+\\)"` — filter world age numbers. +- `r"with \\d+ methods"` — ignore method counts when redefining functions. +- `r"[0-9\\.]+ seconds \\(.*?\\)"` — remove timing output with memory + information. +- `r"[0-9\\.]+ seconds"` — remove simple timing results. +- `r"[0-9\\.]+"` — filter digits from names such as anonymous functions. +- `r"([A-B] [0-5])"` and `r"[A-B] [X-Z] [0-5]"` — account for non-deterministic + process output. +- `r"(world\\nhello|hello\\nworld)"` — allow either ordering of interleaved + output. + +If none of these match your situation, craft a regular expression that +removes the varying text. Using filters keeps doctests stable across +platforms and Julia versions. + +## Setup code + +Small setup expressions may be placed inline using the `setup =` option: + +```` +```jldoctest; setup = :(using InteractiveUtils) +... +``` +```` + +For longer setup code or if multiple blocks require the same environment, use the +`DocTestSetup` meta block: + +```` +```@meta +DocTestSetup = :(import Random; Random.seed!(1234)) +``` +```` + +and disable it afterwards with + +```` +```@meta +DocTestSetup = nothing +``` +```` + +## Maintaining state between snippets + +Related doctest blocks can share state by giving them the same label after the +`jldoctest` keyword. The manual uses this pattern to demonstrate mutation: + +```` +```jldoctest mutation_vs_rebind +julia> a = [1,2,3] +... +``` +```` + +and later + +```` +```jldoctest mutation_vs_rebind +julia> a[1] = 42 +... +``` +```` + +Blocks with the same name execute sequentially during doctesting, so variables +created in the first block remain available in the following ones. + +When a snippet needs to preserve its result for later examples, give it a label +and reuse that label. This avoids repeating setup code and mirrors a REPL +session more closely.