I’m trying to do something that I thought would be easy but is actually rather tricky.
I simply want to get the docstring of a Method.
For example:
"""
my f
"""
f(x::Int) = 2x
"""
with strings
"""
f(x::String) = print(x)
"""
and keyword args
"""
f(; y=1) = print(y)
methods
gives:
# 3 methods for generic function "f":
[1] f(; y) in Main at /Users/federicoclaudi/Documents/Github/Term.jl/workspace.jl:16
[2] f(x::Int64) in Main at /Users/federicoclaudi/Documents/Github/Term.jl/workspace.jl:5
[3] f(x::String) in Main at /Users/federicoclaudi/Documents/Github/Term.jl/workspace.jl:11
if, say, I wanted to get the docstring of the second method, what should I do?
I know about Docs.Binding and Docs.meta to get multidocs like it’s done, for example, in the REPL but I was hoping there was a more direct way to get at this.
Specifically, when the methods are constructors for a DataType there might be multiple methods that differ only in their keyword arguments and the approach above doesn’t distinguish them since they share the same signature.
I’m afraid not. I need the docstring for a specific method, not for all of them. There’s way to use the signature, but it still doesn’t always cover all cases. Isn’t there a way, given an object of type Method to get the actual docstring that belongs to ?
I don’t think that’s possible, you can’t have two methods with the same type signature that only differ by keyword arguments, because the keyword arguments don’t count for dispatch.
This is the solution I landed on, it seems to get the job done, leaving it here in case folks find it useful:
using Base.Docs: meta, Binding, doc
import Markdown
"""
get_methods_with_docstrings(obj::Union{Union, DataType, Function})
Get the docstring for each method for an object (function/datatype).
"""
function get_methods_with_docstrings(obj::Union{Union, DataType, Function})::Tuple{Vector, Vector}
# get the parent module and the methods list for the object
mod = parentmodule(obj)
mm = methods(obj)
# get the module's multidoc
binding = Binding(mod, Symbol(obj))
dict = meta(mod)
multidoc = dict[binding]
# for each module, attempt to get the docstring as markdown
docstrings = []
for m in mm
# cleanup signature
sig = length(m.sig.types) == 1 ? Tuple{} : Tuple{m.sig.types[2:end]...}
haskey(multidoc.docs, sig) || begin
push!(docstrings, nothing)
end
docs = multidoc.docs[sig].text[1] |> Markdown.parse
push!(docstrings, docs)
end
return mm, docstrings
end