如何使用Elixir宏获取模块的完整生成代码

时间:2016-03-15 16:45:47

标签: compilation metaprogramming elixir phoenix-framework

以下是Phoenix应用程序示例的路由器模块。我希望在宏注入函数之后看到模块的完整代码。

我尝试过类似Macro.to_string (Macro.expand (Code.string_to_quoted! File.read!("web/router.ex")), __ENV__)的内容,但它没有完全展开宏。我如何递归扩展每个宏,即pipelineplugscopepipe_throughget

由于

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 个答案:

答案 0 :(得分:6)

正如您所正确观察到的,您需要递归使用Macro.expand/1来真正扩展所有宏级别。有一个内置的工具来实现这一目标:Macro.prewalk/2。这应该让你开始:

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

答案 1 :(得分:4)

这段代码会将一个波束文件反编译回erlang。我没有针对基于插件的模块运行它,所以我不知道结果会有多糟糕,但是这为任何模块提供了最终结果。

  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

原始来源,以及更多信息:http://erlang.org/doc/man/beam_lib.html

请注意,此方法采用[module] .beam

文件路径