2012-01-31 9 views
2

私は、APIを定義する複数の抽象クラスと属性のメソッドを提供するサブクラスを持つ特定の実装を持つプラグインスタイルのアーキテクチャを持つアプリケーションで作業しています抽象クラスで定義されています。 Connection、Table、Columnなどの抽象クラスと、特定のデータベースに対するこれらの特定のサブクラスを持つ汎用データベースアダプタを考えてみましょう。クラスレベルの動的メソッド作成をルビのモジュールに移す

DRYを試みるために、各抽象クラスの属性(デフォルト値)をATTRIBUTESというクラス定数配列として宣言します。 Rubyは真の抽象クラスをサポートしていないので、抽象クラスで呼び出された場合に例外を発生させるメソッドを動的に作成します。たとえば、次のように

module MyApplication 
    class Operation 
    ATTRIBUTES = { name: '', parameters: [], type: :void } 
    ATTRIBUTES.keys.each do |a| 
     str = "Method '%s' called on abstract 'MyApplication::Operation' class" 
     define_method(a) { raise (str % a) } 
     define_method("#{a}=") { |x| raise (str % "#{a}=") } 
    end 
    end 
end 

Iハードコードそれが抽象Operationクラスのサブクラスであるかもしれない、と私はメッセージにしたいので、私は、現在のクラスの名前を使用することはできませんので、メッセージ内のクラス名呼び出されているメソッドが抽象クラスにあることを明示してください。

私はこれらの抽象クラスをいくつも持っています。これらのスタブメソッドを作成するために、ほとんど同じコードをコピーしました(属性リストとクラス名だけが異なります)。私は、この抽象クラスからインクルード(または拡張)できるモジュールにこのコードを組み込むためのさまざまな方法を試しましたが、私の脳はここで折り畳まれ、メタプログラミングの詳細を整理しようとしています働く:)

同じコードを何度も何度も繰り返さないようにするために、この共通のクラスレベル(インスタンス作成のメソッド)コードをモジュールに取り込む人はいますか?

答えて

2

これ欲しいものを行う必要があります。私はまだ混乱している場合を除き、

module PluginHelpers 
    def stub_required_methods(*method_names) 
    method_names.each do |method_name| 
     define_method(method_name) do 
     raise NotImplementedError, "Method #{__method__} must be implemented in #{self.class}" 
     end 
    end 
    end 
end 

class A 
    class B 
    class C 
     extend PluginHelpers 
     stub_required_methods(:foo, :bar) 
    end 
    end 
end 

# usage 
A::B::C.new.foo # => NotImplementedError: Method foo must be implemented in A::B::C 
+0

これはそれらすべてが終わるすべてのクラスで定義されているになるだろうこれは、*モジュール*にスタブメソッドを追加しませんPluginHelpersを拡張しますか?私は、この作業が望ましくない副作用を持つようになったという試みの(多くの)反復の1つのように感じます。 –

+0

私はあなたの懸念を理解していますか分かりません。私が書いたコードをとり、あなたの特定のユースケースのために試してみよう。 –

+0

私はそれを動作させるのに苦労していましたが、それはパスと 'require'に問題があることが判明しました。今働いているようですので、助けてくれてありがとう! –