時計を壊せ

駆け出してからそこそこ経ったWebプログラマーの雑記

How to use Sledge - 基本編

Sledgeの使い方のまとめです。個人用のメモのようなものなので誰かの役に立つかは不明です。
僕自身が初心者のようなものなのでフレームワーク初心者にも読みやすいかも知れません。もしかしたら。

とりあえず今回は基本編です。

はじめに

Sledgeを知らない人のために。

免責事項

あくまでもこの文書はPerl暦実質4年程度でMVCフレームワークを使った開発を始めてSledgeで体験したの19歳の学生が書いたものです。
内容に一部誤りがある可能性があります。これを信用してSledge環境を構築/利用して何らかの損害が発生しても一切責任は取れませんのでご了承下さい。
また、間違っている部分がありましたらTwitterかコメント欄、トラックバック等でご指摘・ご教授頂けると有難いです。
あと、やたら長いですが怒らないで下さい。

Sledgeとは

MVCフレームワーク*1です。
Perlを使って手軽にWebアプリケーション*2を作る事が出来ます。(Webアプリケーションとして作るメリットとデメリットはWikipediaを参照。)
似たようなものにCatalystCGI::ApplicationMENTAArk等があります。

Sledgeを使うメリット
  1. Webアプリケーションを比較的楽に作成する事ができます。
  2. mod_perl環境で動作する事を前提に作られています。自分で書いたコードがmod_perl環境で動作する事を前提に作られていれば、mod_perl環境でもほぼ確実に動作します。
  3. CGI環境でもソースコードを殆ど変更せずに動作します。
  4. デフォルトでSQLデータベースサーバーを使ったセッション管理をほとんど意識せずに行う事が出来ます。
  5. SourceforgeCPANで多数のモジュールが提供されています。
Sledgeを使うデメリット
  1. Apache2 + mod_perl2に対応していません。(ただし自分で改造して対応する事は可能です。)
  2. インストールにmod_perlが必要です。(Pure PerlなのでforceインストールすればCGIモードは使えるかも。未確認。)
  3. CGI環境で運用する場合、動作速度に難があります。

導入編

【予言】導入から引っかかります。

Sledgeの動作環境

Sledgeの動作には次のソフトウェアが必要です。

まずはこれらをインストールしましょう。makeとgccは殆どの場合デフォルトで入っていると思います。
FreeBSDならportsでapache13-modperl*4mod_perl*5とperl5.12*6をインストールしちゃえばOKだと思います。(他のBSD系でこれらのportsがあるかは知りません)
しかしLinux系ではApache1.3とmod_perl1.3について殆どパッケージは提供されていなかったと思うのでソースコードをダウンロードして展開して./configureしてmakeしてmake installしなきゃいけないかもしれません。頑張って下さい。

また、Sledgeのインストールには次のPerlモジュールが必要です。

  • Apache::Request
  • Apache::Reload
  • CGI
  • Test::Inline
  • Carp::Assert
  • Class::Fields
  • Class::Accessor
  • Class::Data::Inheritable
  • Class::Singleton
  • Class::Trigger
  • Digest::SHA1
  • File::Spec
  • File::Temp
  • HTML::FillInForm
  • HTML::Template
  • HTML::StickyQuery
  • IO::Stringy
  • Jcode
  • LWP
  • Test::Simple
  • Test::Harness
  • Time::HiRes
  • URI
  • Errno
  • Template
  • Data::Properties
  • Error
  • Storable
  • Encode::compat

ここまではBundle::Sledgeでインストール出来ます。これらは展開したディレクトリ内のeg/prereq-modulesに記述されています。
これ以外にもDBIとか使ってるので、もしインストールされていなければtestをするときにエラーが出るかもしれません。

Sledgeのインストール

Sledgeはここでダウンロード出来ます。
Unixはfetch、Linuxwgetでダウンロードすると良いでしょう。いや別にw3mlynxでダウンロードしてもいいですけど。

(実際のURLとは若干異なります)

$ fetch http://sourceforge.jp/frs/redir.php?m=jaist&f=%2Fsledge%2F8401%2FSledge-x.x.tar.gz

さて、ダウンロードが完了したら早速展開て展開先のディレクトリに移動しましょう。

(実際のファイル名等とは若干異なります)

$ tar zxvf Sledge-x.x.tar.gz
$ cd ./Sledge-x.x

