spiritlooseのはてなダイアリー このページをアンテナに追加 RSSフィード

2009-07-30

[]Schenker - RubySinatraのようなフレームワーク作成中


http://github.com/spiritloose/Schenker


前に RubySinatra を触ってみていいなとおもったので最近作り始めた。

ひととおり機能はそろってきたので公開してみる。


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に入ってるやつ)でも動く。


まだドキュメントがないけど、RailsScaffoldで生成されたものを移植したサンプルが http://github.com/spiritloose/schenker-sample にあります。


no title を参考にさせていただいて(パクって)チュートリアルを書いてみた。


$ 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);
};

Status

通常では200番のステータスコードになるがstatusメソッドをつかうと変更できる

get '/' => sub {
    status 404;
    "Not found";
};

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

サンプルアプリケーションを参考にしてください。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証