I have been working on a few improvements for doctests.
Everything that I'm proposing here has already been implemented.
The proposals started because some modules in Elixir are not being tested with doctests, and this
is because there are certain limitation in doctest. These improvements aim to eliminate those.
My proposal consist of two main points:
1) Streamline Doctests with regular examples.
Currently some examples need to be expressed in regular code, not in IEx examples, because some
features are not supported.
-- a) Include comments in doctest syntax.
We should allow full-line comments in code (currently only comments after evaluated expressions
are allowed). My proposal is to have three different kind of comments.
---- I) Regular comments, such as:
# this is a regular comment
iex> true
true
---- II) Return value comments.
These are useful when we will not get the same value everytime the function is run.
iex> spawn(fn -> true end)
#=> PID<0.97.0>
---- III) Print comments.
Currently it is not clear when a value is returned or printed on screen (stdout/stderr), so my
proposal is to create a new convention for this. My suggestion is to use "#>> ", but it could
be anything.
iex> IO.puts "Elixir"
#>> Elixir
:ok
2) Mimic IEx by allowing user to import IEx.Helpers, which are automatically imported when IEx is
loaded.
I came across this when I was trying to run doctests in the Port module. In the examples the
flush/0 function is used which is imported from IEx.Helpers. Currently it is impossible simulate a
doctest if the whole IEx environment is required, without explicitly importing IEx.Helpers.
So my proposal is to add an option :import_iex_helpers, which works the same way as :import
option, taking :true, :false, :only, and :except values (default value is :false).
doctest ModuleToDocTest, import_iex_helpers: true
or
doctest ModuleToDocTest, import_iex_helpers: [only: [flush: 0]]
this way the first example in the Port module could be doctested as:
iex> port = Port.open({:spawn, "cat"}, [:binary])
#=> #Port<0.1444>
iex> send port, {self(), {:command, "hello"}}
#=> {#PID<0.80.0>, {:command, "hello"}}
iex> send port, {self(), {:command, "world"}}
#=> {#PID<0.80.0>, {:command, "world"}}
iex> flush()
#>> {#Port<0.1444>, {:data, "hello"}}
#>> {#Port<0.1444>, {:data, "world"}}
:ok
iex> send port, {self(), :close}
#=> {#PID<0.80.0>, :close}
iex> flush()
#>> {#Port<0.1444>, :closed}
:ok
The implemented and tested code can be found here:
https://github.com/eksperimental/elixir/tree/doctest_improvements3
Thank you for reading and looking forward for your feedback.