/
DocMeta.jl
88 lines (70 loc) · 2.93 KB
/
DocMeta.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""
This module provides APIs for handling documentation metadata in modules.
The implementation is similar to how docstrings are handled in `Base` by the `Base.Docs`
module — a special variable is created in each module that has documentation metadata.
# Public API
* [`DocMeta.getdocmeta`](@ref)
* [`DocMeta.setdocmeta!`](@ref)
# Supported metadata
* `DocTestSetup`: contains the doctest setup code for doctests in the module.
"""
module DocMeta
using ..Documenter: Utilities
using DocStringExtensions
"The unique `Symbol` that is used to store the metadata dictionary in each module."
const META = gensym(:docmeta)
"List of modules that have the metadata dictionary added."
const METAMODULES = Module[]
"Type of the metadata dictionary."
const METATYPE = Dict{Symbol,Any}
"Dictionary of all valid metadata keys and their types."
const VALIDMETA = Dict{Symbol,Type}(:DocTestSetup => Union{Expr,Symbol})
"""
"""
function initdocmeta!(m::Module)
if !isdefined(m, META)
@debug "Creating documentation metadata dictionary (META=$META) in $m"
Core.eval(m, :(const $META = $(METATYPE())))
push!(METAMODULES, m)
else
@warn "Existing documentation metadata dictionary (META=$META) in $m. Ignoring."
end
return getfield(m, META)
end
"""
getdocmeta(m::Module)
Returns the documentation metadata dictionary for the module `m`. The dictionary should be
considered immutable and assigning values to it is not well-defined. To set documentation
metadata values, [`DocMeta.setdocmeta!`](@ref) should be used instead.
"""
getdocmeta(m::Module) = isdefined(m, META) ? getfield(m, META) : METATYPE()
"""
getdocmeta(m::Module, key::Symbol, default=nothing)
Return the `key` entry from the documentation metadata for module `m`, or `default` if the
value is unset.
"""
getdocmeta(m::Module, key::Symbol, default=nothing) = get(getdocmeta(m), key, default)
"""
setdocmeta!(m::Module, key::Symbol, value; recursive=false, warn=true)
Set the documentation metadata value `key` for module `m` to `value`.
If `recursive` is set to `true`, it sets the same metadata value for all the submodules too.
If `warn` is `true`, it prints a warning when `key` already exists and is gets rewritten.
"""
function setdocmeta!(m::Module, key::Symbol, value; warn=true, recursive=false)
key in keys(VALIDMETA) || throw(ArgumentError("Invalid metadata key\nValid keys are: $(join(keys(VALIDMETA), ", "))"))
isa(value, VALIDMETA[key]) || throw(ArgumentError("Bad value type ($(typeof(value))) for metadata key $(key). Must be <: $(VALIDMETA[key])"))
if recursive
for mod in Utilities.submodules(m)
setdocmeta!(mod, key, value; warn=warn, recursive=false)
end
else
isdefined(m, META) || initdocmeta!(m)
meta = getdocmeta(m)
if warn && haskey(meta, key)
@warn "$(key) already set for module $m. Overwriting."
end
meta[key] = value
end
return nothing
end
end