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,希望它允许在基本模块中动态注册命令模块。