ここからが正念場です。まずはSledgeの依存モジュールをインストールしましょう。
スーパーユーザーになるのを忘れてはいけません。

$ su
# cpan -i Bundle::Sledge

もしPerlを導入したばかりであればインストールすら始まらないうちにエラーが出るかも知れません。
その場合、YAMLモジュールをCPANを使わずに手動でインストールしてcpanの設定を適切に設定し直せば正常に動作する可能性があります。
基本的にtestでResult: PASSが出ればインストールは成功します。

依存モジュールのインストールが完了したらSledge本体のインストールに移りましょう。
まずは、

$ perl Makefile.PL

Makefileを生成しましょう。
ここで

Checking if your kit is complete...
Looks good
Writing Makefile for Sledge

と表示されればOKです。

もしここで、

が表示されていたらmod_perlのインストールに失敗しています。
それ以外のモジュール名が表示された場合はそのモジュールのインストールに失敗しています。

OKならば次のステップに進みましょう。

$ make
$ make test

makeはよっぽどの事が無い限り通ります。問題はmake testです。

一部のtestで

Subroutine HTML::Template::new redefined at t/02_template.t line 67.
Subroutine Sledge::Registrar::context redefined at /home/xxx/Sledge-x.x/blib/lib/Sledge/Pages/Base.pm line 79.
Subroutine Mock::Pages::redirect redefined at t/52_rewrite_query.t line 46.
Subroutine Sledge::Pages::Base::redirect redefined at t/51_sticky_query.t line 52.
Use of uninitialized value in hash element at /home/xxx/Sledge-x.x/blib/lib/Sledge/SessionManager/Cookie.pm line 16.

という警告が表示されるかもしれませんがこれらは無視しても問題有りません。

もし、

Dubious, test returned

と表示された場合はそのtestに失敗しています。
私の環境では、

Can't locate object method "__triggers" via package "Test::Pages" at t/11_hooks.t line 9.
Can't call method "getline" on an undefined value at t/30_upload.t line 93, chunk 1.

というエラーが表示されました。
上のエラーについてはここを見て対処して下さい。
下のエラーは/tmpを別のパーティーションにしていると起きるエラーです。このエラーが起きているとファイルのアップロードが行えません。
ですが、別で提供されているSledge-Plugin-SaveUploadを導入すればエラーが出る部分の代替機能が提供されるのでこのエラーは無視して大丈夫です。(ただし、その場合linkではなくsaveを使う事になります)

さて、OKならついにインストールです。
インストールはスーパーユーザーで行わなければならないのでスーパーユーザーになるのを忘れないで下さい。

$ su
# make install
# exit
$ rehash

これでインストールは完了です。

試作編

新しいフレームワークを使い始めるときはHelloWorldから。定石ですね。

Sledgeを使ったWebアプリケーションを作る前に

まずはセッションの管理方法とテンプレートについて決めてしまいましょう。
Sledgeのセッション管理モジュールには主に使われるもので次のものがあります。

<Sledge::Session系>(サーバー側のセッションの管理方法を決めるモジュール)

Sledge::Session::File ファイルを使ってセッションを管理します。
Sledge::Session::MySQL MySQLを使ってセッションを管理します。
Sledge::Session::Pg PostgreSQLを使ってセッションを管理します。
Sledge::Session::SQLite SQLiteを使ってセッションを管理します。

<Sledge::SessionManager系>(セッションIDの受け渡しの方法を決めるモジュール)

Sledge::SessionManager::Cookie Cookieを使ってセッションIDの受け渡しを行ないます。
Sledge::SessionManager::StickyQuery QUERY_STRINGからセッションIDを受け取ります。セッションIDはHTMLに埋め込んで渡します。
Sledge::SessionManager::Rewrite Sledge::SessionManager::StickyQueryとほぼ同じ事をmod_rewriteを使って行ないます。

<特殊なセッション管理を行うモジュール>(特殊な動作をします。詳しくはpodを読んで下さい。)

Sledge::SessionManager::CookieStore Cookieにセッションデータを埋め込みます。別口でインストールします。

Sledgeのテンプレート処理モジュールには主に使われるもので次のものがあります。

<Sledge::Template系>(テンプレートの処理方法を決めるモジュール)

Sledge::Template HTML::Templateを使ってテンプレートを処理します。
Sledge::Template::TT Template-Toolkitを使ってテンプレートを処理します。

