4
votes

Context

Inside every Phoenix (Elixir Web Framework) App, at the bottom of the /lib/{yourapp}_web.ex file e.g: /lib/chat_web.ex there is a __using__/1 macro defined as:

@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
defmacro __using__(which) when is_atom(which) do
  apply(__MODULE__, which, [])
end

Question: what is the __using__/1 macro used for?

If you can, share (or link to) a usage example which will help demonstrate it in a real world context.

Where does the apply function come from given that it's not "imported" in the /lib/{yourapp}_web.ex file and what is the effect of the "apply" ?

We have tried googling and reading several docs, tutorials, blog posts etc. on Macros. e.g:

But still no closer to understanding the why/when/how we would use __using__/1 macro ... :-(

If we attempt to comment out or delete it from lib/chat_web.ex the app does not compile even though it is not invoked from with chat_web.ex ... and excoveralls (test coverage reporting) reports that it's not being executed.

I find this confusing / non-beginner-friendly and searching the Phoenix guide (docs) is not particularly insightful e.g: https://github.com/phoenixframework/phoenix/blob/29536f3b86154ab64647643a3eeeb263e33834cd/guides/controllers.md image

 Further context:

In the Phoenix Chat Example/Tutorial: https://github.com/dwyl/phoenix-chat-example
We are tracking test coverage as a learning exercise ...
There is only one line of code that is not being covered by Tests: https://codecov.io/gh/dwyl/phoenix-chat-example/src/b57cc174d7f1c9aac22947f23170b29d4c303776/lib/chat_web.ex#L65 image

How is it that the line is not being executed ("covered") when we run the tests, but if we comment out the line the tests fail?

Is this macro "magic" in that it is being "used" without actually being called? Any shoshin insight much appreciated!

1
Recently I come across the same thing and i searched but couldn't find the the answer. But then I implemented it in my project and that makes sense. Let me give you example where I use it. I have test cases that have same controller written with macro. so its not suitable for me ti write similar test cases for each controller .so i used macro __using__/1. and include that macro in every controller test . It solves my problem of writing same code for each test controller over and over.script

1 Answers

3
votes

FYI: the best source is the Elixir documentation, not guides, tutorials and blog posts. Let me cite this excerpt from Kernel.use/2:

When calling:

use MyModule, some: :options

the __using__/1 macro from the MyModule module is invoked with the second argument passed to use as its argument. Since __using__/1 is a macro, all the usual macro rules apply, and its return value should be quoted code that is then inserted where use/2 is called.

There are also examples there, which might clarify the concept on itself.


How is it that the line is not being executed (“covered”) when we run the tests, but if we comment out the line the tests fail?

Since it’s a macro, it is injected into the calling source code on compilation stage. That said, when use ThisModule is called, the AST, returned by __using__/1 is being injected into the caller’s context.

I have no idea why Coverage is so stupid to mark this line, though.