Needleのインターセプタ機能を試す
Needleのインターセプタ機能を使ってみます。
ブロックを使ったインターセプタの適用
ブロックを使ってメソッドの呼び出しの前と後でメソッド名と引数を出力するインターセプタを適用するサンプルです。
- 「registry.intercept( <インターセプタを適用するサービス名> ).doing { <インターセプタの処理> }」でサービスにインターセプタを適用します。
- ブロックには、「chain」と「context」が引数で渡されてきます。
require 'rubygems' require 'needle' # レジストリに登録するサービスクラス class Kitten def initialize(name) @name = name end def meow( count ) puts "#{@name} : #{'meow!' * count}" end end # レジストリ registry = Needle::Registry.define {|builder| builder.mii { Kitten.new("mii") } } # サービス「mii」の前後でメソッド名と引数を出力するインターセプタ registry.intercept( :mii ).doing {|chain,context| # コンテキストは以下の属性を持つ。 # context.sym : メソッド名 # context.args : 引数 # context.block : ブロック # context.data : インターセプタ間で共有するデータ begin puts "before.. #{context.sym}( #{context.args.join(", ")} )" chain.process_next( context ) # 次のor本来の処理を実行 ensure puts "after.. #{context.sym}" end } # サービスの取得とメソッドの実行。 mii = registry[:mii] mii.meow(3)
実行結果です。
before.. meow( 3 ) mii : meow!meow!meow! after.. meow
クラスを使ったインターセプタの適用
専用のクラスを用意してインターセプタを適用する例です。ブロックを使うやり方と比べて、インターセプタの再利用が容易なのがメリット。なお、クラスは、Needleの世界では「InterceptorFactory」と呼ばれていますが、内容はAOP Alliance における MethodInterceptorです。なんでFactoryなのかは疑問。
- インターセプタクラスは以下のメソッドを実装する必要があります。
- あとは、「registry.intercept( <インターセプタを適用するサービス名> ).with( <インターセプタクラス> )」でサービスにインターセプタを適用できます。
# インターセプタクラス(Needleではインターセプタファクトリと呼ばれる。) class RepeatInterceptor # コンストラクタ def initialize( point, options ) # pointは「Needel::ServicePoint」のインスタンス # optionsでインターセプタ登録時に指定したパラメータが渡されてくる。 @count = options[:count] || 3 end # サービスのメソッドが実行された場合の処理を記述するメソッド def process( chain, context ) @count.times { # オプションで指定された回数 chain.process_next( context ) # 本来の処理を実行 } end end # サービス「mii」にRepeatInterceptorを登録。 registry.intercept( :mii ).with { RepeatInterceptor } # ↓のような感じで、オプションを渡すことができる。 #registry.intercept( :mii ).with { RepeatInterceptor }.with_options( :count=>5 ) # サービスの取得とメソッドの実行。 mii = registry[:mii] mii.meow(3)
実行結果です。
mii : meow!meow!meow! mii : meow!meow!meow! mii : meow!meow!meow!