ANN: Announcing DoctorDocstrings.jl

Hello all!

DoctorDocstrings.jl is a package that will help you enhance your REPL workflow for adding docstrings to your package. It is very simple, alpha, and hardcoded (for now). Dear lord don’t judge me from the janky hacks it’s awful awful. But it works! The docs are here.

The idea is to

  1. listdocs($MyPackage) to know see all exports in your package/module and true/false for having docstrings/examples.
  2. diagnosedocs($MyPackage) if you only want to know the ones that are missing docstrings
  3. Now that you know which one you want to add docstrings to, you play around with some inputs in the REPL.
  4. fixdocs() select from your REPL history which inputs you want, choose a docstrings template, and step in to @edit the last selected input. The previous REPL entries are in your clipboard, so just pasting should work.

Here’s a live 3 minute demo to show the workflow.

Comments, issues, PRs welcome.

Acknowledgments

Thanks a lot to @mbauman for early feedback, @PetrKryslUCSD for REPLHistory.jl, (a good reference for this project), and @StefanKarpinski for “incepting” this idea into my todo-list, and @tlienart for help with the documentation.

31 Likes

Beautiful, and pure gold for the name.

It’s not so clear from the docs what quantifies as an “example”. Care to provided a (very explicit, very specific) definition?

To be clear: how does the package decides if one of my docstrings has, or has not, an example? I don’t mean “how do you write examples”

2 Likes

Thanks, I just added the link.

Here’s what I mean by examples - anything that is copy/pasteable Julia code that comes after Examples\n==== in the docstring, like what is in ?parse:

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> parse(Int, "1234")
  1234

  julia> parse(Int, "1234", base = 5)
  194

  julia> parse(Int, "afc", base = 16)
  2812

  julia> parse(Float64, "1.2e-3")
  0.0012

The logic for checking if it has examples is very unsophisticated - I just splat everything onto a string and check for the existence of a Examples\n==== occurring. I’m open to suggestions on how not to jankily abuse the doc internals :sweat_smile:. (This works for enough use cases as a hack that perfect is the enemy of the good for shipping, so I thought I’d nerdsnipe someone into helping me implement something better .)

Sometimes you do not realise how much you want/need a package doing something until you see a package and see how great idea is it. It is a great idea. I will try with my code and then I will give my feedback.

1 Like

Great, Examples\n==== is exactly what I was looking for. Would be good to extend this with other possibilities. So far I have always used ## Example or ## Examples, so It would be good to provide a keyword like example_quantifier = ["Examples\n====", "## Examples"...] that has a lot of defaults

1 Like

Thanks! I do hope other people like the REPL mucking about + fixdocs() workflow.

Sounds like an excellent PR to handle edge cases :smiley:

1 Like

Just found a bug that has to do with (I think) macro hygiene.

If I input

julia> using SparseArrays

julia> A = sparsevec([1,2,3], [1.0, 0.0, 1.0])
3-element SparseVector{Float64, Int64} with 3 stored entries:
  [1]  =  1.0
  [2]  =  0.0
  [3]  =  1.0

julia> dropzeros!(A)
3-element SparseVector{Float64, Int64} with 2 stored entries:
  [1]  =  1.0
  [3]  =  1.0

And I select them with pickandcopy(), which tries to @eval Meta.parse(inputstring), I get sparsevec not defined.

Any help?