【问题标题】:Elixir rename and wrap Erlang module?Elixir 重命名和包装 Erlang 模块?
【发布时间】:2014-10-30 21:49:42
【问题描述】:

是否可以重命名现有的 Erlang 模块?我想在 Elixir 项目(断言库)中使用几个 Erlang 模块中的一些代码。

我不想将所有 Erlang 模块都转换为 Elixir,因为它们是完整的,但我想重命名它们,并可能向它们添加额外的功能。这两个模块都是简单的函数集合,它们不实现行为或做任何不寻常的事情。

我希望能够采用现有的 Erlang 模块:

-module(foo_erl).

-export([some_fun/1]).

some_fun(Arg) ->
  ok.

并编写一个 Elixir 模块来扩展 Erlang 模块:

defmodule ExFoo do
   somehow_extends_erlang_module :foo_erl

   another_fun(arg) do
     :ok
   end
end

然后就可以使用Erlang模块中定义的函数了:

iex(1)> ExFoo.some_fun(:arg) #=> :ok

这可以在 Elixir 中实现吗?如果是这样,我该怎么做?

【问题讨论】:

    标签: module erlang elixir


    【解决方案1】:

    一般来说,我们建议避免包装 Erlang 模块。如果您想以自动方式包装许多模块,velimir 的帖子就在现场。

    如果你有一次性的情况,你肯定想包装一个 Erlang 模块,我建议简单地使用defdelegate

    defmodule MyLists do
      defdelegate [flatten(list), map(fun, list)], to: :lists
    end
    

    【讨论】:

    • 我有 3 个模块也需要这样做,但我选择使用 defdelegate,因为它使包装变得明确。当有人打开MyLists 模块时,他们将确切知道 flatten/1 的定义位置。
    【解决方案2】:

    这是我可以建议的第一件事。我 100% 确信它可以以更优雅的方式解决。因为我还不是 Elixir 大师,所以我稍后会回到这个问题。

    defmodule Wrapper do
      defmacro __using__(module) do
        exports = module.module_info[:exports] -- [module_info: 0, module_info: 1]
        for {func_name, arity} <- exports do
          args = make_args(arity)
          quote do
            def unquote(func_name)(unquote_splicing(args)) do
              unquote(module).unquote(func_name)(unquote_splicing(args))
            end
          end
        end
      end
    
      defp make_args(0), do: []
      defp make_args(arity) do
        Enum.map 1..arity, &(Macro.var :"arg#{&1}", __MODULE__)
      end
    end
    
    defmodule WrapperTest do
      use ExUnit.Case, async: true
    
      use Wrapper, :lists
    
      test "max function works properly" do
        assert (max [1, 2]) == 2
      end
    end
    

    【讨论】:

      猜你喜欢
      • 2013-12-05
      • 2017-12-13
      • 2015-11-29
      • 2021-12-18
      • 2016-10-20
      • 1970-01-01
      • 2016-07-10
      • 2013-06-25
      • 2023-03-27
      相关资源
      最近更新 更多