後先考えず、空気も読まず、気分がのったので、晒してみます。記事を書いた後で、意外と日本語のRack情報があった事に気づいて愕然としたのは、内緒です。以降、基本的には公式ドキュメント等の劣化コピーなので、注意してください。
Rack
Rackとは、Rubyで実装したアプリケーションとウェブサーバとを繋ぐインターフェースです。Rackプロトコルに従って実装したアプリケーションは、利用するウェブサーバを自由に選択する事が可能となります。
Rackの開発元へは、以下のリンクから。
Rack: a Ruby Webserver Interface
Rackプロトコル概要
Rackプロトコルについて、簡単に説明します。
Rackプロトコルに従ったアプリケーションとは、環境変数envを引数にとるメソッドcallを持つRubyオブジェクト(インスタンス)を意味します。callは、3つの要素を持つArrayオブジェクトを返します。これは順に、『HTTPステータスコード』『HTTPレスポンスヘッダ』『HTTPボディ』となります。
環境変数
アプリケーションは、環境変数を読み書きする事で、入出力操作等を行える様になります。環境変数は、いわゆるCGI環境変数や、Rack独自の環境変数、アプリケーション独自の変数を格納します。環境変数はStringオブジェクトをキーに持つHashオブジェクトです。
ここでCGI環境変数と呼んでいるのは、PEP333に定められているCGI環境変数と同様です。CGI環境変数はすべてStringオブジェクトとして値を保持します。
Rack独自の環境変数のキーは、"rack."で始まります。入力ストリーム(rack.input)およびエラーストリーム(rack.errors)も、これに含まれます。
アプリケーション独自の環境変数のキーは、アプリケーション固有のプレフィックスで始まります。キーは、Rack環境変数同様に必ずドットを含まなければなりません。つまり、『プレフィックス.名前』というキーを利用しなければならないという事になります。アプリケーション独自と書きましたが、アプリケーションのみならず、ウェブサーバが利用する事もあり得ます。
レスポンス
先述の通り、レスポンスは3つの要素からなるArrayオブジェクトです。それぞれについて、簡単に説明します。
第1要素は、HTTPステータスコードになります。これは、必ず100以上でなければなりません。また、to_iメソッドに応答可能である必要があります。整数でなくとも、to_iによって整数に変換可能であればかまいません。
第2要素は、HTTPレスポンスヘッダです。これは、eachに応答し、ヘッダフィールドを意味するキーとその値をyieldしなければなりません。簡単にいえば、Hash#eachと同様の振る舞いをするという事です。
特に注意すべき制約として、ステータスコードが204か304の場合を除いて、必ずContent-Typeを含まなければならないという点が挙げられます。
第3要素は、HTTPボディです。これは、eachに応答し、Stringオブジェクトをyieldしなければなりません。一般に、StringオブジェクトからなるArrayオブジェクトか、アプリケーションインスタンス自身、もしくはFileの振る舞いをするオブジェクトが使われるでしょう。
検査
Rackプロトコルに従えているかどうかについて、検査するための手段が提供されています。Rack::Lintというミドルウェアを有効にする事で、アプリケーション実行時に検査し、異常があれば例外をスローします。
補足
Rackプロトコルの詳細については、以下の公式ドキュメントをご覧ください。
File: SPEC
参考までに自身による和訳へのリンクを紹介しておきます。
KOSHIGOE学習帳 - [Ruby] Rackプロトコル仕様
対応環境
ここで、Rackの対応環境について紹介したいと思います。
ウェブサーバ
Rackが同梱するハンドラ(Rack::Handler::*)か、ウェブサーバが同梱するハンドラによって、以下の様なウェブサーバがRack対応を果たしています。
Mongrel, EventedMongrel, WEBrick, FCGI, CGI, SCGI, LiteSpeed, Ebb, Fuzed, Phusion Passenger, Thin
ウェブフレームワーク
Rackが同梱するアダプタ(Rack::Adapter::*)か、ウェブフレームワークが同梱するアダプタによって、以下の様なウェブフレームワークがRack対応を果たしています。
Camping, Coset, Halcyon, Mack, Maveric, Merb, Racktools::SimpleApplication, Ramaze, Sinatra, Vintage, Waves
Ruby on Railsは、Thinに同梱されるアダプタによって稼働させる事ができ、これは今後のバージョンでRackにマージされる予定です。
補足
詳細については、以下の公式ドキュメントをご覧ください。
Rack Documentation
チュートリアル
Rackについて、基本的な説明をしてきましたが、ここで実際のアプリケーションを動かしてみましょう。参考までに、手元の環境を掲載しておきます。
$ uname -a Darwin koshigoe.local 9.4.0 Darwin Kernel Version 9.4.0: Mon Jun 9 19:30:53 PDT 2008; root:xnu-1228.5.20~1/RELEASE_I386 i386 i386 MacBookPro3,1 Darwin $ ruby --version ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin9.4.0] $ gem --version 1.2.0
Rack導入
まずは、Rackをインストールします。
$ sudo gem install rack
$ rackup --version
Rack 0.1
2008/09/09現在、RubyGemsでインストール可能なRackのバージョンは0.4.0です("rackup --version"の結果は、Rackプロトコルとしては、バージョン0.1という事だと思います)。
最新の開発版に興味がある方は、GitHubのリポジトリをご覧ください。
chneukirchen's rack at master — GitHub
簡易アプリケーション
以下を"config.ru"として適当な場所に保存します。
run Proc.new { |env| [ 200, {'Content-Type' => 'text/html; charset=UTF-8'}, [env.map { |key, value| Rack::Utils.escape_html("#{key}=#{value}")}.join("<br />\n")] ] }
ここでは、手軽にアプリケーションインスタンスをProcオブジェクトで実装しました。環境変数をダンプするだけのアプリケーションとなります。
このファイルを、rackupを利用して任意のウェブサーバ上で動かしてみます。
$ rackup config.ru
ここではウェブサーバを指定していないため、WEBrickが起動するはずです。早速、ウェブブラウザから結果を見てみましょう。オプションを省略したので、"http://localhost:9292/"にリクエストすれば結果が見られるはずです。
環境変数の内容が表示されたでしょうか。
rackup
話が前後しますが、rackupについても簡単に説明しておきます。rackupは、rackup configファイルを読み込み、任意のウェブサーバでアプリケーションを実行するためのユーティリティです。rackup configとは、Rackの独自DSLで記述する設定ファイルです。DSLはRack::Builderで実装されています。
基本的に、『アプリケーションライブラリの読み込み』『ミドルウェアの選択』『アプリケーションの実行およびマッピング』を記述する事になります。
Rackには、実行環境があり、rackup実行時に指定する事ができます。Rackのソースを見た限りでは、development, deployment, noneの3種類が定義されているようです。rackupは指定された実行環境に応じて、自動的にミドルウェアを選択します。
bin/rackup at master from chneukirchen's rack — GitHub
以下は、rackupのヘルプになります。
$ rackup -h
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)
-D, --daemonize run daemonized in the background
-P, --pid FILE file to store PID (default: rack.pid)
Common options:
-h, --help Show this message
--version Show version
設定ファイルは、.ruで終わる任意のファイル名で良いはずです。設定ファイルの指定を省略した場合、カレントディレクトリのconfig.ruを読み込もうとします。
ミドルウェア
Rackは、いくつかのミドルウェアを提供しています。
基本構造
ミドルウェアは、基本的にはアプリケーションを包むラッパーです。設定ファイル内で"use Hoo"とする事で、アプリケーションがミドルウェアに包まれ、処理を連鎖させるわけです。少々、強引な解釈かと思いますが、おおむねこのような理解で問題ないかと思います。
ミドルウェアは、以下の規約に従います(実装から独断で書いています)。
- initializeメソッドの第1引数にアプリケーションインスタンスをとる
- 実行時にアプリケーション同様に扱うためにcallメソッドを実装している
- ほか、Rackプロトコルに従う
ラッピングするためにinitializerの点が特徴的ですが、基本的にはアプリケーションのような振る舞いをするオブジェクトです。
一覧
バージョン0.4.0時点で利用可能なミドルウェアの一覧です。中には、正確にはアプリケーションというべきものも含まれていますが、便利だという事で含めます。
- Rack::Auth::Basic
- Basic認証を行うミドルウェア。全体もしくはアプリケーションごとに保護可能。
- Rack::Auth::Digest::MD5
- MD5によるダイジェスト認証を行うミドルウェア。アプリケーションごとの保護のみ確認。
- Rack::Auth::OpenID
- OpenIDによる認証を行うミドルウェア。動作確認はとれていない。
- Rack::Cascade
- レスポンスコードによるアプリケーションのカスケーディングを行うミドルウェア。ファイルが存在しなければ(404 Not Foundなら)任意のアプリケーションを実行する、など。
- Rack::CommonLogger
- ロギングを行うミドルウェア。development環境とdeployment環境では強制される。
- Rack::Deflater
- 圧縮転送に対応するミドルウェア。
- Rack::Directory
- ディレクトリインデックスの表示か指定アプリケーションの実行を行うミドルウェア(アプリケーション?)。
- Rack::File
- ファイルの表示を行うアプリケーション。
- Rack::Lint
- プロトコルを守れているか検査するミドルウェア。development環境では強制される。
- Rack::Lobster
- サンプルアプリケーション。ロブスターが表示される。
- Rack::URLMap
- アプリケーションのロケーションを設定できる。DSLのmapに対応する。
- Rack::Rcursive
- Rack::ForwardRequest.new(location)がraiseされた時に、locationに対応するアプリケーションに転送するミドルウェア。
- Rack::Reloader
- Rubyスクリプトが変更された時に、スクリプトをリロードするミドルウェア。リロードの最短間隔を指定できる。
- Rack::Session::Cookie
- Cookieを利用した単純なセッション管理を行うミドルウェア。env['rack.session']などからHashでセッションデータを操作可能。
- Rack::Session::MemCache
- memcachedを利用した並列管理可能なセッション管理を行うミドルウェア。セッションキーはCookieで行う。env['rack.session']などからHashでセッションデータを操作可能。
- Rack::Session::Pool
- Cookieを利用した並列管理可能なセッション管理を行うミドルウェア。env['rack.session']などからHashでセッションデータを操作可能。
- Rack::ShowExceptions
- 例外発生時に見栄えの良いページとして表示するミドルウェア。development環境では強制される。
- Rack::ShowStatus
- エラーレスポンス(400以上)の際、Rackが提供するテンプレートを使ってページを表示するミドルウェア。env['rack.showstatus.detail']に文字列(HTML)を入れておくと、これも表示される。
- Rack::Static
- URLに対応する静的ファイルを表示するミドルウェア。特定のディレクトリ(URL)のみを静的ファイルとして扱う様な場合に便利。
サンプル
ミドルウェアの利用例をGitHubに置いておきました。興味のある方は、ご覧ください。サンプル中の英語については、気にしないようお願いします。
koshigoe's rackup_examples at master — GitHub
一部のミドルウェアでは、その実行に別途RubyGemsを必要とするものがあります。必要に応じてインストールしてください。
まとめ
以上、怪しげなところが多々ありますが、簡単にRackについて説明しました。
基礎として、後は、Rack::RequestとRack::Response、およびRack::Utilsの紹介もするべきですが、今回はここまで。まだ、アプリケーション実装の詳細までは経験していないため、この程度にとどめようかと思います。
この記事の内容は、基本的には公式ドキュメントとウェブに公開されている情報をまとめ直した様なものです。より詳細に興味がある場合は、Rackのソースや、以下の参考情報をご覧ください。いくつかはまだ読んでいなかったりしますが、興味深そうなだったので含めておきます。
- ウノウラボ Unoh Labs: RackでWebアプリのWebサーバー依存を無くす
- Greenbear Diary - 5分でわかるRack , シュレーディンガーの猫たち
- Greenbear Laboratory - Rack日本語リファレンス
- 満足せる豚。眠たげなポチ。:CGI から Mongrel まで、Rack で Web アプリを Web サーバから抽象化する
- Rack でセッションを使う - Mi manca qualche giovedi`?
機会があれば、省略したユーティリティクラスや、利用レポートなどについても書いてみようかと思っています。利用レポートといっても、ssbをRack化してmod_passengerで動かしているデータしかとれませんが。しかも、作業用マシンで動かしていて、毎日電源を落としているので、稼働データは取れません。
会社の同僚がこれを読まない事を祈っています。おそらく、社内勉強会では、Rackネタを披露します。この内容から大きく変わる事はないでしょう。
それでは、長文失礼しました。


コメントする