影武者(kagemusha)というスタブフレームワークはテスト時以外にも使えるかも…
Time.nowのテスト? それMochaでできるよ - http://rubikitch.com/に移転しましたを書いてるとid:ujihisaより「kagemusha」というgemを教えてもらった。
require 'rubygems' require 'kagemusha' birthday = Time.local(1993, 2, 24) Time.now # => Tue Jun 03 01:59:14 +0900 2008 Kagemusha.new(Time).defs(:now) { birthday }.swap do Time.now # => Wed Feb 24 00:00:00 +0900 1993 end
Kagemusha#defはインスタンスメソッドの定義をすりかえ、Kagemusha#defsはクラスメソッドの定義をすりかえる。これらはselfを返す。
で、Kagemusha#swapの間だけすりかえを実行する。まさしく影武者だ。
こんなのだからテスト時以外にも使えそうだ。
「Kagemusha - a library of testing mock-objects」とは書いているけど、引数等のチェック機能がないからスタブフレームワークだと思う…
ザ・ワールドもこの通り。
require 'rubygems' require 'kagemusha' now = Time.now Kagemusha.new(Time).defs(:now) { now }.swap do # ザ・ワールド! Time.now # => Tue Jun 03 02:08:06 +0900 2008 sleep 2 Time.now # => Tue Jun 03 02:08:06 +0900 2008 end # そして時は動きだす Time.now # => Tue Jun 03 02:08:08 +0900 2008
影武者のソースコードを読んで初めてModule#define_methodの第2引数を知った(^^; 遅すぎ…
第2引数にUnboundMethodも受け付けるから、Module#instance_methodと組み合わせれば自由自在にメソッドを書き換えられる。aliasで退避するのはかっこ悪くて嫌。
class X def hoge() :X end end class Y < X def hoge() :Y end end class Z < Y define_method(:hoge, X.instance_method(:hoge)) end X.new.hoge # => :X Y.new.hoge # => :Y Z.new.hoge # => :X
こういうことができるから、やっぱりメソッドもオブジェクトなんだなぁーと感じる。