Crystal 関係の情報を拾ってるとWebフレームワークの Kemal が超イケてるぽいので,Rubyのベタ書きCGIな個人サイトを Kemal で再構築してみようと試行錯誤中。
その中で,階層数を特定せず複数階層("a", "a/b", "a/b/c", ...)全体にマッチするルートを指定する必要にかられたのですがKemalのドキュメントを見てもそれらしい記述が見当たりません。
Kemalのインスパイア元であるSinatraのドキュメントを当たってみる,とどうやらスプラット(*
)を使えば良いっぽいので,
get '/download/*.*' do
# matches /download/path/to/file.xml
params['splat'] # => ["path/to/file", "xml"]
end
モノは試しとKemalで
# access to http://localhost:3000/test1/test2/test3
get "/*" do |env|
env.params["splat"]
end
とやってみたら,案の定Exception: Missing hash key: "splat"
と怒られた。
その後,Kemalのソースを追いかけてパスツリーの検索にRadix::Tree#find
が使われていることを突き止め,さらにRadixのソースを追いかけてみると,コロン(:
)を使ったパラメータ名指定と同じように,スプラットの後にもパラメータ名を指定できるようで,↓みたいにすれば良いらしい。
# access to http://localhost:3000/test1/test2/test3
get "/*path" do |env|
env.params["path"] # => "test1/test2/test3"
end
スプラットが複数出てくる時に別の名前を指定できるので,Sinatraの指定のキーで配列が返ってくる仕様より便利かも。
Kemal(Radix)超イカス!!
で余談ですが,スプラットの後ろの文字列がパラメータ名になるため,明示的なパラメータ名をつけず”*"
とだけ指定すると,名前が空文字(""
)のパラメータとして設定されるみたい。下の例みたいにルートパス以下を全部引っ掛けるような時ならコレでも良いかも。
# access to http://localhost:3000/test1/test2/test3
get "/*" do |env|
env.params[""] # => "test1/test2/test3"
end
追記
ルート(route)に "/*"
を指定すると,env.params[""]
にはリクエストパスからルート(root)パスである先頭の /
を除いた文字列が格納されます。
get "/*" do |env|
env.params[""] # http://localhost:3000/aaa/bbb/ccc => "aaa/bbb/ccc"
end
サイトのルートパス(/
)にアクセスしたら場合には空文字を返してくれるかと思ったら,どうやらこのルートは /
にはマッチしない模様。
それじゃ "*"
を指定すれば先頭の /
も含んだリクエストパス全体が帰ってくんじゃないかと試しましたが,こちらはどのパスに対してもマッチしないルートになってしまいました。
get "*" do |env|
env.params[""] # http://localhost:3000/ => 404 Error
# http://localhost:3000/aaa/bbb/ccc => 404 Error
end
さしあたりルートパスのルートは独立して指定するしかなさそうですね。