スレッドで読み込み

Rubyのスレッドは並列実行はサポートしていないので、CPUバウンドなボトルネックに対しては効果がないけど、IOバウンドなものに対しては有効だという話。Wikiquoteはネットワークが遅いので、やってみた。シンプルで分かりやすい。

#!/usr/local/bin/ruby 
require 'open-uri' 
require 'hpricot'
require 'fileutils'

QUOTE_FILE = File.expand_path("~/.quotes")

class Wikiquote

  attr_accessor :q

  def initialize
    @q = []
  end

  def show
    cache if @q.size == 0
    puts @q.shift
  end

  def cache
    if @q.size <= 4
      @q += get_quote(date)
    end
  end

  def load
    if(File.exists?(QUOTE_FILE))
      @q += File.new(QUOTE_FILE).read.split("\n@@\n")
    end
  end

  def store
    File.open(QUOTE_FILE, "w") do |f|
      f.write(@q.join("\n@@\n"))
    end
  end

  def get_quote(date)
    q = []
    
    doc = Hpricot(open("http://en.wikiquote.org/wiki/#{date}"))
    doc.search("dl").each do |dl|
      dd = dl.search("dd")
      dd.search("ul").remove
      q << dd.inner_html.strip.gsub(/<[^>]+>/,"").gsub("~","---")
    end

    q.delete("") # for some reasons...
    q.pop; q # so as not to output whitespace

  end
 
  def date
    srand
    months = %w(January February March April May June July
              August September October November December)
    months.shuffle.pop + "_" + (rand(28).to_i + 1).to_s
  end
end

if $0 == __FILE__
  w = Wikiquote.new
  w.load
  t = Thread.new do 
    w.cache
  end
  w.show
  t.join
  w.store
end