fabioticconi

fabioticconi

Understanding __using__, with a practical problem

Hi all,

I’m trying to solve a practical problem - make an ExUnit “data case” with async true as default, instead of false.

So if a user does this:

use MyTestCase

Then async will be true, but if the user specifies use MyTestCase, async: false then it will be respected.

It seems to me that it should be fairly easy to inject code into the ExUnit.CaseTemplate to make it happen, but my understanding of Elixir metaprogramming is limited and have been stuck.

In my datacase, the first thing I do is to use ExUnit.CaseTemplate. This will import some callbacks and assertions and inject an __using__, overridable macro. As can be seen here: elixir/lib/ex_unit/lib/ex_unit/case_template.ex at v1.13.4 · elixir-lang/elixir · GitHub

Now, I thought I could do something like:

defmodule MyTestCase
  use ExUnit.CaseTemplate

  using opts do quote do
    # modify opts keyword list, put async true if not present
  end
end

But the __proxy__ function is called before evaluating the provided block (it’s the using/1 helper function in ExUnit.CaseTemplate that I’m leveraging). This means that the opts will have already been processed so I can’t know, at that point, whether the user had specified async: true or async: false.

What am I missing? Can I work with this or do I need to essentially drop the use ExUnit.CaseTemplate line and replicate what is does but in the way I need?

Marked As Solved

LostKobrakai

LostKobrakai

You likely want this:

defmodule MyTestCase
  use ExUnit.CaseTemplate

  defmacro __using__(opts) do
    opts
    |> Keyword.put_new(:async, true)
    |> super()
  end
end

For overwriting a overwritable __using__ macro, you need to implement exactly that macro. To call the injected implementation with your changes you can use super(). There’s no need to fiddle with quote in this case as you never need to convert text of code into AST.

Where Next?

Popular in Questions Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement