Skip to content

Commit 38a7199

Browse files
Merge pull request #133 from JuliaDocs/mh/capture-expr
Support capturing `Expr` for use in abbreviations.
2 parents 20c850b + 9711545 commit 38a7199

File tree

5 files changed

+68
-0
lines changed

5 files changed

+68
-0
lines changed

src/DocStringExtensions.jl

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ import LibGit2
8282
export @template, FIELDS, TYPEDFIELDS, EXPORTS, METHODLIST, IMPORTS
8383
export SIGNATURES, TYPEDSIGNATURES, TYPEDEF, DOCSTRING, FUNCTIONNAME
8484
export README, LICENSE
85+
export interpolation
8586

8687
# Includes.
8788

src/templates.jl

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ end
9797
# On v0.6 and below it seems it was assumed to be (docstr::String, expr::Expr), but on v0.7
9898
# it is (source::LineNumberNode, mod::Module, docstr::String, expr::Expr)
9999
function template_hook(source::LineNumberNode, mod::Module, docstr, expr::Expr)
100+
docstr = _capture_expression(docstr, expr)
100101
# During macro expansion we only need to wrap docstrings in special
101102
# abbreviations that later print out what was before and after the
102103
# docstring in it's specific template. This is only done when the module

src/utilities.jl

+36
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,42 @@
33
# Utilities.
44
#
55

6+
#
7+
# Expression Capture.
8+
#
9+
10+
"""
11+
interpolation(object::T, captured::Expr) -> new_object
12+
13+
Interface method for hooking into interpolation within docstrings to change
14+
the behaviour of the interpolation. `object` is the interpolated object within a
15+
docstring and `captured` is the raw expression that is documented by the docstring
16+
in which the interpolated `object` has been included.
17+
18+
To define custom behaviour for your own `object` types implement a method of
19+
`interpolation(::T, captured)` for type `T` and return a `new_object` to
20+
be interpolated into the final docstring. Note that you must own the definition
21+
of type `T`. `new_object` does not need to be of type `T`.
22+
"""
23+
interpolation(@nospecialize(object), @nospecialize(_)) = object
24+
25+
# During macro expansion process the interpolated string and replace all interpolation
26+
# syntax with calls to `interpolation` that pass through the documented expression along
27+
# with the resolved object that was interpolated.
28+
function _capture_expression(docstr::Expr, expr::Expr)
29+
if Meta.isexpr(docstr, :string)
30+
quoted = QuoteNode(expr)
31+
new_docstring = Expr(:string)
32+
append!(new_docstring.args, [_process_interpolation(each, quoted) for each in docstr.args])
33+
return new_docstring
34+
end
35+
return docstr
36+
end
37+
_capture_expression(@nospecialize(other), ::Expr) = other
38+
39+
_process_interpolation(str::AbstractString, ::QuoteNode) = str
40+
_process_interpolation(@nospecialize(expr), quoted::QuoteNode) = Expr(:call, interpolation, expr, quoted)
41+
642
#
743
# Method grouping.
844
#

test/interpolation.jl

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module InterpolationTestModule
2+
3+
struct TestType
4+
value::Int
5+
end
6+
7+
import DocStringExtensions
8+
9+
# For TestType(1), it interpolates the function signature, and for
10+
# TestType(2) it interpolates the function body.
11+
DocStringExtensions.interpolation(obj::TestType, ex::Expr) = ex.args[obj.value]
12+
13+
"""
14+
$(TestType(1))
15+
"""
16+
f(x) = x + 1
17+
18+
"""
19+
$(TestType(2))
20+
"""
21+
g(x) = x + 2
22+
23+
end

test/tests.jl

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const DSE = DocStringExtensions
22

33
include("templates.jl")
4+
include("interpolation.jl")
45
include("TestModule/M.jl")
56

67
# initialize a test repo in test/TestModule which is needed for some tests
@@ -516,6 +517,12 @@ end
516517
@test fmt(:(TemplateTests.OtherModule.f)) == "method `f`\n"
517518
end
518519
end
520+
@testset "Interpolation" begin
521+
let fmt = expr -> Markdown.plain(eval(:(@doc $expr)))
522+
@test occursin("f(x)", fmt(:(InterpolationTestModule.f)))
523+
@test occursin("x + 2", fmt(:(InterpolationTestModule.g)))
524+
end
525+
end
519526
@testset "utilities" begin
520527
@testset "keywords" begin
521528
@test DSE.keywords(M.T, first(methods(M.T))) == Symbol[]

0 commit comments

Comments
 (0)