1

これに似た質問があります。アドオンシステムを備えたアプリを書いています。アドオンミックスインモジュールがあります。これは、それが含まれていることを検出し、新しいアドオンを自動的に登録します。

module Addon
  def self.included(receiver)
     addon = receiver.new   # Create an instance of the addon
     (snip)                 # Other stuff to register the addon 
     addon.on_register      # Tell the instance it was registered
  end
end

ミックスインの使用例は次のとおりです。

class MyAddon
  def on_register
    puts "My addon was registered"
  end
  include Addon  # ** note that this is at the end of the class **
end

上記のように、この実装では、インクルードがクラスの最下位にある必要があります。それ以外の場合、self.includedが呼び出されるときにon_registerは定義されません。

私の懸念は、アドオン開発者が誤ってインクルードを一番上に置き、アドオンが機能しなくなる可能性があることです。または、派生クラスなど、MyAddonクラスが既に含まれている後に拡張するものがある可能性があります。

これについてもっと良い方法はありますか?

4

3 に答える 3

2

私が見つけた他の答えと他のいくつかの情報を抽出した後、私は私のために働くことになった答えを文書化したいと思いました。

この質問で説明されているように、クラスが定義されていることをinclude()時に検出することはできません。したがって、オブジェクトを作成するために「included」コールバックに依存することは、あまり堅牢なソリューションではありませんでした。

代わりに、解決策は、すべてのアドオンを検出し、すべてがロードされた後にそれらをインスタンス化することでした。アドオン開発者に課せられた唯一の制約は、彼らのコードが共通のトップレベルのモジュール名前空間を共有しなければならないということでした。

これが最善の方法かどうかはまだわかりませんが、私が始めた方法よりも間違いなくうまく機能します。

モジュールでアドオンを検索するコードは次のとおりです。渡された名前空間から開始し、アドオンクラスを含むクラスを再帰的に検索します。

def find_and_instantiate(mod, addons)
   consts = mod.constants
   consts.each do |c|
     sym = mod.const_get(c)
     if (sym.class == Module)
       find_and_instantiate(sym, addons)
     else
       if (sym.class == Class && sym.include?(Addon))
         addons << sym.new(@container)            
       end
     end        
   end
 end
于 2012-11-11T14:17:50.320 に答える
1

私が思いつくことができる最善の方法は、#on_registerメソッドが宣言された後にモジュールを含める必要があることをモジュールのユーザーに通知することです。

module Addon
  def self.included(receiver)
        raise "include #{self.name} after the #on_register method is defined" unless receiver.method_defined? :on_register
        receiver.new.send(:on_register)
  end
end

これは理想的とは言えませんが、これを行うためのより良い方法を見つけるまで、間違いを悪化させることを防ぎます。

于 2012-11-11T02:28:14.137 に答える
-1

申し訳ありませんが、これをお渡しする必要があります。だからあなたはあなたのコードが賢いのを聞きたいのです。はい、そうです、それはあまりにも賢いです。しかし、他の開発者のことを心配したい場合は、賢くするのをやめて、普通になり始める必要があります。

Rubyはオブジェクト指向言語です。OOPの基本は、最初にオブジェクト構造とそのメソッドを定義し、次にすべてが定義されたら、MyApp.newを1回呼び出すだけで自分の世界を理想的にインスタンス化することです。そうすれば、私が最初に何を定義したかは問題ではありません。'include'呼び出しは、モジュール継承階層を確立するのに役立ちますが、それ以外は何もしません。

しかし、いいえ、あなたはOOPをしたくありません。フックを悪用してその中のincludedレシーバー(!)をインスタンス化し、そのインスタンスメソッドを呼び出します。それが彼らが難読化されたコードと呼んでいるものです。言い換えれば、OOPから古い良いgotoスタイルのディレクティブプログラミングに戻ります。Rubyを使用すると、能力を制限するのではなく、難読化することができますが、大きな力と大きな責任を持って、あなた自身が節度を発揮する必要があります。

コードを正常にするには、コードをリファクタリングする必要があります。あなたが何を達成したいのかわからないので、私たちはあなたのためにそれをすることはできません。誰が知っている、多分あなたの考えは天才に値する。残念ながら、あなたの質問からはわかりません。あなたが持っているいくつかのアドオンシステム。私はあなたに尋ねています:あなたはそれが必要ですか?古き良きミックスインシステムはあなたにとって十分ではありませんか?RubyでJavaをプログラミングしていませんか?そして、あなたのアプリはRailsよりも大きくなるのでしょうか?はいの場合は、アドオンシステムを使用してください。そうでない場合は、事前に分離できないアドオンシステムを作成するのではなく、遊んでみるのをやめて、アプリが想定していることを実際に実行するアルゴリズムの作成に時間を費やしてください。あなたが会社で働いているなら(私は疑いますが)、上司にこれを読ませてください。

于 2012-11-11T02:28:10.133 に答える