読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

Needleのインターセプタ機能を試す

Needleのインターセプタ機能を使ってみます。

  • Seasarなどで提供されているメソッドインターセプタの機能が利用できます。
  • 専用のインターセプタクラスを用意して適用するほか、ブロックを使って簡単にフック処理を指定することも可能です。

ブロックを使ったインターセプタの適用

ブロックを使ってメソッドの呼び出しの前と後でメソッド名と引数を出力するインターセプタを適用するサンプルです。

  • 「registry.intercept( <インターセプタを適用するサービス名> ).doing { <インターセプタの処理> }」でサービスにインターセプタを適用します。
  • ブロックには、「chain」と「context」が引数で渡されてきます。
    • contextはフックしたメソッド名やメソッドの引数などが格納されるオブジェクトです。
    • 「chain.process_next( 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!