A Day in the Life

2008-06-05

has_many :through で別DBの model を設定

内部的に INNER JOIN してるのでエラってひけないなー。Rails 2 でも DB は一つ的な思想なんだろうか。

LazyLoader Mixin

のをもうちょっと汎用的に使えるように拡張。

class Foo
  include LazyLoader
  lazy_reader :bar
  def bar
    sleep 1
    'bar variable'
  end
end

f = Foo.new
puts f.bar
puts f.bar # 二回目は結果がすぐ返る

しかしこの程度では

class Foo
  def bar
    unless @bar
      sleep 1
      @bar = 'bar variable'
    end
    @bar
  end
end

でも別にいいじゃん、ということになる。実際は Fiber もしくは Thread (1.8 の Thread でうまくできるかは知らない) 切り替わりのタイミングで、とある Module を include したクラスの LazyLoading を一気に非同期でロードしたい。

cho さんに教えて貰った Io の

a := @foo

みたいなのを手軽にやりたいんだよなー。これができると、Web アププフレームワークで、DB や http から取得等の非同期で平行して走られ、かつ一番時間かかる処理を同時に行える。コントローラ側では意識せずに書くことができ、(erb なら)テンプレートで呼び出されるときにまだ処理が終わってなければそこで処理が終わるまで待ち受けられる。コントローラ処理が終わったらコンテキスト変えて、とかのタイミングで非同期ロード開始すれば実装的にはできそう。

というのが次の世代のWebアプリケーションフレームワークでは標準(頭使わなくて非同期でどんどん書ける)になりそうな気がしてるんだけどどうだろう。もう知らないだけで、そういう実装結構出てきてるのかな。

以下拡張したやつのソース。

module LazyLoader
  module ClassMethods
    attr_accessor :lazy_reader_methods
    def method_added(method_name)
      if self.lazy_reader_methods.keys.include?(method_name) && !self.lazy_reader_methods[method_name]
        lazy_method method_name
      end
    end

    def lazy_reader(*method_names)
      self.lazy_reader_methods ||= {}
      method_names.each do |name|
        self.lazy_reader_methods[name.to_sym] = nil
      end
    end

    def lazy_method(*method_names)
      method_names.each do |method_name|
        closure = instance_method method_name
        self.lazy_reader_methods[method_name] = closure
        define_method(method_name) do
          iv_name = "@#{method_name}"
          unless instance_variables.include? iv_name.to_sym
            self.instance_eval "#{iv_name} = nil"
            instance_variable_set iv_name, closure.bind(self).call
          end
          instance_variable_get iv_name
        end
      end
    end
  end

  def self.included(base)
    base.extend ClassMethods
  end
end

iPod

新品になって戻ってきた\(^o^)/

ハト問題

またつがいの鳥があらわれやがった、、、ぜ、、、、

記事の一覧 >