忘れたときに備えた記録

トップ 最新 追記
2005|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|11|12|
2009|01|02|03|04|05|06|10|12|
2010|06|07|08|12|
2011|07|09|
2012|09|11|
2013|02|03|09|
2015|10|11|
2016|01|08|11|
2017|02|08|10|
2018|11|

2008-09-06(Saturday)

lax_uri.rb - uriライブラリの制限緩い版

RubyのuriライブラリはRFC2396等に忠実なので、ホスト名に'_'を含むURIを処理せず例外を投げてしまいます。

具体的には

といったページを、uriライブラリを使うopen-uriでダウンロード出来ないわけです (っていうか、よく見たらどっちもinfoseek.co.jpのドメインだな。諸悪の根源はinfoseekか)。

まあとにかく、それで以前は、勉強もかねてメソッドを自作してopen-uriの代わりに使ったりしていました。

ところが最近、Mechanizeを使い始めたのですが、これがuriライブラリを使っているため、ホスト名に'_'を含むURIのページをダウンロードしたりできません。

それでとうとう、uriライブラリをオーバーライドしてホスト名に'_'を含むURIを処理できるようにしました。Malagmaに置いてあります。

こんな風に使うと

#!/usr/bin/ruby
uri = "http://foo_bar.org/"

require "uri"
begin
   puts "--- uri ---"
   puts URI.parse(uri)
rescue
   puts $!.message
end

require "lax_uri"
puts "--- lax_uri ---"
puts URI.parse(uri)

こんな感じで、きちんと(?)'_'付きのホスト名も処理してくれます。

--- uri ---
the scheme http does not accept registry part: foo_bar.org (or bad hostname?)
--- lax_uri ---
http://foo_bar.org/

Mechanizeを使うときも、あらかじめrequireしておけば問題なく'_'付きURIからページをダウンロード出来ます(mechanizeとのrequire順は不問)。

#!/usr/bin/ruby
require "rubygems"
require "mechanize"
require "lax_uri"

m = WWW::Mechanize.new
m.get("http://foo_bar.example.org/")
puts m.page.body
Tags: Ruby
本日のツッコミ(全4件) [ツッコミを入れる]

Before...

_ ひらく [おお、ありがとうございます。すっかり見落としていました。 Rubyへのパッチとしてはあちらの方が理想的ですねぇ。取り..]

_ かずひこ [じゃあ、ぜひMLで応援の一票を入れるのがいいのではないでしょうか? :)]

_ ひらく [一票投じてみました!!取り込まれたら嬉しいですねぇ]


2008-09-09(Tuesday)

Spambayesフィルタのバージョン 2008.09.09 を公開しました

先月発覚した、UTF版のSpamBayesフィルタが日本語のトークンを正しく分解できなかったバグを修正しました。EUC版については変わりありません。

こちらからダウンロードできます。また、CodeReposの方にはコミット済みなので、こちらを使っている方は svn up で済みます。

アップデート後に一度、Bayesフィルタの設定画面で「データベースの再構築」を実行することで、正しく分解されたトークンでデータベースが作り直されます。

もう一個のバグ

同時期に「mathmlプラグインを使っていると、投稿されてspam扱いしたコメントをhamとして処理しなおすときに、@cgi.user_agentを呼び出せないエラーが発生している」という現象も見つけたのですが、それっきり手元の環境では再現できなかったので、もしかしたら実験用に色々手を入れていたのが原因だったのかもしれません。

同じ現象が出ている人はご一報頂けると嬉しいです。


2008-09-18(Thursday)

URIあれこれ

RubyのURIライブラリでsplitするときに、もっとも多くの要素に分解するようなURIは何だろうかと試してみました。

irb(main):052:0> URI.split("http://user:pass@host:80/path/info?a=b;c=d&e=f#fragment")
=> ["http", "user:pass", "host", "80", nil, "/path/info", nil, "a=b;c=d&e=f", "fragment"]
irb(main):053:0> URI.split("mailto:mail@example.org")
=> ["mailto", nil, nil, nil, nil, nil, "mail@example.org", nil, nil]

registryに該当する部分を含むURIだけが、ちょっと分かりません。ちなみにHTTPのURIの場合では関係ないみたい 。

