hpricot-0.6.164 @ ruby 1.9.1-p0

ようやく入った hpricot を本番に投入したところ、今度は ruby コードの方でエラーを出力してくれた。

d:/ruby/lib/ruby/gems/1.9.1/gems/hpricot-0.6.161/lib/hpricot/elements.rb:306:in `block in filter': wrong number of arguments (1 for 0) (ArgumentError)
        from d:/ruby/lib/ruby/gems/1.9.1/gems/hpricot-0.6.161/lib/hpricot/elements.rb:304:in `each'
        from d:/ruby/lib/ruby/gems/1.9.1/gems/hpricot-0.6.161/lib/hpricot/elements.rb:304:in `find_all'
...

テキストノードを抽出する XPath ステートメントを与えただけなのだが、一体これは……?
elements.rb:306 付近を見てみるとこんな感じになっていた。

nodes = Elements[*nodes.find_all do |x| 
                      i += 1
                      x.send(meth, *([*args] + [i])) ? truth : !truth
                  end]

ふむふむ、各ノードに対してメッセージを送信して、true なノードを抽出しているわけだ。で、そのメッセージ=メソッドの引数が一致しなくてエラーが出ていると。
伝統の printf デバッグかまして エラー手前の meth の内容を見てみると、"filter[text]" なるメソッド名だった。filter[ほにゃらら] というメソッドは define_method で定義されているようだ。

  module Traverse
    def self.filter(tok, &blk)
      define_method("filter[#{tok.is_a?(String) ? tok : tok.inspect}]", &blk)
    end

その下にはずらりと、「filter なんとか」が並んでいる。text の filter を定義しているところを探してみると、すぐに見つかった。

    filter 'text' do
      self.text?
    end

メッセージ送信時に渡しているパラメータは *([*args] + [i]) なので、少なくとも1以上の引数であることが期待されている一方で、この text filter は引数が 0 個。そりゃ通らないわけだ。ruby 1.8 ではこれらのコードはエラーが出ないのだが、調べてみると、どうやら define_method の ruby 1.8 専用仕様(?)で、引数の数が一致して無くても良きに計らうようになっていたようだ。
他の幾つかのフィルタもそんな調子で引数が省略されていた。まだ使ったことの無いものばかりだが、地雷であることは間違いない。これら地雷群に対して |ignore| なる仮引数を付けておいた。これで今後、爆発することはないだろう。
とりあえず、エラーが出ていた XPath も普通に使えるようになった。これでようやく一安心……出来ると良いのだが。