我有一个定义宏的下一个模块:
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.Command:
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
面对代理在编译时启动但在重新启动应用程序时无法启动的问题。 如何存储地图"命令" => "负责处理的模块"在宏指定命令名称的条件下?或者可以提示另一种方式动态选择模块来处理命令。我想将所有命令保存在单独的模块中,以便更好地维护和添加新的简单方法。