Schenker - RubyのSinatraのようなフレームワーク作成中
http://github.com/spiritloose/Schenker
前に Ruby の Sinatra を触ってみていいなとおもったので最近作り始めた。
ひととおり機能はそろってきたので公開してみる。
HTTP::Engine + HTTP::Engine::Middleware + HTTPx::Dispatcher + Sinatra風インターフェース
みたいな感じのフレームワーク、っていうかDSL。
# myapp.pl #!/usr/bin/env perl package MyApp; use Schenker; get '/' => sub { 'Hello, world!'; }; get '/hello/:name' => sub { my $args = shift; "Hello, $args->{name}!"; };
で `./myapp.pl` すると動く。デフォルトはServerSimpleだけど、CGIでもPOEでもModPerlでもFCGIでもAnyEvent(Remedieに入ってるやつ)でも動く。
まだドキュメントがないけど、RailsのScaffoldで生成されたものを移植したサンプルが http://github.com/spiritloose/schenker-sample にあります。
http://labs.unoh.net/2009/05/sinatra.html を参考にさせていただいて(パクって)チュートリアルを書いてみた。
$ git clone git://github.com/spiritloose/Schenker.git $ cd Schenker $ cpan -i .
# app.pl #!/usr/bin/env perl package App; use Schenker; get '/' => sub { 'Hello, world'; };
$ ./app.pl $ curl http://localhost:4567/
Routes
HTTPメソッドにURLとクロージャを渡します。
get '/' => sub { }; post '/' => sub { }; put '/' => sub { }; Delete '/' => sub { # deleteは組み込み関数なので泣く泣く… };
==追記==
b:id:kazuhookuさん
http://b.hatena.ne.jp/kazuhooku/20090730#bookmark-15017671
よさげ。もともと HTTP メソッドは大文字なんだから、全部 upcase しちゃえば Delete で泣く必要ないんじゃないかなと思った
ちょっと迷ってます。揃えたいんですが、大文字だと今度はHTTP::Request::Commonとかぶったり…
==追記おわり==
パラメータを含めたURLも可能
get '/hello/:name' => sub { my $args = shift; "Hello $args->{name}"; };
GETパラメータ、POSTパラメータはparam('xxx')かparams->{xxx}で取得できる。
アプリケーションファイルは複数に分けることが可能。
(分けないと見通しがつかない規模ならCatalyst等をお勧めしますが…)
#!/usr/bin/env perl package App; use Schenker; get '/' => sub { "Hello world"; }; do 'more_routes.pl'; # more_routes.pl use strict; use warnings; get '/foo' => sub { "Foo"; }; 1;
Redirect
redirect '/'; redirect 'http://www.google.co.jp'; redirect '/', 303; redirect '/', 307;
Session
有効にするにはTOPレベルか、configureブロックに書く
enable 'sessions'; get '/' => sub { session->set(count => 0); session->set(count => session->get('count') + 1); };
Filters
イベントの前に実行される
Before sub { # beforeはMoose/Mouseで定義済みなので… warn 'before'; };
Nested params は組み込み。
<form> <input ... name="post[title]" /> <input ... name="post[body]" /> <input ... name="post[author]" /> </form>
param('post'); # { title => '', body => '', author => '' }
Views
viewファイルはroot/viewsに置きます。
今のところTTとText::MicroTemplateが使える。
get '/' do tt 'index'; # views/index.tt mt 'index'; # views/index.mt end
Layouts
TTのWRAPPERを使ってください。
tt_options WRAPPER => 'layout.tt';
アプリケーションと同じファイルにviewが書ける。
get '/' => sub { tt 'index'; }; __END__ @@ index hello, world!
PadWalkerが入ってるとローカル変数がそのままテンプレートで使える。
get '/' => sub { my $name = 'Michael Schenker'; tt 'index'; }; __END__ hello, [% name %]
PadWalker入ってない or 使いたくない or Text::MicroTemplateの場合は stash や引数に渡す。
get '/' => sub { stash name => 'Rudolf Schenker' tt 'tt'; mt 'mt', {}, stash->{name}; }; __END__ @@ tt hello, [% name %] @@ mt hello, <?= $_[0] ?> hello, <?= stash->{name} ?>
Models
Schenkerはmodelを提供してないので、好きなのを使ってください。
JSONでも出力してみる
use JSON; get '/api/items.json' => sub { content_type 'application/json'; to_json({ foo => 'bar' }); };
Helpers
helpersでメソッドを定義するとイベント内やテンプレートで使えます。
が、そのままサブルーチン定義しても一緒です。
helpers bar => sub { "$_[0]bar"; }; get '/:name' => sub { bar(params->{name}) };
HTTP::Engine::Middleware
Useで指定する。
Use 'HTTP::Engine::Middleware::MobileAttribute';
Schenker自体がいくつか読み込んでます。
Error Handling
not_found
定義されてないURLにアクセスがあった場合に動作。
デフォルトで設定されてますが、変えたいときに。
not_found sub { status 404; body "Not found"; };
error
例外が投げられたら動作
error sub { status 500; body 'Internal Server Error'; };
独自の例外を使いたい場合
define_error MyCustomError => sub { status 500; body 'MyCustomError'; }; get '/' => sub { raise MyCustomError; };
development環境ではデフォルトでスタックトレースが表示されます(CGI::ExceptionManager::StackTrace)。
Configuration
configure development => sub { set dbname => 'devdb'; enable 'feature'; }; configure production => sub { set dbname => 'productiondb'; disable 'feature'; }; configure qw(development production) => sub { }; get '/whatdb' => sub { 'We are using the database named ' . options->dbname; };
Deploy
サンプルアプリケーションを参考にしてください。