多くの同じ機能を共有する webmachine 用のリソースをいくつか書いています。したがって、一般的な関数を別のモジュールに記述し、何らかの方法でそれを含めて、そのエクスポートをリソースによって自動的にエクスポートすることが可能かどうか疑問に思っています (すべてのリソースから明示的にエクスポートする必要はありません)。
4 に答える
すべての 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
関数は、たとえば、ラッパー モジュールで次のように使用されます。
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}}.
これは、すべてのリソースがいくつかの共通ロジックを共有するプロジェクトでうまく機能します (このようなラッパー モジュールで実装されます)。ただし、パフォーマンスのベンチマークはあまり行っていませんが、オーバーヘッドはかなり小さいはずです (1 つの dict ルックアップと 1 つの追加モジュール呼び出し、およびいくつかのレコード ラングリング)。
実際には可能ですが、文書化されていない機能を介してのみ可能です。モジュールの継承。
いいえ、できません。私がしたことは、アプリが必要とするすべてのコールバックをジェネリック関数に実装することでした。もう 1 つの方法は、エクスポートを調べる代わりに、関数から cb をフェッチするように webmachine にパッチを当てることです。