rack-logo posted by (C)komagata
komagataです。
仕事でも使う必要が出てきたのでRubyの勉強をしています。WebアプリケーションでRubyを使おうとしていきなり躓いたのがApache、WEBrick、Mongrel等、実行環境毎の設定やAPIの違いです。
Rubyを普段使っている人には常識過ぎるのか情報が少なく、FastCGIで単に「Hello, World」を表示させるのにも一苦労でした。(Railsでは簡単に動くのが悔しい)
そんな実行環境毎のAPIの差を吸収してくれるRackというライブラリを知ったので試してみました。
RackはRuby版WSGIと呼ばれているそうです。WSGIとはWeb Server Gateway Interfaceの略でWeb ServerとWeb Applicationの間のInterfaceを定めたPython界の仕様だそうです。
Web ApplicationはWSGIの仕様に沿ったAPIを使って作ればWeb Serverが変っても問題無いようになるはずです。
まずはこちらを参考に最低限のものを書いてみました。
インストール:
$ gem install rack
hello-rack.rb:
#!/usr/bin/env ruby require 'rubygems' require 'rack' include Rack class HelloRack def call(env) [200, {"Content-Type" => "text/plain"}, ["Hello, Rack"]] end end Handler::WEBrick.run HelloRack.new, :Port => 3000
これを起動してみます。
$ ruby hello-rack.rb [2007-05-07 18:43:31] INFO WEBrick 1.3.1 [2007-05-07 18:43:31] INFO ruby 1.8.5 (2006-08-25) [i486-linux] [2007-05-07 18:43:31] INFO WEBrick::HTTPServer#start: pid=19600 port=3000
ブラウザから3000番にアクセスしてみると・・・
hello_rack posted by (C)komagata
動きました!
HandlerにはWEBrickの他にCGI, FastCGI, Mongrelがあります。それぞれのHandlerを使うことで環境を切り替えることができます。
RequestやResponseはそれぞれRack::Request, Rack::Responseに分かりやすい感じで抽象化されているので環境差を気にせず使えそうです。
しかし、
「結局プログラムを変えなきゃいけないなら意味無いじゃないか、Railsならオプションや設定だけで変えられるのに!」
などと思われたかもしれません。
それを解決するためにRackではrackupというコマンドがあります。rackupとDSL風な設定ファイルを使ってWebサーバー依存をプログラムから追い出すことが出来ます。
rackupコマンド:
$ rackup --help Usage: rackup [ruby options] [rack options] [rackup config] Ruby options: -e, --eval LINE evaluate a LINE of code -d, --debug set debugging flags (set $DEBUG to true) -w, --warn turn warnings on for your script -I, --include PATH specify $LOAD_PATH (may be used more than once) -r, --require LIBRARY require the library, before executing your script Rack options: -s, --server SERVER serve using SERVER (webrick/mongrel) -o, --host HOST listen on HOST (default: 0.0.0.0) -p, --port PORT use PORT (default: 9292) -E, --env ENVIRONMENT use ENVIRONMENT for defaults (default: development) Common options: -h, --help Show this message --version Show version
まずアプリケーションの方からサーバー依存を取ります。
hello-rackup.rb:
require 'rack/request' require 'rack/response' module Rack class HelloRackup def call(env) Response.new.finish do |res| res.write "Hello, Rackup" end end end end
(hello-rack.rbの例もそうですが、要はcallできてResponseっぽいものを返すものならば何でもいいみたいです。)
Rackのexampleについているlobstericiousというふざけたアプリケーションを参考にして設定を書きます。(拡張子はrbではなくruです。rackupだからでしょうか?)
lobstericious:
lobstericious posted by (C)komagata
hello-rackup.ru:
require 'hello-rackup' run Rack::HelloRackup.new
rackupコマンドをこの設定ファイルを指定して起動します。
$ rackup -s webrick -p 9292 hello-rackup.ru [2007-05-07 19:27:29] INFO WEBrick 1.3.1 [2007-05-07 19:27:29] INFO ruby 1.8.5 (2006-08-25) [i486-linux] [2007-05-07 19:27:29] INFO WEBrick::HTTPServer#start: pid=22015 port=9292
これでブラウザから9292番にアクセスすると、
hello_rackup posted by (C)komagata
動きました!
-sオプションにmongrelを指定すればmongrelで起動します。アプリケーション本体には手を入れずに済むようになりました。
更に設定ファイルでは下記のようにProxyのように透過的に動作するMiddlewareを簡単に追加することが出来ます。(このuseというメソッド、Rubyに慣れていないのでPerlみたいに普通にあるのかと思ってKernelモジュールや予約語一覧を探し回ってしまいました・・・)
require 'hello-rackup' use Rack::ShowExceptions use Rack::CommonLogger use Rack::Lint run Rack::HelloRackup.new
例えば、Rack::ShowExceptionsを追加するとはエラーをPythonのフレームワークDjango風に表示にし、Rack::CommonLoggerを追加するとApache風のログを出力します。Rack(棚)にMiddlewareを積んでいって機能を追加していくイメージなのかもしれません。
Djangoにそっくり:
traceback_ruby posted by (C)komagata
ところでCGIやFastCGIはどうするのかというと、正しいやり方がわかってません・・・。今は苦肉の策でこんなファイルを置いています・・・。
hello-rackup.fcgi:
#!/bin/sh rackup hello-rackup.ru -s fastcgi
これはかなりヘボいのでどなたか正しいやり方を教えていただければ幸いです・・・。
このようにRackを使うことでRailsのようにWebサーバごとのエントリポイントやrackup用の設定ファイルを用意しておくだけで本体のアプリには手を入れずに様々な環境で動作するWebアプリケーションが書けます。オープンソースで配布するアプリケーションを作る場合などには役に立つのではないでしょうか。