Running doctests via Mix

110 views
Skip to first unread message

Dave Thomas

unread,
Apr 16, 2013, 12:32:01 AM4/16/13
to elixir-l...@googlegroups.com
I've been playing with getting doctests to run without having to write a separate test module. I'm working towards having a mix task that takes a list of .ex files and just runs the doctests in them.

As a first spike, I'm trying it with a static module inside the task itself


However, when I run it, I get the failures below. Is there an ast_to_string or equivalent to I can see what's wrong with the module I'm generating? Alternatively, can anyone give me a hint where to start digging?

Cheers


Dave


Failures:

  1) test moduledoc at Mix.Tasks.Doctest.Wombat (1) (Mix.Tasks.Doctest.InternalTests)
     ** (FunctionClauseError) no function clause matching: Mix.Tasks.Doctest.InternalTests."test moduledoc at Mix.Tasks.Doctest.Wombat (1)"([test: ExUnit.Test[name: :"test moduledoc at Mix.Tasks.Doctest.Wombat (1)", case: Mix.Tasks.Doctest.InternalTests, failure: nil], case: Mix.Tasks.Doctest.InternalTests])
     at nofile:1

  2) test moduledoc at Mix.Tasks.Doctest.Wombat (2) (Mix.Tasks.Doctest.InternalTests)
     ** (FunctionClauseError) no function clause matching: Mix.Tasks.Doctest.InternalTests."test moduledoc at Mix.Tasks.Doctest.Wombat (2)"([test: ExUnit.Test[name: :"test moduledoc at Mix.Tasks.Doctest.Wombat (2)", case: Mix.Tasks.Doctest.InternalTests, failure: nil], case: Mix.Tasks.Doctest.InternalTests])
     at nofile:1

Finished in 0.00 seconds


José Valim

unread,
Apr 16, 2013, 12:56:20 AM4/16/13
to elixir-l...@googlegroups.com
Dave,

Macro.to_binary is going to convert an ast to binary.
I would also suggest using the quote mechanism to generate the code you desire.

Here is an example. Assuming you have a list of tuples with the function names and their implementation, similar to the ones you get from doctest:

    list = quote do: [foo: 1 + 2, bar: 3 + 5]
    defs = Enum.map list, fn { name, impl } ->
      quote do
        def unquote(name)(_), do: unquote(impl)
      end
    end

    contents = quote do
      use ExUnit.Case, async: true

      # Splice the functions in the module body.
      # unquote would work just fine too
      unquote_splicing(defs)
    end

    Module.create(MyModule, contents, __ENV__.location)
    MyModule.foo(:whatever) #=> 3
          
You could also use Code.eval_quoted as you were, but in general Elixir provides tools so you can avoid any of the evaling functions.



José Valim
Skype: jv.ptec
Founder and Lead Developer


--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Dave Thomas

unread,
Apr 16, 2013, 1:12:38 AM4/16/13
to elixir-l...@googlegroups.com

I would also suggest using the quote mechanism to generate the code you desire.


And that indeed worked (and is infinitely more elegant than building the ast by hand :)

I'll finish this up tomorrow. Would you consider a pull request for it?


Dave

José Valim

unread,
Apr 16, 2013, 1:22:02 AM4/16/13
to elixir-l...@googlegroups.com
I'll finish this up tomorrow. Would you consider a pull request for it?

I thought about it originally and I am undecided. While it seems interesting, I couldn't find a scenario where I would use it directly, since setting up the test framework is easy. If there are good use cases for it though, I don't see why not. :)

Also, I just realized you could call doctest directly from the test case. So you probably just need this:

    contents = quote do
      use ExUnit.Case, async: true
      Enum.each modules_to_test, doctest(&1)
    end

    Module.create(MyModule, contents, __ENV__.location)

It takes all the fun away though!
Reply all
Reply to author
Forward
0 new messages