今回は例として

  • Sledge::Session::File
  • Sledge::SessionManager::Cookie
  • Sledge::Template::TT

を使ってソースコードを書いていきます。

雛形の作成

まずは雛形を作りましょう。Sledgeのインストール時に同時にインストールされるsledge-setupを使います。
今回は公式CVSにあるサンプルと同じディレクトリ構成で作ることを想定します。
今回はHelloWorldという名前でプロジェクトを作ります。
Sledgeで作ったWebアプリケーションを/usr/local/www/sledge/上にディレクトリを作ってそこに置く事を想定します。(別にアクセス出来ればどこでもokです)

$ mkdir -p /usr/local/www/sledge/HelloWorld/htdocs/
$ mkdir /usr/local/www/sledge/HelloWorld/lib/
$ mkdir /usr/local/www/sledge/HelloWorld/view/
$ mkdir /usr/local/www/sledge/HelloWorld/session/
$ cd /usr/local/www/sledge/HelloWorld/lib/
$ sledge-setup HelloWorld

これを実行し、

mkdir HelloWorld
mkdir HelloWorld/Config

Initial setup for HelloWorld is now finished.

Remember:

1) Edit HelloWorld/Config/_common.pm
2) Make session table.

    Thanks for using Sledge!
              - Sledge development team

といった表示が出れば成功です。
これでプロジェクトの雛形が出来ました。

プロジェクトの設定

次にプロジェクトの設定を行います。

1) Edit HelloWorld/Config/_common.pm
2) Make session table.

とありますが今回はセッション管理にSledge::Session::Fileを使うので2)は行う必要はありません。
(もちろん、データベースを使ったセッション管理を行う事も想定する場合はこの限りではありません)

まずは、エディタで./HelloWorld/Config/_common.pmを開きましょう。vimでもemacsでもnviでも何でも良いです。

するとこんなソースが見れる筈です。

package HelloWorld::Config::_common;
use strict;
use vars qw(%C);
*Config = \%C;

$C{TMPL_PATH}     = '/path/to/tmpl_dir';
$C{DATASOURCE}    = [ 'dbi:mysql:sledge','root', '' ];
$C{COOKIE_NAME}   = 'sledge_sid';
$C{COOKIE_PATH}   = '/';
$C{COOKIE_DOMAIN} = undef;

1;

SledgeではこのCという連想配列を使って設定情報を管理します。
では、早速編集していきましょう。

まず、$C{TMPL_PATH}でテンプレートが保存してあるディレクトリを指定します。(今回は/usr/local/www/sledge/HelloWorld/view/ですね)
つぎに、今回は$C{DATASOURCE}は使用しないのでコメントアウトします。(もちろん、データベースを使ってセッション管理をする場合は必要です)
そして、今回はSledge::Session::Fileでセッション情報を保存するディレクトリを指定するので$C{SESSION_DIR}を設定します。
また、$C{COOKIE_*}にはセッションCookieの名前やその有効ドメインや有効パスが入っています。
そのままでも動作はしますがセッションIDが漏れてしまい、なりすましに利用される恐れがあります。
また、このCookie nameではクライアントにSledgeを使ってWebアプリケーションを作っている事が分かってしまい、Sledgeの脆弱性*7を突いた標的にされやすくなってしまいます。
Cookieの適切に設定を行う事でより安全なWebアプリケーションを作成する事が出来ます。
もちろん最低でもuse struct;。use warnings;もした方が良いです。

仮にhttp://hoge.net/helloworld/上にトリガとなるスクリプト(後述)を配置する場合、

package HelloWorld::Config::_common;
use strict;
use warnings;
use vars qw(%C);
*Config = \%C;

$C{TMPL_PATH}     = '/usr/local/www/sledge/HelloWorld/view/';
#$C{DATASOURCE}    = [ 'dbi:mysql:sledge','root', '' ];
$C{SESSION_DIR}   = '/usr/local/www/sledge/HelloWorld/session/';
$C{COOKIE_NAME}   = 'helloworld_sid';
$C{COOKIE_PATH}   = '/helloworld/';
$C{COOKIE_DOMAIN} = 'hoge.net';

1;

こんな感じになると思います。

次に、./HelloWorld/Pages.pmを編集します。
デフォルトのPages.pmは以下のようになっていると思います。

