3

我正在为共享许多相同功能的 webmachine 编写几个资源。所以我想知道是否可以在单独的模块中编写常用函数,然后以某种方式包含它,并使其导出由资源自动导出(无需显式从每个资源中导出它们)。

4

4 回答 4

3

我们有一个包装器模块,它实现所有 Webgear 回调,如果它们在那里实现,则将它们传输到真正的实现模块。该模块可以对某些部分进行特殊实现,甚至可以在使用它的模块中启用新的回调。基本上,该模块是所有其他资源的包装资源。

首先,您的调度地图如下所示:

[{"/some/path", webgear_wrapper, {actual_resource, ["Some", extra, "Args"]}}].

为此,您需要发现您的实际实现模块实现了哪些回调:

-record(context, {module, context, exports}).

init({Mod, Args}) ->
    {ok, Context} = Mod:init(Args),
    {ok, #context{module = Mod, context = Context, exports = exports(Mod)}}.

exports(Mod) ->
    dict:from_list(Mod:module_info(exports)).

这将初始化一个基本的 Webgear 资源,该资源具有关于处于其状态的真实回调模块的信息。

然后,对于包装器资源的每个回调(如果您希望实现模块能够使用,则必须实现),您将查看该函数是否已实现并在那里处理它,使用此函数:

call(#context{module = Mod, context = Cxt, exports = Exports},
     Func, Req, Default) ->
    case dict:is_key(Func, Exports) of
        true  -> Mod:Func(Req, Cxt);
        false -> {Default, Req, Cxt}
    end.

call/4例如,该函数在 wrapper 模块中使用如下:

malformed_request(Req, Cxt) ->
    % false here is the default value to return if the callback is missing
    {Res, NewReq, NewCxt} = call(Cxt, malformed_request, Req, false),
    % Now we must update the state accordingly
    {Res, NewReq, Cxt#context{context = NewCxt}}.

这在我们的项目中运行良好,所有资源共享一些公共逻辑(在这样的包装模块中实现)。虽然没有对性能进行太多基准测试,但开销应该相当小(一个字典查找和一个额外的模块调用,加上一些记录争论)。

于 2011-02-21T08:40:33.253 回答
2

实际上这是可能的,但只能通过未记录的功能。模块继承。

于 2011-02-20T04:05:06.440 回答
1

是的,您可以使用混音器库,https://github.com/opscode/mixer,它是一个编译器解析转换,可以完全按照您的意愿进行操作。我到处使用它来进行网络机器回调

于 2013-09-09T08:23:58.597 回答
0

不,这是不可能的。我所做的是将我的应用程序所需的所有回调实现到通用函数。另一种方法是修补 webmachine 以从函数中获取 cb,而不是通过查看导出。

于 2011-02-19T16:45:52.107 回答