Elixir:在另一个函数之后运行函数

时间:2017-12-08 02:43:52

标签: elixir

我仍然是Elixir的新手并检查存储库中的一些代码,并想知道是否有办法减少以下代码片段:

  def find(client) do
    Common.find(client, @resource)
    |> ResponseHandler.handle_response(@model_module)
  end

  def find(client, identifier) do
    Common.find(client, @resource, identifier)
    |> ResponseHandler.handle_response(@model_module)
  end

  def filter(client, filter) do
    Common.filter(client, @resource, filter)
    |> ResponseHandler.handle_response(@model_module)
  end

  def create(client, bank_transactions_map) do
    Common.create(client, @resource, bank_transactions_map)
    |> ResponseHandler.handle_response(@model_module)
  end

  def update(client, identifier, bank_transactions_map) do
    Common.update(client, @resource, identifier, bank_transactions_map)
    |> ResponseHandler.handle_response(@model_module)
  end

这里的所有功能都进入相同的功能,似乎有点重复。有没有办法在模块中设置一个函数来接受一个参数并运行.handle_response行而不在每个函数中设置它?

2 个答案:

答案 0 :(得分:2)

您可以定义一个新函数,该函数接受函数名称以及参数,并且该函数将在最后输入ResponseHandler.handle_response(@model_module)。以下代码未经测试但应该有效:

def find(client) do
  go(:find, [client, @resource])
end

def find(client, identifier) do
  go(:find, [client, @resource, identifier])
end

...

def go(function, args) do
  apply(Common, function, args)
  |> ResponseHandler.handle_response(@model_module)
end

如果需要,您还可以自动注入@resource作为第二个参数:

def find(client) do
  go(:find, [client])
end

def find(client, identifier) do
  go(:find, [client, identifier])
end

...

def go(function, [head | tail]) do
  apply(Common, function, [head, @resource | tail])
  |> ResponseHandler.handle_response(@model_module)
end

您可以使用宏/元编程进一步减少这一点,但如果您只有5个案例,我不推荐它,因为它使代码复杂化。我会选择第一个解决方案,因为它是最简单的解决方案。

答案 1 :(得分:1)

如果这是真正的代码,意味着函数是来自另一个具有相同名称并散布有@resource参数列表的模块的函数的包装器,那么可以动态地定义它们:

functions =
  [find: ~w|client|a,
   find: ~w|client identifier|a,
   filter: ~w|client filter|a,
   create: ~w|client bank_transactions_map|a,
   update: ~w|client identifier bank_transactions_map|a]

Enum.each(functions, fn {fun, args} ->
  args = Enum.map args, &{&1, [], Elixir}
  wrapped_args = with [h | t] <- args,
    do: [h | [ quote(do: @resource) | t ]] # inject @resource
  def unquote(fun)(unquote_splicing(args)) do
    Common 
    |> apply(unquote(fun), unquote(wrapped_args))
    |> ResponseHandler.handle_response(@model_module)
  end
end)

如果包装不是那么纯粹,那么要包装的函数的初始列表应该扩展为[find: [params: [...], as: :search]

这种方法的优点是,一旦函数 producer 被编写并经过充分测试,添加新的包装就像更新配置文件一样简单。