package HelloWorld::Pages;
use strict;
use Sledge::Pages::Compat;

use Sledge::Authorizer::Null;
use Sledge::Charset::Default;
use Sledge::SessionManager::Cookie;
use Sledge::Session::MySQL;
use Sledge::Template::TT;

use HelloWorld::Config;

sub create_authorizer {
    my $self = shift;
    return Sledge::Authorizer::Null->new($self);
}

sub create_charset {
    my $self = shift;
    return Sledge::Charset::Default->new($self);
}

sub create_config {
    my $self = shift;
    return HelloWorld::Config->instance;
}

sub create_manager {
    my $self = shift;
    return Sledge::SessionManager::Cookie->new($self);
}

sub create_session {
    my($self, $sid) = @_;
    return Sledge::Session::MySQL->new($self, $sid);
}

1;

ソースを読めば分かる通り、Pages.pmではクラスのオブジェクト作ってそれを返す事だけをしています。
違う方法でセッション管理をしたかったり、違うライブラリの提供するテンプレートを使いたかったりしたい場合には、
ここでオブジェクトを生成するクラスを変えて、さっきの_common.pmでそのクラスで使用するオプションを適切に設定すればOKです。

今回はSledge::Session::MySQLでは無くSledge::Session::Fileを使うので以下のようになります。

package HelloWorld::Pages;
use strict;
use warnings;
use Sledge::Pages::Compat;

use Sledge::Authorizer::Null;
use Sledge::Charset::Default;
use Sledge::SessionManager::Cookie;
use Sledge::Session::File;
use Sledge::Template::TT;

use HelloWorld::Config;

sub create_authorizer {
    my $self = shift;
    return Sledge::Authorizer::Null->new($self);
}

sub create_charset {
    my $self = shift;
    return Sledge::Charset::Default->new($self);
}

sub create_config {
    my $self = shift;
    return HelloWorld::Config->instance;
}

sub create_manager {
    my $self = shift;
    return Sledge::SessionManager::Cookie->new($self);
}

sub create_session {
    my($self, $sid) = @_;
    return Sledge::Session::File->new($self, $sid);
}

1;

これでプロジェクトの設定は完了です。

テンプレートの作成

テンプレートについてはHTML::TemplateやTemplate-Toolkitの資料がWebに大量にあるので、そちらをを参照して下さい。
ここのプロジェクトでは以下の様なテンプレートがあると仮定します。

<?xml version="1.0" encoding="EUC-JP"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=EUC-JP" />
    <title>[% title %]</title>
    </head>
  <body>
    <h1>[% title %]</h1>
    <p>Sledgeは[% IF mod_perl_flag==1 %]mod_perl[% ELSE %]CGI[% END %]で動作しています。</p>
  </body>
</html>

これを先ほど指定した$C{TMPL_PATH}*8にindex.htmlとして保存して下さい。
拡張子は必ず.htmlでなければならない点に注意して下さい。.tmpl等で保存してはいけません。
[2010/8/16追記]html以外の拡張子を使う事も可能ですが後述するdispatch_*メソッドで、テンプレートを*.htmlとして自動的に読み込む事が出来ないのでload_tmplメソッドで別途テンプレートを読み込む必要があります。

Pagesクラスの作成

Webアプリケーションの本質的な処理を行う、Pagesクラスを作成します。
このクラスで先程の./HelloWorld/Pages.pmを継承させる事でPagesクラスになります。
クラス名は何でも良いんですがここではHelloWorld::Pages::Indexとしましょう。
HelloWorldと表示してmod_perlで動いているかCGIで動いているか教えてるページを先程のテンプレートを使って作って表示したい場合こうなります。

package HelloWorld::Pages::Index;

use strict;
use warnings;
use base qw(HelloWorld::Pages);

__PACKAGE__->tmpl_dirname('.');

sub dispatch_hello{
    my $self = shift;

    $self->tmpl->param(
        title => 'HelloWorld!',
        mod_perl_flag => defined($ENV{MOD_PERL})
    );
}

1;

では各所の意味を解説していきます。

__PACKAGE__->tmpl_dirname('.');

ここでテンプレートの存在するディレクトリを、先ほど指定した$C{TMPL_PATH}からの相対パスで指定しています。
今回は$C{TMPL_PATH}に直接テンプレートを置いたので.を指定していますが、.の場合はこの行は省略可能です。

