LazyArray作ってみた
ヽ( ・∀・)ノくまくまー(2008-12-02) 優しいMerbの育て方にて紹介されているLazyArrayクラス。
ソースを見たところ何故かArrayのサブクラスじゃないで、もしArrayのサブクラスとして実装してみたらどうなるかというのをやってみた。
- まず初期値はブロックで渡すのは基本だよな。
- そのブロックを実行して初期化するメソッドを作って……
- Arrayの全部のメソッドの前でその初期化メソッドを実行すればいいわけだ。
- でも毎回loadedフラグ見るのダサいよな……
- 初期化が終わったらremove_methodしてArrayのメソッドに戻せばいいんじゃね?
- そうすると上書きメソッドは全部シングルトンだよな。class << selfっと。
- いちいち全部定義するの面倒だからdefine_methodだよな。
- Arrayにのみ定義されてるインスタンスメソッドを取るには、Array.instance_methods(false)か。
- よし、動いた!
- EnumerableのメソッドはArray#eachが必ず呼ばれるから定義しなくて大丈夫だよな。
- それ以前にArray#each単体でセグった!
- と思ったらdefine_methodでblockを受け取るようにしてなかったのが問題だった。 <- imkk
と、舞波メソッドで現状を表現してみました。
環境
C:ruby>ruby -v ruby 1.9.0 (2008-10-04 revision 19669) [i386-mswin32]
LazyArray class
class LazyArray < Array OVERWRITE_METHODS = Array.instance_methods(false) def initialize &block @block = block class << self OVERWRITE_METHODS.each do |method_name| define_method method_name do |*args, &block| lazy_load super *args, &block end end private def lazy_load class << self remove_method *OVERWRITE_METHODS remove_method :lazy_load end if @block.arity == 0 replace @block.call else @block.call self end end end end end
補足
単純に技術的興味でやったので使えるかどうかは正直良くわからない。
define_methodとremove_methodのコストとEager loadingのコストを比較してないのでパフォーマンスも疑問。
remove_methodの使いどころがわかったような気がするのが収穫か。