2016-04-05 8 views
4

特定の動作を採用した各ロード済みモジュールを見つけることは可能ですか?動作を採用したすべてのモジュールを見つける

私は非常に簡単なチャットボットを構築していると私はいくつかのクールなコマンドを作りたいが、私は、好ましくは、それらをハードコーディングすることなく、複数のコマンドを実装する方法が必要であることを達成します。

各コマンドは、3つのparams(メッセージ、作者、chat_channel_ref)を取り、それが一致するかどうかをtrueまたはfalseを返し、何かをする機能になります。

私は私がそれらを採用しているすべてのモジュールを発見したことができれば、うまく自分のニーズに合わせて Behaviorsたエリクサーのチュートリアルを閲覧します。あなたの誰かが前にそれをしたことがありますか?他に何ができますか?私はまた、 "使用"について考えました(私はエージェントが保有するリストに現在のモジュールを追加するコードを実行します)。

+1

これらのうちどれくらいをお持ちになりますか?たぶんソースコードのどこかに、おそらくスーパーバイザー仕様の中にそれらのリストを保持して、それぞれが別のプロセスで実行する方が簡単かもしれません。 –

答えて

6

これは基本的に正確に行い、私のexrmプロジェクト、からの抜粋です:それは、プラグインの動作を実装する任意のモジュールを見つける:行動に類似している検討する

@doc """ 
    Loads all plugins in all code paths. 
    """ 
    @spec load_all() :: [] | [atom] 
    def load_all, do: get_plugins(ReleaseManager.Plugin) 

    # Loads all modules that extend a given module in the current code path. 
    @spec get_plugins(atom) :: [] | [atom] 
    defp get_plugins(plugin_type) when is_atom(plugin_type) do 
    available_modules(plugin_type) |> Enum.reduce([], &load_plugin/2) 
    end 

    defp load_plugin(module, modules) do 
    if Code.ensure_loaded?(module), do: [module | modules], else: modules 
    end 

    defp available_modules(plugin_type) do 
    # Ensure the current projects code path is loaded 
    Mix.Task.run("loadpaths", []) 
    # Fetch all .beam files 
    Path.wildcard(Path.join([Mix.Project.build_path, "**/ebin/**/*.beam"])) 
    # Parse the BEAM for behaviour implementations 
    |> Stream.map(fn path -> 
     {:ok, {mod, chunks}} = :beam_lib.chunks('#{path}', [:attributes]) 
     {mod, get_in(chunks, [:attributes, :behaviour])} 
    end) 
    # Filter out behaviours we don't care about and duplicates 
    |> Stream.filter(fn {_mod, behaviours} -> is_list(behaviours) && plugin_type in behaviours end) 
    |> Enum.uniq 
    |> Enum.map(fn {module, _} -> module end) 
    end 
+0

これはランタイムのみですか? – Haito

+0

コンパイル時にも同じコードを実行することができますが、これにはいくつかの注意点があります(私はその必要はありません)。exrmの場合は不要です。また、アプリケーション環境で最初に実行したときに結果をキャッシュすることで、結果をキャッシュすることもできます。それは本当にどのくらい頻繁に呼び出される必要があるかによって異なります。 – bitwalker

0

別のオプションはProtocolsです。プロトコルを作成すると、新しいコマンドごとにそのプロトコルを実装する必要があります。

+0

ええ、私は考えました。しかし、プロトコルはtyprごとに実装されています(リストなどの場合)。そして、各関数の意味は同じです。 – Haito

0

私は、彼らが特定の 関数呼び出しをサポートしている場合のみ、プラグインをロードするライブラリを書きました。行動はエリクシールで減価償却されますが、アーラン法の@behaviourはまだサポートされていますが、あなたが期待するよりもはるかに少ないものを購入します。 (関数シグネチャがない場合は、コンパイル時の警告のみです)。

https://github.com/bbense/pluginator

+0

あまりにも非難されています。 – Haito

+0

ElixirのBehavior "macro"は、@behaviourモジュール属性を使用するだけで廃止予定です。機能はまだ残っていますが、Elixirのラッピングは、それを正当化するのに十分有用なものが追加されていないと判断されたため、削除されました。 –

関連する問題