キャッシュ対応のWikiquote

Wikiquoteから1つ引っ張ってきて表示するスクリプトを書き換えた。毎回ネットワークにアクセスするのもバカらしいので、1度に持ってこれる5、6個の引用(HTMLで1枚分)を~/.quotesに保存するようにした。このファイルに引用が存在する限り、ネットワークに見に行くことなく、即座に引用を表示する。.quotesの残りが4個以下になると、とりあえず1つ引用を表示した後にネットワークに追加分の引用を取りにいく。

もしかして、この程度のものでもSQLiteとか使うべきなのかと思った。性能的な問題よりも、実装者のスキルセットの蓄積や使いまわしまで考えると、SQLiteとか良さそう。

最近、Android端末を手に入れたので、モバイル端末でWikiquoteを表示するプログラムでも作ってみようかと思っている。端末を左右にふると、おみくじのようにランダムに引用を表示する。で、実はWikiquote自体へのリンクのほかにもAmazonへのリンクを埋め込んでおいて、その発言をした人に関する本がすぐに買えるようにしておく。で、アフィリエイトでうはうは……うは。

#!/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
    cache
  end

  def cache
    if @q.size <= 4
      @q += get_quote(fortune)
    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 fortune
    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
  w.cache
  w.show
  w.store
end

しかし、これ、どうしてもネットワークを見に行くときにはコマンドラインに戻ってくるのに時間がかかる。本当はキャッシュに読み込む動作と表示系は非同期的にするのが吉。そうするとこのRubyスクリプトをベースに実行スクリプトを2つ用意して、「$ cache & show」と並列に実行すべきじゃないかと思った。