11

Mixin として使用するモジュールでインスタンス変数を初期化するクリーンな方法はありますか? たとえば、次のものがあります。

module Example

  def on(...)   
    @handlers ||= {} 
    # do something with @handlers
  end

  def all(...)
    @all_handlers ||= []
    # do something with @all_handlers
  end

  def unhandled(...)
    @unhandled ||= []
    # do something with unhandled
  end

  def do_something(..)
    @handlers     ||= {}
    @unhandled    ||= []
    @all_handlers ||= []

    # potentially do something with any of the 3 above
  end

end

各関数でそれぞれが適切に初期化されているかどうかを何度も確認する必要があることに注意してください@member。これは少しイライラします。私はむしろ書きたい:

module Example

  def initialize
    @handlers     = {}
    @unhandled    = []
    @all_handlers = []
  end

  # or
  @handlers  = {}
  @unhandled = []
  # ...
end

また、物事が正しく初期化されていることを繰り返し確認する必要はありません。しかし、私が言えることから、これは不可能です。initialize_meメソッドを追加して拡張クラスからExample呼び出す以外に、これを回避する方法はありますか? initialize_me私はこの例Classを見ましたが、これを達成するためだけにモンキーパッチを適用する方法はありません。

4

4 に答える 4

13
module Example
  def self.included(base)
    base.instance_variable_set :@example_ivar, :foo
  end
end

編集:これはクラスインスタンス変数を設定していることに注意してください。モジュールがクラスに混在している場合、インスタンスはまだ作成されていないため、インスタンスのインスタンス変数を作成することはできません。ただし、ミックスインで初期化メソッドを作成することはできます。例:

module Example
  def self.included(base)
    base.class_exec do
      def initialize
        @example_ivar = :foo
      end
    end
  end
end

インクルードクラスのinitializeメソッド(誰か?)を呼び出しているときにこれを行う方法があるかもしれません。わからない。しかし、ここに別の方法があります:

class Foo
  include Example

  def initialize
    @foo = :bar
    after_initialize
  end
end

module Example
  def after_initialize
    @example_ivar = :foo
  end
end
于 2012-09-25T15:24:34.393 に答える
2

おそらくこれは少しハックですが、使用prependして目的の動作を得ることができます。

module Foo
  def initialize(*args)
    @instance_var = []
    super
  end
end

class A
  prepend Foo
end

コンソールからの出力は次のとおりです。

2.1.1 :011 > A.new
 => #<A:0x00000101131788 @instance_var=[]>
于 2014-04-07T04:41:37.497 に答える
1

modulesとしてフックを提供しますModule#included。このトピックに関する ruby​​ doc を確認するActiveSupport::Concernか、モジュールに関するいくつかのヘルパーを提供する を使用することをお勧めします。

于 2012-09-25T15:26:01.770 に答える