Skip to content

Commit 25736c3

Browse files
kdheepakmortenpi
authored andcommitted
Add TYPEDSIGNATURES (#72)
1 parent ddfdccd commit 25736c3

File tree

5 files changed

+164
-1
lines changed

5 files changed

+164
-1
lines changed

src/DocStringExtensions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ module DocStringExtensions
7777

7878
# Exports.
7979

80-
export @template, FIELDS, EXPORTS, METHODLIST, IMPORTS, SIGNATURES, TYPEDEF, DOCSTRING, FUNCTIONNAME
80+
export @template, FIELDS, EXPORTS, METHODLIST, IMPORTS, SIGNATURES, TYPEDSIGNATURES, TYPEDEF, DOCSTRING, FUNCTIONNAME
8181
export README, LICENSE
8282

8383
# Includes.

src/abbreviations.jl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,68 @@ function format(::MethodSignatures, buf, doc)
303303
end
304304
end
305305

306+
307+
#
308+
# `TypedMethodSignatures`
309+
#
310+
311+
"""
312+
The singleton type for [`TYPEDSIGNATURES`](@ref) abbreviations.
313+
314+
$(:FIELDS)
315+
"""
316+
struct TypedMethodSignatures <: Abbreviation end
317+
318+
"""
319+
An [`Abbreviation`](@ref) for including a simplified representation of all the method
320+
signatures with types that match the given docstring. See [`printmethod`](@ref) for details on
321+
the simplifications that are applied.
322+
323+
# Examples
324+
325+
The generated markdown text will look similar to the following example where a function `f`
326+
defines method taking two positional arguments, `x` and `y`, and two keywords, `a` and the `b`.
327+
328+
````markdown
329+
```julia
330+
f(x::Int, y::Int; a, b...)
331+
```
332+
````
333+
"""
334+
const TYPEDSIGNATURES = TypedMethodSignatures()
335+
336+
function format(::TypedMethodSignatures, buf, doc)
337+
local binding = doc.data[:binding]
338+
local typesig = doc.data[:typesig]
339+
local modname = doc.data[:module]
340+
local func = Docs.resolve(binding)
341+
local groups = methodgroups(func, typesig, modname)
342+
if !isempty(groups)
343+
println(buf)
344+
println(buf, "```julia")
345+
for group in groups
346+
if length(group) == 1
347+
for method in group
348+
printmethod(buf, binding, func, method, typesig)
349+
println(buf)
350+
end
351+
else
352+
for (i, method) in enumerate(group)
353+
if i == length(group)
354+
t = typesig
355+
else
356+
t = typesig.a
357+
typesig = typesig.b
358+
end
359+
printmethod(buf, binding, func, method, t)
360+
println(buf)
361+
end
362+
end
363+
end
364+
println(buf, "\n```\n")
365+
end
366+
end
367+
306368
#
307369
# `FunctionName`
308370
#

src/utilities.jl

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,58 @@ function printmethod(buffer::IOBuffer, binding::Docs.Binding, func, method::Meth
222222
return buffer
223223
end
224224

225+
"""
226+
$(:TYPEDSIGNATURES)
227+
228+
Print a simplified representation of a method signature to `buffer`. Some of these
229+
simplifications include:
230+
231+
* no `TypeVar`s;
232+
* no types;
233+
* no keyword default values;
234+
* `?` printed where `#unused#` arguments are found.
235+
236+
# Examples
237+
238+
```julia
239+
f(x::Int; a = 1, b...) = x
240+
sig = printmethod(Docs.Binding(Main, :f), f, first(methods(f)))
241+
```
242+
"""
243+
function printmethod(buffer::IOBuffer, binding::Docs.Binding, func, method::Method, typesig)
244+
# TODO: print qualified?
245+
print(buffer, binding.var)
246+
print(buffer, "(")
247+
local args = arguments(method)
248+
for (i, sym) in enumerate(args)
249+
if typesig isa UnionAll
250+
t = typesig.body.a.types[1]
251+
else
252+
t = typesig.types[i]
253+
end
254+
print(buffer, "$sym::$t")
255+
if i != length(args)
256+
print(buffer, ", ")
257+
end
258+
end
259+
local kws = keywords(func, method)
260+
if !isempty(kws)
261+
print(buffer, "; ")
262+
join(buffer, kws, ", ")
263+
end
264+
print(buffer, ")")
265+
if typesig isa UnionAll
266+
t = typesig.body.a
267+
else
268+
t = typesig
269+
end
270+
rt = Base.return_types(func, t)
271+
if length(rt) >= 1 && rt[1] !== Nothing && rt[1] !== Union{}
272+
print(buffer, " -> $(rt[1])")
273+
end
274+
return buffer
275+
end
276+
225277
printmethod(b, f, m) = String(take!(printmethod(IOBuffer(), b, f, m)))
226278

227279
get_method_source(m::Method) = Base.uncompressed_ast(m)

test/TestModule/M.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ f(x) = x
66

77
g(x = 1, y = 2, z = 3; kwargs...) = x
88

9+
h(x::Int, y::Int = 2, z::Int = 3; kwargs...) = x
10+
911
const A{T} = Union{Vector{T}, Matrix{T}}
1012

1113
h_1(x::A) = x

test/tests.jl

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,53 @@ end
155155
@test occursin("\n```\n", str)
156156
end
157157

158+
@testset "method signatures with types" begin
159+
doc.data = Dict(
160+
:binding => Docs.Binding(M, :h_1),
161+
:typesig => Tuple{M.A},
162+
:module => M,
163+
)
164+
DSE.format(DSE.TYPEDSIGNATURES, buf, doc)
165+
str = String(take!(buf))
166+
@test occursin("\n```julia\n", str)
167+
if Sys.iswindows()
168+
@test occursin("h_1(x::Union{Array{T,2}, Array{T,1}} where T) -> Union{Array{T,2}, Array{T,1}} where T", str)
169+
else
170+
@test occursin("h_1(x::Union{Array{T,1}, Array{T,2}} where T) -> Union{Array{T,1}, Array{T,2}} where T", str)
171+
end
172+
@test occursin("\n```\n", str)
173+
174+
doc.data = Dict(
175+
:binding => Docs.Binding(M, :h),
176+
:typesig => Tuple{Int, Int, Int},
177+
:module => M,
178+
)
179+
DSE.format(DSE.TYPEDSIGNATURES, buf, doc)
180+
str = String(take!(buf))
181+
@test occursin("\n```julia\n", str)
182+
if typeof(1) === Int64
183+
@test occursin("\nh(x::Int64, y::Int64, z::Int64; kwargs...) -> Int64\n", str)
184+
else
185+
@test occursin("\nh(x::Int32, y::Int32, z::Int32; kwargs...) -> Int32\n", str)
186+
end
187+
@test occursin("\n```\n", str)
188+
189+
doc.data = Dict(
190+
:binding => Docs.Binding(M, :h),
191+
:typesig => Tuple{Int},
192+
:module => M,
193+
)
194+
DSE.format(DSE.TYPEDSIGNATURES, buf, doc)
195+
str = String(take!(buf))
196+
@test occursin("\n```julia\n", str)
197+
if typeof(1) === Int64
198+
@test occursin("\nh(x::Int64) -> Int64\n", str)
199+
else
200+
@test occursin("\nh(x::Int32) -> Int32\n", str)
201+
end
202+
@test occursin("\n```\n", str)
203+
end
204+
158205
@testset "function names" begin
159206
doc.data = Dict(
160207
:binding => Docs.Binding(M, :f),

0 commit comments

Comments
 (0)