sub dispatch_hello{
    my $self = shift;

    $self->tmpl->param(
        title => 'HelloWorld!',
        mod_perl_flag => defined($ENV{MOD_PERL})
    );
}

ここがWebアプリケーションの実質的な核になります。
ここで入力に応じて処理を行って結果を返したりリダイレクトしたりするわけです。
dispatch_*の*には好きな名前をいれる事が出来ます。好きな人の名前でもOKです。
実際は提供する機能の名前を入れる事になるでしょう。
このサンプルではHelloWorld!を表示するのでhelloとしています。
そして、このdispatch_helloの場合はhelloがデフォルトのテンプレート名になるので、
hello.htmlをテンプレートとして利用します。
もし別のテンプレート(hoge)を利用したい場合は、

$self->load_template('hoge');

とするとテンプレートとしてhogeを利用します。

また、

    $self->tmpl->param(
        title => 'HelloWorld!',
        mod_perl_flag => defined($ENV{MOD_PERL})
    );

ここでテンプレートモジュールに渡すパラメータを指定しています。
$ENV{MOD_PERL}が定義されていればmod_perlで動作しています。

このdispatch_*メソッドはひとつのモジュール内にいくらでも作成する事が出来ます。
しかし実際には別のクラスに分けて作成した方が機能拡張時に有利に働く場合が多いでしょう。
理由は別の機会に解説すると思います。

トリガの作成

要するに、ユーザーがアクセスするファイルですね。
このファイルにユーザーがアクセスすると、このSledgeプロジェクトが実行されることになります。

HelloWorld::Pages::Indexにあるdispatch_helloでWebアプリケーションの主な処理を行いたい場合、
一番シンプルなトリガは以下のようになります。

#!/usr/bin/perl
use strict;
use warnings;
use HelloWorld::Pages::Index;

HelloWorld::Pages::Index->new->dispatch('hello');

もちろん、mod_perlとして動作させる場合は

#!/usr/bin/perl

は不要です。
また、必要に応じて/usr/bin/perlは実際のPerlのパスに書き換えて下さい。
これを/usr/local/www/sledge/HelloWorld/htdocs/にindex.cgiとして保存してこの工程は完了です。
これもファイル名は自由に決めてOKです。

仕上げ

まずは実行出来る状態にするためにパーミッションを変えます。

$ chmod -R 705 /usr/local/www/sledge/HelloWorld/

次に、httpd.confを編集します。
mod_perlとして動作させる場合は、〜に以下のものを追加して下さい。

  Alias /helloworld/ "/usr/local/www/sledge/HelloWorld/htdocs/"
  <Location //helloworld>
    SetHandler perl-script
    PerlHandler Apache::Registry
    SetEnv PERL5LIB /usr/local/www/sledge/HelloWorld/lib/
    Options +ExecCGI
    PerlSendHeader On
  </Location>

CGIとして動作させる場合は、〜に以下のものを追加して下さい。

  ScriptAlias /helloworld/ "/usr/local/www/sledge/HelloWorld/htdocs/"
  <Directory "/usr/local/www/sledge/HelloWorld/htdocs/">
    SetEnv PERL5LIB /usr/local/www/sledge/HelloWorld/lib/
    Options ExecCGI
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>

こんな感じで設定したらapacheの再起動をかけます。
これでSledgeを使ったWebアプリケーションが実行出来る環境が整いました。
あとはhttp://hoge.net/helloworld/index.cgiにアクセスすれば良いと思います。
(localでテストする場合はhostsにhoge.netを追加するのを忘れずに!)

まとめ

  • マニュアルって書くの大変なんですね。
  • てかマニュアル書くつもりがチュートリアルになっとる。
  • でも初心者には分かりやすいかなぁ。
  • 理解しがたいところは解説したつもりです。
  • 最後まで読んで頂き有難う御座いました。

もし良かったら質問・批判・感想・アドバイスを書いていって下さい。

*1:ライブラリや枠組みを提供するライブラリ。

*2:ウェブの機能や特徴を利用したアプリケーションの事。(Wikipediaより引用)

*3:Plain Old Document

*4:/usr/ports/www/apache13-modperl/

*5:/usr/ports/www/mod_perl/

*6:/usr/ports/lang/perl5.12/

*7:本当にあるか、どんなものがあるかは知りません。

*8:/usr/local/www/sledge/HelloWorld/view/