Sinatra で正規表現を使ったルートを使う場合に注意すること

Sinatra ではルートの設定に正規表現を使うことができる。例えば以下のような感じで。

get %r{/hello/([\w]+)} do |c|
    "Hello, #{c}!"
end
http://www.sinatrarb.com/intro.html
問題

上記の例は公式のページに載っているのだけれど、これをそのまま使おうとしたらハマった。正規表現のルートは暗黙的に 先頭から末尾まで という条件を付加してはくれない、ということ。"^" や、"$" は自分で付加しなければならない。なので例のままだと次のようになる。

% ruby app.rb        
== Sinatra/1.2.6 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.2.11 codename Bat-Shit Crazy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
192.168.0.1 - - [07/Aug/2011 08:54:04] "GET /hello/sinatra HTTP/1.1" 200 15 0.0019 # 200 Ok 期待通り
192.168.0.1 - - [07/Aug/2011 08:54:19] "GET /aaa/hello/sinatra HTTP/1.1" 200 15 0.0011 # 404 を期待してるのに...
192.168.0.1 - - [07/Aug/2011 08:54:35] "GET /hello/sinatra/zzz HTTP/1.1" 200 15 0.0021 # 同上
192.168.0.1 - - [07/Aug/2011 08:54:52] "GET /aaa/hello/sinatra/zzz HTTP/1.1" 200 15 0.0019 # 同上

ルートにマッチして欲しくないリクエストまでマッチしてしまっている。

解決

適宜 "^" や "$" を付ける。

get %r{^/hello/([\w]+)$} do |c|
    "Hello, #{c}!"
end
% ruby app.rb
== Sinatra/1.2.6 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.2.11 codename Bat-Shit Crazy)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
192.168.0.1 - - [07/Aug/2011 09:17:43] "GET /hello/sinatra HTTP/1.1" 200 15 0.0018 # 200 Ok
192.168.0.1 - - [07/Aug/2011 09:17:50] "GET /aaa/hello/sinatra HTTP/1.1" 404 457 0.0013 # 404 期待通り
192.168.0.1 - - [07/Aug/2011 09:17:58] "GET /hello/sinatra/zzz HTTP/1.1" 404 457 0.0013 # 同上
192.168.0.1 - - [07/Aug/2011 09:18:03] "GET /aaa/hello/sinatra/zzz HTTP/1.1" 404 461 0.0003 # 同上