nelsonic
nelsonic

Reputation: 33214

Why/How/When to use the __using__(which) macro in Phoenix Controller/View/etc?

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!

Upvotes: 4

Views: 505

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

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.

Upvotes: 3

Related Questions