はじめに
Plack Advent Calendar で Plack をかじって以来,その上で動くサイトやアプリケーションを気軽に作れるようなフレームワークを作ってみています.少しは動くようになってきたので,恥ずかしながら晒してみることにしました.
以下,そんな Web(サイト|アプリケーション)フレームワーク「Hoya」の,現状におけるさわりについて紹介します.
あくまで「現状における」なので,これからいろいろ使い方にも変更が加わるかと思いますが,ご了承くださいまし.
概要
「Hoya」という名前の由来は次のとおりです.
- メガネラボ
- Plack 向け → 焦点
- 「メガネ」「焦点」といえば...
- その会社といえば...
ありがとうございました ><
あ,これは後づけですが,私の持っているカメラも関連があったりなかったり.
以前に作っていたフレームワークの流れをそこそこ保ちつつ,処理部分を,より簡単な記述で書けることを目指しています.あくまで個人的主観ですが...
また,YAPC::Asia 2009 で知った・知るきっかけとなった,Plack まわりはもちろん,Text::MicroTemplate::Extended や DBIx::Skinny などのモジュールを組み込んでいたりもしています.
とりあえず「Hello, world」
手順
- Hoyaの入手
- 「プロジェクト」のセットアップ
- サーバ起動スクリプトの修正
- サーバの起動
- Hello, world.
Hoyaの入手
次のあたりから git clone などして,テキトーなディレクトリに置きます.以下,このディレクトリを HOYADIR とします.今回のデモでは,/Works/Hoya/master としています.
「プロジェクト」のセットアップ
HOYADIR/script 下に,setup_project.pl という,「プロジェクト」のセットアップを手伝ってくれる perl スクリプトがあります.
実行すると何か聞かれるので,「y」と答えると,現在いるディレクトリ(以下,このディレクトを,PROJECT_ROOT とします)に,アプリケーションが最低限動作するための,ファイル・ディレクトリ構成を開始します.
/Users/iwata/tmp/hoyapp % perl /Works/Hoya/master/script/setup_project.pl Are you sure to setup directories? [y/N]: y mkdir ./bin mkdir ./conf ... mkdir ./site/default/default/js/page mkdir ./site/default/default/mt mkdir ./site/default/default/tt /Users/iwata/tmp/hoyapp %
ディレクトリ構成は,次のような感じです.
/Users/iwata/tmp/hoyapp % tree -d . |-- bin |-- conf |-- data | |-- sql | `-- yaml |-- doc |-- hoya -> /Works/Hoya/master |-- lib |-- log |-- pl | |-- action | `-- model |-- s -> ./site/default/default |-- script |-- site | `-- default | `-- default | |-- css | | |-- common | | `-- page | |-- img | |-- js | | |-- common | | |-- lib | | `-- page | |-- mt | `-- tt |-- t |-- tmp |-- upload | `-- default `-- www 32 directories /Users/iwata/tmp/hoyapp %
なお,ファイル・ディレクトリの生成は,すべて PROJECT_ROOT 以下のみに行われます,念のため.
サーバ起動スクリプトの修正
PROJECT_ROOT/bin 下には,plackup をラップした plackup-simple.sh というシェルスクリプトがあります.このファイルを 1行修正します.
1 2 3 4 5 6 7 8 9 10 | #!/bin/sh HOYADIR=/path/to/Hoya HOST=localhost ENABLE_LOGGER=1 PROJECT_ROOT=$(cd $(dirname $0)/../ && pwd) SITE_NAME=$1 SERVER_PORT=$2 |
3行目の「HOYADIR=」の値に,先の HOYADIR を設定します.
サーバの起動
修正した PROJECT_ROOT/bin/plackup-simple.sh を実行します.次のようなメッセージの後,リクエスト待機状態となります.
/Users/iwata/tmp/hoyapp % ./bin/plackup-simple.sh PERL_VER: 5.12.1 PLACK_ENV: development $SITE_NAME is not specified. Set to 'default'. SITE_NAME: default $SERVER_PORT is not specified. Set to '5000'. SERVER_PORT: 5000 SERVER_USER: iwata PSGI_FILE: /Users/iwata/tmp/hoyapp/www/default.psgi Watching www pl lib conf /Works/Hoya/master/lib /Works/Hoya/master/extlib /Users/iwata/tmp/hoyapp/www/lib /Users/iwata/tmp/hoyapp/www/default.psgi for file updates. HTTP::Server::PSGI: Accepting connections at http://localhost:5000/
モジュールが足りなかったりすると,次のように失敗するので,随時モジュールを追加する必要があります.
... PSGI_FILE: /Users/iwata/tmp/hoyapp/www/default.psgi Watching www pl lib conf /Works/Hoya/master/lib /Works/Hoya/master/extlib /Users/iwata/tmp/hoyapp/www/lib /Users/iwata/tmp/hoyapp/www/default.psgi for file updates. Error while loading /Users/iwata/tmp/hoyapp/www/default.psgi: Can't locate Hoge.pm in @INC (@INC contains: /Works/Hoya/master/lib /Works/Hoya/master/extlib lib /Users/iwata/perl5/perlbrew/perls/perl-5.12.1/lib/site_perl/5.12.1/darwin-2level /Users/iwata/perl5/perlbrew/perls/perl-5.12.1/lib/site_perl/5.12.1 /Users/iwata/perl5/perlbrew/perls/perl-5.12.1/lib/5.12.1/darwin-2level /Users/iwata/perl5/perlbrew/perls/perl-5.12.1/lib/5.12.1 .) at /Users/iwata/tmp/hoyapp/www/default.psgi line 32. BEGIN failed--compilation aborted at /Users/iwata/tmp/hoyapp/www/default.psgi line 32.
※ 現状では,依存モジュールを自動で...ということができてません><
Hello, world.
ポート番号 5000 で localhost にアクセスしてみると,次のような感じになります.
上のように表示されれば,Hoyaアプリケーションが(たぶん)無事動作したことになります.
付け足してみる
ごく簡単なチュートリアル(?)ということで.
手順
- テキトーにアクセス
- URL・アクションマッピングの設定
- アクションの記述
- ビューの記述
- 再度アクセス
テキトーにアクセス
URLを http://localhost:5000/user/1234?message=こんにちは としてアクセスしてみると,次のように表示されます.
何か出ましたね.
URL・アクションマッピングの設定
Hoyaアプリケーションは,「どんなURLの場合に,どんな処理を行うか」を基本としています.これを「URL・アクションマッピング」と呼んでいます.(「アクション」は「何らかの処理」くらいのイメージで無問題でしょう.)
この設定は,PROJECT_ROOT/conf/urlmap.yml に YAML として記述されています.
プロジェクト構成直後は,次のようになっています.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ---
# variables for 'path-regexp'
VAR:
INT: '\d+'
ABC: '[a-zA-Z]+'
UUID: '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
#--------------------------------------------------------------------------------
#
# main
#
#--------------------------------------------------------------------------------
main:
- ^hello /?$:
- hello
- ^user/ ($INT) /?$:
- [user_id]
- {hoge: ほげほげ}
- user_profile
- .*:
- index |
先の例では,「PATH_INFO が ^/user/ ($INT) /?$ にマッチし,そこにスカラ値として記述されている user_profile という名前のアクションが呼び出されている(,しかし,そのような名前のアクションは存在していない)」というように,予め準備されているルールにヒットするようにしていました.
アクションの記述
user_profile という名前のアクションは,PROJECT_ROOT/pl/action/user/profile.pl に記述することで対応させることができます.
/Users/iwata/tmp/hoyapp % mkdir pl/action/user /Users/iwata/tmp/hoyapp % touch pl/action/user/profile.pl /Users/iwata/tmp/hoyapp % $EDITOR pl/action/user/profile.pl
簡単なサンプルを次に.
# GET メソッドに対する処理 GET { # a: アクション「user_profile」を表すオブジェクト # r: Plack::Request オブジェクト # クエリパラメータ (Hash::MultiValue オブジェクト) my $q = a->q; # URL・アクションマッピングパラメータ (Hash::MultiValue オブジェクト) my $qq = a->qq; # ビューで利用する変数を設定する a->set_var( path_info => r->path_info, message => $q->get('message'), ); a->import_var( user_id => $qq->get('user_id'), hoge => $qq->get('hoge'), list => [qw/aaa bbb ccc ddd/], ); # 必ず文字列を返す!基本は空文字 ''; }; # # GET,POST に共通した事前処理 # BEFORE { '' }; # # POST メソッドに対する処理 # POST { '' }; # # GET, POST に共通した事後処理 # AFTER { '' };
ビューの記述
アクションの記述で,「必ず文字列を返す」とありましたが,ここで返す文字が,どのビューを呼び出すか,の名前となります.(空文字の場合は,アクションの名前と同じ,つまりここでは,user_profile です.)
user_profile というビューは,PROJECT_ROOT/site/default/default/mt/user/profile.mt というファイルに対応します.(ちょっと長ったらしいですが,このあたりの理由はまた後日にでも.)
/Users/iwata/tmp/hoyapp % mkdir site/default/default/mt/user /Users/iwata/tmp/hoyapp % touch site/default/default/mt/user/profile.mt /Users/iwata/tmp/hoyapp % $EDITOR site/default/default/mt/user/profile.mt
ビューのテンプレートとして,Text::MicroTemplate::Extended を採用しているので,このフォーマットに沿って記述することになります.
? extends '_base';
? block title => sub {
id:<?= $user_id; ?>さんのプロフィール -
? }
? block content => sub {
<h2>id:<?= $user_id; ?>さんのプロフィール</h2>
<h3>PATH_INFO</h3>
<p><?= $var->{path_info}; ?></p>
<h3>メッセージ</h3>
<p><?= $var->{message}; ?></p>
<h4>ほげ</h4>
<p><?= $hoge; ?></p>
<h4>リスト</h4>
<ul>
? for (@$list) {
<li><?= $_; ?></li>
? }
</ul>
? }再度アクセス
アクションとビューを記述した状態で,先のURLへもう一度アクセスてみると,次のように表示されます.
デプロイ的な何か
Plack::Handler::Apache2 を経由した mod_perl での動作を確認しています.他の方法については未確認です.
まとめ
とりあえず動きました ><
モデルを定義してこれを利用したり,フォームバリデーションっぽいことを行ったり...などといった踏み込んだことについては,またおいおい触れていきたいと思います.
おわりに
以上,Plack をベースとした Web(サイト|アプリケーション)フレームワーク「Hoya」の現状における概要とかごく簡単な使い方とかについて紹介してみました.
とりあえず動くような実装だったり,無ドキュメントだったり,テストがなかったり,と,なんとまぁ無責任な状態での公開ですが,少しでも興味を持っていただけたなら幸いです.



