如何使用 Elixir 宏获取模块的完整生成代码
How to get the full generated code of a module using Elixir macros
下面是示例 Phoenix 应用程序的路由器模块。我想查看模块 after 宏注入函数的完整代码。
我试过 Macro.to_string (Macro.expand (Code.string_to_quoted! File.read!("web/router.ex")), __ENV__)
之类的东西,但它没有完全展开宏。我如何递归展开每个宏,即 pipeline
、plug
、scope
、pipe_through
和 get
.
谢谢
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
正如您正确观察到的,您需要递归地使用Macro.expand/1
才能真正扩展所有宏级别。有一个内置工具可以实现此目的:Macro.prewalk/2
。这应该让你开始:
ast
|> Macro.prewalk(&Macro.expand(&1, __ENV__))
|> Macro.to_string
|> IO.puts
这段代码会将 beam 文件反编译回 erlang。我没有 运行 它针对基于插件的模块,所以我不知道结果会有多糟糕,但这给了你 any 模块的最终结果.
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
的文件路径
下面是示例 Phoenix 应用程序的路由器模块。我想查看模块 after 宏注入函数的完整代码。
我试过 Macro.to_string (Macro.expand (Code.string_to_quoted! File.read!("web/router.ex")), __ENV__)
之类的东西,但它没有完全展开宏。我如何递归展开每个宏,即 pipeline
、plug
、scope
、pipe_through
和 get
.
谢谢
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
正如您正确观察到的,您需要递归地使用Macro.expand/1
才能真正扩展所有宏级别。有一个内置工具可以实现此目的:Macro.prewalk/2
。这应该让你开始:
ast
|> Macro.prewalk(&Macro.expand(&1, __ENV__))
|> Macro.to_string
|> IO.puts
这段代码会将 beam 文件反编译回 erlang。我没有 运行 它针对基于插件的模块,所以我不知道结果会有多糟糕,但这给了你 any 模块的最终结果.
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
的文件路径