Introducing Ark

YAPC::Asia 2009 Tokyo

Sep 10th, 2009

自己紹介

アジェンダ

Ark とは何か

Ark の特徴

HTTP::Engine

HTTP::Engine

sub request_handler {
    my ($req) = @_;
    # ...
    return $res;
}

HTTP::Engine

...

HTTP::Engine

...

HTTP::Engine

HTTP::Engine以降のWAF

BM11

...

BM11

...

BM11

...

BM11

...

BM11

BM11に特化とは

BM11に特化とは

BM11に特化とは

BM11に特化とは

BM11現状

Ark

Catalystライク

MyApp.pm

package MyApp;
use Ark;

# additional config

1;

Catalystライク

MyApp/Controller/Root.pm

package MyApp::Controller::Root;
use Ark 'Controller';

has '+namespace' => default => '';

sub index :Path {
    my ($self, $c) = @_;
    $c->res->body('Hello World!');
}

1;

Catalystアンライク

BEGINとかしなくていい

package MyApp::Controller::Root;
use Moouse;
BEGIN { extends 'Catalyst::Controller' }

CGIモード

CGIモード

my $app = MyApp->new;
$app->setup_minimal( action_cache => 'tmp/action.cache' );

ディスパッチテーブルキャッシュ

CGIモード

GET /

load MyApp::Controller::Root

CGIモード

$c->forward('/another_controller/action');

load MyApp::Controller::Another

CGIモード

$c->session

テンプレート

...

テンプレート

Text::MicroTemplate::Extended

...

Text::MicroTemplate::Extended

テンプレートの継承

インクルードモデル

<?= include 'header' ?>

...

<?= include 'footer' ?>

テンプレートの継承

wrapperモデル

wrapper.tt

<html>
<body>
[% content %]
</body>
</html>

テンプレートの継承

wrapperモデル

content.tt

<h1>Hello</h1>

テンプレートの継承

継承モデル

base.mt

<html>
<head>
<title><?= block title => 'Default Title' ?></title>
</head>
<body>
<?= block content => '' ?>
</body>
</html>

テンプレートの継承

継承モデル

child.mt

? extends 'base'

? block content => sub {
<h1>Hello World</h1>
? } # endblock content

テンプレート継承

Perlで継承をサポートしたテンプレートエンジンは

Text::MicroTemplate::Extended と Template::Declare

だけ!(たぶん)

モデル

...

モデル

Catalystライクモデル

package MyApp::Model::Foo;
use Ark 'Model::Adaptor';

__PACKAGE__->config(
    class => 'Foo',
);

Catalystライクモデル

$c->model('Foo');

Ark::Models

...

Ark::Models

Ark::Models 基本

モデル定義(オブジェクト登録)

package MyApp::Models;
use Ark::Models -Base;

register Foo => sub {
    $_[0]->ensure_class_loaded('Foo');
    Foo->new;
};

Ark::Models 基本

モデルの使用

use MyApp::Models;

my $foo = models->get('Foo');
my $foo = models('Foo');

Ark::Models 基本

モデルの使用

use MyApp::Models 'hoge';

my $foo = hoge->get('Foo');
my $foo = hoge('Foo');

Ark::Models うれしいところ

どこからでも同じように利用することができる

CLIスクリプトでも

use MyApp::Models;
my $conf = models('conf');

どこからでも同じように利用することができる

Formモジュール(後述)から

custon_validation => sub {
    my ($self, $form, $field) = @_;

    my $value = $form->param($field->name);
    my $user  = models('Schema::User')->find({ username => $value })

    if ($user) {
        $form->set_error( $field->name, 'already_taken' );
    }
},

遅延ロード

依存性の解決

依存性の解決

register Schema => sub {
    my $self = shift;
    my $conf = $self->get('conf')->{database};

    croak "Require database config" unless $conf and ref $conf eq 'ARRAY';

    $self->ensure_class_loaded('MyApp::Schema');
    MyApp::Schema->connect(@$conf);
};

依存性の解決

register 'Schema::User' => sub {
    my $self   = shift;
    my $schema = $self->get('Schema');

    $schema->resultset('User');
};

依存性の解決

models('Schema::User');

組み込みモデル

Ark設定

Ark設定

return {
    database => [
        'dbi:mysql:foo', 'root', undef,
        {
            on_connect_do => 'SET NAMES utf8',
            mysql_enable_utf8 => 1,
        },
    ],
};

Ark設定

my $home = MyApp::Models->get('home');

return {
    my_file => $home->file('my_file'),
}

Ark設定

CatalystライクにするMagic

package MyApp;
use Ark;

use_model 'MyApp::Models';

1;

Ark::Form

フォーム定義

package MyApp::Form::Signup;
use Ark 'Form';

param username => (
    type        => 'TextField',
    label       => 'Username',
    constraints => [
        'NOT_NULL',
        'ASCII',
    ],
);

param password => (
    type        => 'PasswordField',
    label       => 'Password',
    constraints => [
        'NOT_NULL',
        'ASCII',
    ],
);

1;

フォーム表示

<?= form->render ?>

Or

<?= form->render('username') ?>
<?= form->render('password') ?>

バリデーション

package MyApp::Controller::Root;
use Ark 'Controller::Form';

sub signup :Local :Form('MyApp::Form::Signup') {
    my ($self, $c) = @_;

    if ($self->form->submitted_and_valid) {
        # signup
    }
}

バリデーション

package MyApp::Controller::Root;
use Ark 'Controller';

with 'Ark::ActionClass::Form';

でも同じ

Formの継承

Formの継承

package MyApp::Form::Account;
use Ark 'Form';

param username => (
    # ...
);

param password => (
    # ...
);

1;

Formの継承

package MyApp::Form::Signup;
use Ark '+MyApp::Form::Account';

use MyApp::Models;

param '+username' => (
    custon_validation => sub {
        my ($self, $form, $field) = @_;
        return if $form->is_error('username');

        if (models('Schema::User')->find({ username => $form->param('username') })) {
            $form->set_error( username => 'already_taken' );
        }
    },
);

sub messages {
    return {
        %{ shift->SUPER::messages },
        'username.already_taken' => 'this username already taken',
    };
}

その他の機能

プラグイン

だいたい一通りある

t/plugin_*

みると、なにがあるかと使い方がわかる

Action Role

サポート。

ex: Ark::ActionClass::Form

エンコーディングサポート

エンコーディングサポート

use Ark 'Controller'
use utf8;

エンコーディングサポート

use Ark 'Controller'
no utf8;

モバイルサポート

PSGI

開発

Example application

まとめ

That's All