Generating Documentation
Under the hood of documenter.jl
Morten Piibeleht
@mortenpi
"""
Base.runtests(tests=["all"]; ncores=ceil(Int, Sys.CPU_THREADS / 2),
exit_on_error=false, [seed])
Run the Julia unit tests listed in `tests`, which can be either a string or an array of
strings, using `ncores` processors. If `exit_on_error` is `false`, when one test
fails, all remaining tests in other files will still be run; they are otherwise discarded,
when `exit_on_error == true`.
If a seed is provided via the keyword argument, it is used to seed the
global RNG in the context where the tests are run; otherwise the seed is chosen randomly.
"""
function runtests(tests = ["all"]; ncores = ceil(Int, Sys.CPU_THREADS / 2),
exit_on_error=false,
seed::Union{BitInteger,Nothing}=nothing)
if isa(tests,AbstractString)
tests = split(tests)
end
exit_on_error && push!(tests, "--exit-on-error")
seed !== nothing && push!(tests, "--seed=0x$(string(seed % UInt128, base=16))") # cast to UInt128 to avoid a minus sign
ENV2 = copy(ENV)
ENV2["JULIA_CPU_THREADS"] = "$ncores"
try
run(setenv(`$(julia_cmd()) $(joinpath(Sys.BINDIR::String,
Base.DATAROOTDIR, "julia", "test", "runtests.jl")) $tests`, ENV2))
catch
buf = PipeBuffer()
Base.require(Base, :InteractiveUtils).versioninfo(buf)
error("A test has failed. Please submit a bug report (https://github.com/JuliaLang/julia/issues)\n" *
"including error messages above and the output of versioninfo():\n$(read(buf, String))")
end
end
Inline docstrings in .JL files
help?> Base.runtests
Base.runtests(tests=["all"]; ncores=ceil(Int, Sys.CPU_THREADS / 2),
exit_on_error=false, [seed])
Run the Julia unit tests listed in tests, which can be either a string or an array of strings, using ncores
processors. If exit_on_error is false, when one test fails, all remaining tests in other files will still be
run; they are otherwise discarded, when exit_on_error == true. If a seed is provided via the keyword argument,
it is used to seed the global RNG in the context where the tests are run; otherwise the seed is chosen randomly.
# Unit Testing
```@meta
DocTestSetup = :(using Test)
```
## Testing Base Julia
Julia is under rapid development and has an extensive test suite to verify functionality across
multiple platforms. If you build Julia from source, you can run this test suite with `make test`.
In a binary install, you can run the test suite using `Base.runtests()`.
```@docs
Base.runtests
```
## Basic Unit Tests
The `Test` module provides simple *unit testing* functionality. Unit testing is a way to
see if your code is correct by checking that the results are what you expect. It can be helpful
to ensure your code still works after you make changes, and can be used when developing as a way
of specifying the behaviors your code should have when complete.
Simple unit testing can be performed with the `@test` and `@test_throws` macros:
```@docs
Test.@test
Test.@test_throws
```
For example, suppose we want to check our new function `foo(x)` works as expected:
```jldoctest testfoo
julia> using Test
julia> foo(x) = length(x)^2
foo (generic function with 1 method)
```
If the condition is true, a `Pass` is returned:
```jldoctest testfoo
julia> @test foo("bar") == 9
Test Passed
julia> @test foo("fizz") >= 10
Test Passed
```
If the condition is false, then a `Fail` is returned and an exception is thrown:
```jldoctest testfoo
julia> @test foo("f") == 20
Test Failed at none:1
Expression: foo("f") == 20
Evaluated: 1 == 20
ERROR: There was an error during testing
```
Markdown pages
Build pipelines
Build pipelines
Basic setup
# make.jl
using Documenter, Example
makedocs(
sitename = "Example.jl",
modules = [Example],
pages = Any[
"Home" => "index.md",
"Showcase" => "showcase.md",
],
)
Example/
├── .travis.yml
├── Project.toml
├── README.md
├── LICENSE.md
├── src
│ ├── Example.jl
│ └── utilities.jl
└── test
└── runtests.jl
Example/
├── .travis.yml
├── Project.toml
├── README.md
├── LICENSE.md
├── src
│ ├── Example.jl
│ └── utilities.jl
├── test
│ └── runtests.jl
└── docs
Example/
├── .travis.yml
├── Project.toml
├── README.md
├── LICENSE.md
├── src
│ ├── Example.jl
│ └── utilities.jl
├── test
│ └── runtests.jl
└── docs
├── Project.toml
├── src
│ ├── assets
│ │ ├── favicon.ico
│ │ └── logo.svg
│ ├── index.md
│ └── showcase.md
└── make.jl
Example/
├── .travis.yml
├── Project.toml
├── README.md
├── LICENSE.md
├── src
│ ├── Example.jl
│ └── utilities.jl
├── test
│ └── runtests.jl
└── docs
├── Project.toml
├── src
│ ├── assets
│ │ ├── favicon.ico
│ │ └── logo.svg
│ ├── index.md
│ └── showcase.md
├── make.jl
└── build
Example/
├── .travis.yml
├── Project.toml
├── README.md
├── LICENSE.md
├── src
│ ├── Example.jl
│ └── utilities.jl
├── test
│ └── runtests.jl
└── docs
├── Project.toml
├── src
│ ├── assets
│ │ ├── favicon.ico
│ │ └── logo.svg
│ ├── index.md
│ └── showcase.md
├── make.jl
└── build
├── assets
│ ├── favicon.ico
│ ├── logo.svg
│ ├── documenter.js
│ ├── search.js
│ └── documenter.css
├── index.html
├── showcase
│ └── index.html
├── search_index.js
└── search
└── index.html
$ julia --project=docs/ docs/make.jl
[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: ExpandTemplates: expanding markdown templates.
[ Info: CrossReferences: building cross-references.
[ Info: CheckDocument: running document checks.
[ Info: Populate: populating indices.
[ Info: RenderDocument: rendering document.
[ Info: HTMLWriter: rendering HTML pages.
REPL WORKFLOW
pkg> activate docs/
julia> using Revise
julia> include("docs/make.jl")
[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: ExpandTemplates: expanding markdown templates.
[ Info: CrossReferences: building cross-references.
[ Info: CheckDocument: running document checks.
[ Info: Populate: populating indices.
[ Info: RenderDocument: rendering document.
[ Info: HTMLWriter: rendering HTML pages.
Travis: Basic setup
using Documenter, DocStringExtensions
makedocs(
sitename = "DocStringExtensions.jl",
modules = [DocStringExtensions],
pages = Any[
"Home" => "index.md",
"Showcase" => "showcase.md",
],
)
deploydocs(
repo = "github.com/JuliaDocs/DocStringExtensions.jl.git",
)
DocStringExtensions/
├── .travis.yml
├── Project.toml
├── README.md
├── LICENSE.md
├── src
│ ├── abbreviations.jl
│ ├── DocStringExtensions.jl
│ ├── templates.jl
│ └── utilities.jl
└── test
├── coverage.jl
└── runtests.jl
DocStringExtensions/
├── .travis.yml
├── Project.toml
├── README.md
├── LICENSE.md
├── src
│ ├── abbreviations.jl
│ ├── DocStringExtensions.jl
│ ├── templates.jl
│ └── utilities.jl
├── test
│ ├── coverage.jl
│ └── runtests.jl
└── docs
├── build
├── make.jl
├── Project.toml
└── src
├── assets
│ ├── favicon.ico
│ └── logo.svg
├── index.md
└── showcase.md
Travis
jobs:
include:
- stage: "Documentation"
julia: 1.0
os: linux
script:
- julia --project=docs/ -e'
using Pkg; Pkg.instantiate();
Pkg.develop(PackageSpec(path=pwd()))'
- julia --project=docs/ docs/make.jl
after_success: skip
Splicing docstrings
## Public Interface
```@docs
Documenter
makedocs
hide
deploydocs
Deps
Deps.pip
doctest
DocMeta
DocMeta.getdocmeta
DocMeta.setdocmeta!
```
Explicit declaration
```@docs
foo
foo()
foo(::Int, ::AbstractString)
```
Type signatures
Docstrings
julia> using LinearAlgebra
julia> Docs.meta(LinearAlgebra)
IdDict{Any,Any} with 139 entries:
Base.Math.acot => MultiDoc(Type[Union{Tuple{AbstractArray{T,2}}, Tu…
LinearAlgebra.normalize => MultiDoc(Type[Union{Tuple{AbstractArray{T,1} wher…
LinearAlgebra.lowrankdowndate! => MultiDoc(Type[Tuple{Cholesky,Union{DenseArray{T,1…
Base.copy => MultiDoc(Type[Tuple{Union{Adjoint, Transpose}}], …
LinearAlgebra.QRPivoted => MultiDoc(Type[Union{}], IdDict{Any,Any}(Union{}=>…
LinearAlgebra.logdet => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}],…
LinearAlgebra.ldlt! => MultiDoc(Type[Union{Tuple{SymTridiagonal{T,V}}, T…
Base.:* => MultiDoc(Type[Tuple{AbstractArray{T,2} where T,Ab…
LinearAlgebra.eigvecs => MultiDoc(Type[Tuple{SymTridiagonal{#s621,V} where…
Base.exp => MultiDoc(Type[Tuple{Union{DenseArray{#s622,2}, Re…
LinearAlgebra.triu => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}, …
LinearAlgebra.ldlt => MultiDoc(Type[Union{Tuple{SymTridiagonal{T,V} whe…
LinearAlgebra.rank => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}],…
LinearAlgebra.lowrankdowndate => MultiDoc(Type[Tuple{Cholesky,Union{DenseArray{T,1…
Base.copyto! => MultiDoc(Type[Tuple{AbstractArray{T,2} where T,Un…
Base.sin => MultiDoc(Type[Tuple{AbstractArray{#s622,2} where …
LinearAlgebra.Hermitian => MultiDoc(Type[Union{Tuple{AbstractArray{T,2} wher…
LinearAlgebra.triu! => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}, …
Base.Math.sincos => MultiDoc(Type[Tuple{AbstractArray{#s620,2} where …
LinearAlgebra.LinearAlgebra => MultiDoc(Type[Union{}], IdDict{Any,Any}(Union{}=>…
Base.Math.sec => MultiDoc(Type[Union{Tuple{AbstractArray{T,2}}, Tu…
Base.cosh => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}],…
LinearAlgebra.opnorm => MultiDoc(Type[Union{Tuple{AbstractArray{T,2} wher…
LinearAlgebra.eigmin => MultiDoc(Type[Tuple{Union{Number, AbstractArray{T…
LinearAlgebra.cond => MultiDoc(Type[Union{Tuple{AbstractArray{T,2} wher…
LinearAlgebra.isposdef! => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}],…
LinearAlgebra.lowrankupdate! => MultiDoc(Type[Tuple{Cholesky,Union{DenseArray{T,1…
LinearAlgebra.svdvals => MultiDoc(Type[Union{Tuple{AbstractArray{T,2}}, Tu…
LinearAlgebra.nullspace => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}],…
LinearAlgebra.logabsdet => MultiDoc(Type[Tuple{AbstractArray{T,2} where T}],…
Base.Math.acoth => MultiDoc(Type[Union{Tuple{AbstractArray{T,2}}, Tu…
⋮ => ⋮
- Handled by Base.Docs module
- Each module has a metadata dictionary
-
Access: Docs.meta(::Module)
-
Docs.Binding => Docs.MultiDoc
-
-
Docs.Binding: (:: Module, :: Symbol) pair
- e.g. for eigen Docs.Binding(LinearAlgebra, :eigen)
-
Docs.MultiDoc
-
A dictionary of docstrings
-
Keys: type signatures
-
Docstrings
module Foo
"function bar"
function bar end
"bar()"
bar() = 1
"bar(int, string)"
bar(x::Int, s::AbstractString) = 1
end
julia> m = Docs.meta(Foo)
IdDict{Any,Any} with 1 entry:
Foo.bar => MultiDoc(Type[Union{}, Tuple{}, Tuple{Int64,AbstractString}], IdDict{Any,Any}(Union{}=>DocStr(svec(…
julia> m = Docs.meta(Foo)
IdDict{Any,Any} with 1 entry:
Foo.bar => MultiDoc(Type[Union{}, Tuple{}, Tuple{Int64,AbstractString}], IdDict{Any,Any}(Union{}=>DocStr(svec(…
julia> multidoc = m[Docs.Binding(Foo, :bar)];
julia> m = Docs.meta(Foo)
IdDict{Any,Any} with 1 entry:
Foo.bar => MultiDoc(Type[Union{}, Tuple{}, Tuple{Int64,AbstractString}], IdDict{Any,Any}(Union{}=>DocStr(svec(…
julia> multidoc = m[Docs.Binding(Foo, :bar)];
julia> multidoc.docs
IdDict{Any,Any} with 3 entries:
Union{} => DocStr(svec("function bar"), function bar…
Tuple{} => DocStr(svec("bar()"), bar()…
Tuple{Int64,AbstractString} => DocStr(svec("bar(int, string)"), bar(int, string)…
julia> m = Docs.meta(Foo)
IdDict{Any,Any} with 1 entry:
Foo.bar => MultiDoc(Type[Union{}, Tuple{}, Tuple{Int64,AbstractString}], IdDict{Any,Any}(Union{}=>DocStr(svec(…
julia> multidoc = m[Docs.Binding(Foo, :bar)];
julia> multidoc.docs
IdDict{Any,Any} with 3 entries:
Union{} => DocStr(svec("function bar"), function bar…
Tuple{} => DocStr(svec("bar()"), bar()…
Tuple{Int64,AbstractString} => DocStr(svec("bar(int, string)"), bar(int, string)…
julia> multidoc.docs[Tuple{Int,AbstractString}]
Base.Docs.DocStr(svec("bar(int, string)"), ...)
julia> m = Docs.meta(Foo)
IdDict{Any,Any} with 1 entry:
Foo.bar => MultiDoc(Type[Union{}, Tuple{}, Tuple{Int64,AbstractString}], IdDict{Any,Any}(Union{}=>DocStr(svec(…
julia> multidoc = m[Docs.Binding(Foo, :bar)];
julia> multidoc.docs
IdDict{Any,Any} with 3 entries:
Union{} => DocStr(svec("function bar"), function bar…
Tuple{} => DocStr(svec("bar()"), bar()…
Tuple{Int64,AbstractString} => DocStr(svec("bar(int, string)"), bar(int, string)…
julia> multidoc.docs[Tuple{Int,AbstractString}]
Base.Docs.DocStr(svec("bar(int, string)"), ...)
julia> multidoc.docs[Union{}]
Base.Docs.DocStr(svec("function bar"), ...)
# Methods
```@docs
Foo.bar
Foo.bar()
Foo.bar(::Int, ::AbstractString)
```
Julia source
Documentation
Splicing docstrings
# Documents
```@autodocs
Modules = [Documenter.Documents]
```
Automatic inclusion:
- @autodocs block
- Supports the following filters
- Modules: by module
- Pages: by .jl filename
- Public/Private: (un)exported names
- Filter: arbitrary user function
doctesting
[text encodings](https://en.wikipedia.org/wiki/Character_encoding).) Here is how `Char` values are
input and shown:
```
julia> 'x'
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
julia> typeof(ans)
Char
```
You can easily convert a `Char` to its integer value, i.e. code point:
```
julia> Int('x')
120
julia> typeof(ans)
Int64
```
On 32-bit architectures, [`typeof(ans)`](@ref) will be [`Int32`](@ref). You can convert an
integer value back to a `Char` just as easily:
```
julia> Char(120)
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
```
[text encodings](https://en.wikipedia.org/wiki/Character_encoding).) Here is how `Char` values are
input and shown:
```jldoctest
julia> 'x'
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
julia> typeof(ans)
Char
```
You can easily convert a `Char` to its integer value, i.e. code point:
```jldoctest
julia> Int('x')
120
julia> typeof(ans)
Int64
```
On 32-bit architectures, [`typeof(ans)`](@ref) will be [`Int32`](@ref). You can convert an
integer value back to a `Char` just as easily:
```jldoctest
julia> Char(120)
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
```
doctesting
module Foo
"""
hello(who::String)
Return "Hello, `who`".
```jldoctest
julia> hello("Stranger")
"Hi, Stranger"
```
"""
hello(who::String) = "Hello, $who"
end
julia> using Foo, Documenter
julia> doctest(Foo)
using Test, Documenter, Example
@testset "Example" begin
... # other tests & testsets
doctest(Example)
... # other tests & testsets
end
Test suite integration:
AVAILABLE NOW
in a registry near you!
julia> using Foo, Documenter
julia> doctest(Foo)
[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
┌ Error: doctest failure in ~/Julia/JuliaDocs/Example/src/Example.jl:9-12
│
│ ```jldoctest; setup = :(using Example)
│ julia> hello("Stranger")
│ Hi, Stranger
│ ```
│
│ Subexpression:
│
│ hello("Stranger")
│
│ Evaluated output:
│
│ "Hello, Stranger"
│
│ Expected output:
│
│ Hi, Stranger
│
│ diff = Hi, Stranger"Hello, Stranger"
└ @ Documenter.DocTests ~/Julia/JuliaDocs/Documenter/src/DocTests.jl:356
┌ Error: Doctesting failed
└ @ Documenter ~/Julia/JuliaDocs/Documenter/src/Documenter.jl:911
`makedocs` encountered a doctest error. Terminating build
Stacktrace:
[...]
Test Summary: | Fail Total
Doctests: Example | 1 1
ERROR: Some tests did not pass: 0 passed, 1 failed, 0 errored, 0 broken.
doctesting: outdated doctests
julia> doctest(Example, fix=true)
julia> doctest(Example, fix=true)
[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: Skipped ExpandTemplates step (doctest only).
[ Info: Skipped CrossReferences step (doctest only).
[ Info: Skipped CheckDocument step (doctest only).
[ Info: Skipped Populate step (doctest only).
[ Info: Skipped RenderDocument step (doctest only).
Test Summary: | Pass Total
Doctests: Example | 1 1
Test.DefaultTestSet("Doctests: Example", Any[], 1, false)
julia> doctest(Example, fix=true)
[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: Skipped ExpandTemplates step (doctest only).
[ Info: Skipped CrossReferences step (doctest only).
[ Info: Skipped CheckDocument step (doctest only).
[ Info: Skipped Populate step (doctest only).
[ Info: Skipped RenderDocument step (doctest only).
Test Summary: | Pass Total
Doctests: Example | 1 1
Test.DefaultTestSet("Doctests: Example", Any[], 1, false)
julia> doctest(Example)
[ Info: SetupBuildDirectory: setting up build directory.
[ Info: Doctest: running doctests.
[ Info: Skipped ExpandTemplates step (doctest only).
[ Info: Skipped CrossReferences step (doctest only).
[ Info: Skipped CheckDocument step (doctest only).
[ Info: Skipped Populate step (doctest only).
[ Info: Skipped RenderDocument step (doctest only).
Test Summary: | Pass Total
Doctests: Example | 1 1
Test.DefaultTestSet("Doctests: Example", Any[], 1, false)
Code evaluation
# Code Evaluation: `@example`
```@example
A = rand(ComplexF64, 10, 15)
real.(A)
```
Code evaluation
# Code Evaluation: `@repl`
```@repl
using LinearAlgebra
A = rand(3, 3)
A^2
norm(ans)
```
Code evaluation
# Plotting
```@example
using Luxor
d = Drawing(600, 400)
origin()
fontsize(50)
circle(O, 150, :stroke)
text("hello world", halign=:center, valign=:middle)
finish()
d # hide
```
Object showable with other MIME types:
New HTML FronT End
WIP
Themes & Plugins
@charset "UTF-8";
@import "darkly/variables";
$sidebar-background: $grey-darker;
$shadow: $grey-darker;
$sidebar-color: $text;
$lightness-unit: -8%;
$docstring-pre-background: adjust-color($background, $lightness: 5);
@import "documenter/utilities";
@import "documenter/variables";
@import "bulma/utilities/all";
@import "bulma/base/all";
@import "documenter/overrides";
@import "bulma/elements/all";
@import "bulma/form/all";
@import "bulma/components/all";
@import "bulma/grid/all";
@import "bulma/layout/all";
@import "bulma-dashboard";
@import "darkly/overrides";
@import "documenter/components";
@import "documenter/patches";
@import "documenter/layout/all";
.docstring > section {
pre {
background-color: $docstring-pre-background;
}
}
- Uses the Bulma CSS framework
- Creating custom themes:
- Overload variables
- Compile w/ DocumenterTools
- Better APIs for JS extensions
Generating Documentation
Under the hood of documenter.jl
Morten Piibeleht
@mortenpi
Michael Hatherly, Fredrik Ekre, and many others
Generating Documentation in Julia
By Morten Piibeleht
Generating Documentation in Julia
Under the hood of Documenter.jl (JuliaCon 2019) https://www.youtube.com/watch?v=m3c8Z6HBn48
- 1,126