irb(main):060:0> URI.constants.sort.each{|c|
irb(main):061:1* m = URI.const_get(c)
irb(main):062:1> puts c, m.component.inspect if m.respond_to?(:component)
irb(main):063:1> }
FTP
[:scheme, :userinfo, :host, :port, :path, :typecode]
Generic
[:scheme, :userinfo, :host, :port, :registry, :path, :opaque, :query, :fragment]
HTTP
[:scheme, :userinfo, :host, :port, :path, :query, :fragment]
HTTPS
[:scheme, :userinfo, :host, :port, :path, :query, :fragment]
LDAP
[:scheme, :host, :port, :dn, :attributes, :scope, :filter, :extensions]
MailTo
[:scheme, :to, :headers]

URIライブラリが参照しているURIを定義するRFCはRFC2396RFC2732などですが、これらはRFC3986によって廃止されています。

余談ですが、ietfのRFCのページは、あるRFCが廃止されていたら何番で廃止されているかが一番上に書かれていて便利です。

そのRFC3986では、hostとして使える文字の制限が減っていて、多分、 hoge://host_name/ なんてのも許されるようです。

ただし、HTTPのためのURIは別のRFCで制限されているので'_'は使えないことになっているようです。この辺の話題は301 Moved Permanentlyにまとまっていて助かりました。

Tags: メモ

2008-09-20(Saturday)

Forwardableの委譲先

Forwardableクラスを使った委譲では、サンプルがそうなっていることもあって、委譲先にはインスタンス変数しか指定できないと思っていました。それで、その割にはわざわざSymbolでも指定できるようになっているとか、インスタンス変数と分かっているのに'@'を付けないとダメとか、変な仕様だなぁと思っていたのです。

そうじゃありませんでした!

#!/usr/bin/ruby
require "forwardable"

class C
   extend Forwardable
   def_delegators(:s, :size, :to_s)
   def s
      "hoge"
   end
end

c = C.new
puts c.size, c.to_s

これを実行すると、ちゃんと

4
hoge

となります。

Forwardableのソースを見ると

    module_eval(<<-EOS, "(__FORWARDABLE__)", 1)
      def #{ali}(*args, &block)
        begin
          #{accessor}.__send__(:#{method}, *args, &block)
        rescue Exception
          $@.delete_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable::d
ebug
          Kernel::raise
        end
      end
    EOS

となっているので、自分自身のメソッドどころか、参照できるものなら何でも委譲先に出来るようです。

Tags: Ruby

2008-09-23(Tuesday)

should_receive したメソッドを実際に実行もさせたい

あるクラスのあるメソッドが別のメソッドを呼ぶという動作をテストするときには、こんな感じのテストを書くと思います。

 o.should_receive(:fuga).with("fuga")
 o.hoge # o.hogeの中でfuga("fuga")されている

このテストが実行されるとき、o.fugaが呼ばれることの確認はされますが、実際にo.fugaが実行されはしません。

中で呼ぶメソッドが自前のものなら良いのですが、他のライブラリのメソッドだったりすると、そのテストを書いた後でライブラリの仕様が変わって、古い呼び出し方だと例外を投げるようになったりすることもあります。でもこのテストではそこまでの確認はできません。

それで、should_receiveでメソッドが呼ばれたことを確認しつつ実際にメソッド呼び出しも行うように、spec/mockを拡張してみました。こんな感じのテストが書けます。

require "mock_extend"

class C
   def hoge
      puts "hoge"
   end
end

describe C do
   it "hoge" do
      c = C.new
      c.should_receive(:puts).with("hoge").and_do{|r, *args|
         r.should be_nil  # この時点でメソッドは実行済み。r はメソッドの戻り値
         args[0].should == "hoge" # *args はメソッドへの引数
      }
      c.hoge
   end
end

実行するとこんな感じに

~/tmp$ spec test_spec.rb 
hoge
.

Finished in 0.006742 seconds

1 example, 0 failures

確かに puts("hoge") が実行されます。

実行まではされなくていいんだけど、そのメソッドが定義されていることだけは確かめたい、という場合もあります。例えばこんなテストを書きたいわけです。

require "mock_extend"
describe Object do
   it "hoge" do
      o = Object.new
      o.should_receive(:hoge).defined
      o.hoge
   end
end

should_receive(:hoge)だけのテストだと、実在しないメソッド hoge を呼び出すようなテストが行われても成功してしまいます。これに .define と付けると、次のように(期待通りに)失敗します。

~/tmp$ spec test2_spec.rb 
F

1)
'Object hoge' FAILED
expected target to respond to hoge
./test2_spec.rb:5:

Finished in 0.006814 seconds

1 example, 1 failure

この and_do と defined を提供するmock_extend.rbMalagmaから手に入ります

Tags: RSpec