10

Below is the router module for a sample Phoenix application. I would like to see the full code of the module after macros inject functions.

I tried things like Macro.to_string (Macro.expand (Code.string_to_quoted! File.read!("web/router.ex")), __ENV__) but it doesn't fully expand the macros. How could I recursively expand every macro, i.e. pipeline, plug, scope, pipe_through and get.

Thanks

defmodule HelloPhoenix.Router do use HelloPhoenix.Web, :router pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers end pipeline :api do plug :accepts, ["json"] end scope "/", HelloPhoenix do pipe_through :browser # Use the default browser stack get "/", PageController, :index end end 

2 Answers 2

7

This bit of code will decompile a beam file back to erlang. I haven't run it against a plug-based module, so I don't know how nasty the result will be, but this gives you the final result for any module.

 def disassemble(beam_file) do beam_file = String.to_char_list(beam_file) {:ok, {_, [{:abstract_code, {_, ac}}]}} = :beam_lib.chunks(beam_file, [:abstract_code]) :io.fwrite('~s~n', [:erl_prettypr.format(:erl_syntax.form_list(ac))]) end 

original source, and more info: http://erlang.org/doc/man/beam_lib.html

Note that this method takes the file path of [module].beam

Sign up to request clarification or add additional context in comments.

1 Comment

Too bad we can't have elixir code but as I can read erlang better than elixir it's okay for me :) Thank you
6

As you have correctly observed, you need to use Macro.expand/1 recursively to truly expand all macro levels. There is a built-in facility to achieve this: Macro.prewalk/2. This should get you started:

ast |> Macro.prewalk(&Macro.expand(&1, __ENV__)) |> Macro.to_string |> IO.puts 

2 Comments

I can't make it work. I also found a package called Mex that can't seem to print the full code either. But thanks anyway, I'll tinker a bit more
Oh it seems inspecting modules is not as straightforward, sorry. If you want to get a quick and dirty solution you can try to manually inject the inspection code into the module itself, so that your __ENV__ is within the module. Can't check right now but you might have some success with that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.