【问题标题】:How to get the full generated code of a module using Elixir macros如何使用 Elixir 宏获取模块的完整生成代码
【发布时间】:2016-07-01 05:54:24
【问题描述】:

以下是 Phoenix 应用程序示例的路由器模块。我想看看模块after宏注入函数的完整代码。

我尝试了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

【问题讨论】:

    标签: compilation metaprogramming elixir phoenix-framework


    【解决方案1】:

    这段代码会将一个梁文件反编译回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

    文件路径

    【讨论】:

    • 太糟糕了,我们不能有 elixir 代码,但是因为我能比 elixir 更好地阅读 erlang,所以对我来说没问题 :) 谢谢
    【解决方案2】:

    正如您正确观察到的,您需要递归使用Macro.expand/1 才能真正扩展所有 宏级别。有一个内置工具可以实现这一点:Macro.prewalk/2。这应该可以帮助您开始:

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

    【讨论】:

    • 我无法让它工作。我还发现了一个名为 Mex 的包,它似乎也无法打印完整的代码。不过还是谢谢了,我会再修修补补
    • 哦,看来检查模块并不那么简单,抱歉。如果您想获得一个快速而肮脏的解决方案,您可以尝试手动将检查代码注入模块本身,以便您的__ENV__ 在模块内。现在无法检查,但您可能会取得一些成功。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 1970-01-01
    相关资源
    最近更新 更多