Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 如何存储宏中传递的值?_Elixir_Metaprogramming - Fatal编程技术网

Elixir 如何存储宏中传递的值?

Elixir 如何存储宏中传递的值?,elixir,metaprogramming,Elixir,Metaprogramming,我有一个定义宏的下一个模块: defmodule BServer.Command do defmacro __using__(_)do quote do @before_compile unquote(__MODULE__) import BServer.Command, only: [command: 1, command: 2, command_description: 1]

我有一个定义宏的下一个模块:

defmodule BServer.Command do

  defmacro __using__(_)do
    quote do
      @before_compile unquote(__MODULE__)
      import BServer.Command, only: [command: 1, command: 2,
                                     command_description: 1]
      Agent.start(fn -> %{} end, name: unquote(__MODULE__))
    end
  end

  defmacro command(command_name, args \\[]) do
    quote do
      name = unquote(Atom.to_string(command_name))
      @command_name Keyword.get(unquote(args), :name, name)
      Agent.update(unquote(__MODULE__), &(Map.put(&1, unquote(command_name), __MODULE__)))
    end
  end

  defmacro __before_compile__(_env) do
    quote do
      def desc(), do: @command_desc
    end
  end

  def all do
      Agent.get(__MODULE__, &(&1))
  end


  def get(name) when is_atom(name) do
    Agent.get(__MODULE__, &(&1[name]), 100)
  end

  def get(name) when is_binary(name) do
    {command, _args} = parse(name)
    String.to_atom(command)
      |> get
  end

  def parse(message) do
    case Regex.run(~r/\w+\b/, message) do
      nil -> 
        {"", []}
      [command | args ] ->
        {command, args }
      [command] ->
        {command, []}   
    end
  end

  defmacro command_description(description) do
    quote do
      @command_desc unquote(description)
    end
  end
end
下一个模块中使用的BServer.命令:

defmodule BServer.Command.Help do
  use BServer.Command

  command :help
  command_description """
    List of available commands
  """

  def process(user) do
    commands = 
      BServer.Command.all
        |> Enum.map(fn ({command, module}) -> 
          "#{command} - #{module.desc}"
        end)
        |> Enum.join("\n")
  end
end
在另一个地方,我动态定义用于处理接收到的命令的模块:

    case BServer.Command.get(message) do
        nil -> false
        command ->
            BServr.User.get(user_attributes)
                |> command.process
    end
面临代理仅在编译时启动,而在应用程序重新启动时不启动的问题。
在宏给出命令名称的情况下,如何存储map“command”=>“负责处理的模块”?或者可以提示以另一种方式动态选择要处理该命令的模块。我希望将所有命令保留在单独的模块中,以便更好地维护和方便地添加新命令。

您希望在编译阶段收集数据,并在应用程序运行时使用它。使用或您选择的任何其他持久性存储。旁注:您正在滥用宏,使事情变得过于复杂。对于这个特定的任务,smth(Module.concat(BServer.Command,Command_Module),Command,args)足够了,假设
{Command_Module,Command}
是从输入中获得的,比如
“help|u help”|>String.split |>Enum.map(String.capitalize/1)
(⇐ 伪代码,但您有一个想法。而且,这里可能会用到,假设您希望您的命令“一起”存在,在一些预先已知的“公共名称空间”下@mudasobwa是的,我考虑过Module.concat/2的变体,但它不允许在BServer.Command.all命令中获得所有命令名,以在帮助命令响应中显示所有可用命令(例如)。我开始使用宏b/c,希望它允许在基本模块中动态注册命令模块。