在Elixir宏中获取当前范围的文档

时间:2018-08-16 18:32:39

标签: elixir documentation metaprogramming

我正在尝试编写帮助程序宏,使我可以编写大量的Elixir结构,而无需进行很多重复操作,所以我编写了宏:

new Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  mainAxisAlignment: MainAxisAlignment.end,
  children: <Widget>[
    new FlatButton(
          onPressed: _navigateToPreparationStepsWidgetClicked,
          child: new Row(
            children: <Widget>[
              new Text(
                'View Preparation Steps'.toUpperCase(),
                style: new TextStyle(
                    fontWeight: FontWeight.bold),
              ),
              new Icon(Icons.keyboard_arrow_right)
            ],
          ))
  ],
)

可用于以下用途:

Button

不过,我想增加通过Column模块属性向此类模块添加文档的可能性:

defmodule Events do
  @moduledoc false

  defmacro defevent(module, fields \\ []) do
    keys = Keyword.keys(fields)

    quote do
      defmodule unquote(module) do
        @type t :: %__MODULE__{unquote_splicing(fields)}

        defstruct unquote(keys)
      end
    end
  end
end

但是,由于没有文档,defmofule Event do import Events defevent Foo, foo: String.t(), bar: number() end 会返回@doc,如果有文档字符串,则会返回defmodule Events do @moduledoc false defmacro defevent(module, fields \\ []) do keys = Keyword.keys(fields) quote do docs = Module.delete_attribute(__MODULE__, :doc) defmodule unquote(module) do for doc <- docs do @moduledoc doc end @type t :: %__MODULE__{unquote_splicing(fields)} defstruct unquote(keys) end end end end 。但是它会错过所有标签,因此编写如下代码:

Module.get_attribute(__MODULE__, :doc)

将仅包含nil字符串,而没有指定标签。我当前的解决方法是使用自定义属性,但这并不是最漂亮的解决方案,因为它需要非标准参数并定义自定义模块属性(这使我依赖于{integer(), String.t()})。

defmofule Event do
  import Events

  @doc "Foo"
  @doc deprecated: "Bar"
  defevent Foo, foo: String.t(), bar: number()
end

有没有办法获取分配了所有属性的当前"Foo"的值?

1 个答案:

答案 0 :(得分:2)

非常有偏见的拙见:没有一个Elixir开发人员没有尝试增强结构。它们既酷,简洁又生动,您的代码只会使事情变得复杂。

我相信,Elixir核心团队同意这一观点,这就是为什么不公开此功能的原因。无论您是否有足够的勇气去解决它,都可以。

这里是how documentation is built by Elixir。请注意主要评论:

@doc false  
# Used internally to compile documentation.  
# This function is private and must be used only internally.

您还在吗?好吧。

深入研究Module.compile_definition_attributes/6,我们进入Module.compile_doc_meta/5

我们距离解决方案仅一步之遥。谨防!私人功能区!

您要自己重新实现Module.get_doc_meta/2

case :ets.take(set, {:doc, :meta}) do
  [{{:doc, :meta}, metadata, _}] -> Map.merge(existing_meta, metadata)
  [] -> existing_meta
end

也就是说,您将从ETS读取{:doc, :meta}键,其中setdefined here