The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Waft - A simple web application framework

SYNOPSIS

Waft は、アプリケーションクラスの基底クラスとなって動作する、CGI用の フレームワークである。

    package MyWebApp;

    use base qw( Waft );

    __PACKAGE__->use_utf8;
    __PACKAGE__->set_default_content_type('text/html; charset=UTF-8');

    sub __default__direct {
        my ($self) = @_;

        return 'TEMPLATE';
    }

クラスメソッド waft は、アプリケーションクラスに属するオブジェクトを 生成して、リクエストに応じたメソッドをディスパッチする。

    MyWebApp->waft;

また、テンプレート処理も実装している。

    <%

    use strict;
    use warnings;

    my ($self) = @_;

    %>

    <h1><% = $self->page %></h1>

    <p>
    Howdy, world!
    </p>

DESCRIPTION

Waft は、1ファイルのみで構成された軽量の Webアプリケーションフレームワークであり、Perl 5.005 以上で動作する。(ただし、 UTF-8 を扱うには 5.8.1 以上の Perl と 3.21 以上の CGI が必要。)

リクエストに応じたメソッドのディスパッチ、 オブジェクト変数の保持、 テンプレート処理 等の機能を有する。

DISPATCH

Waft は、リクエストに応じたメソッドをディスパッチする。

CGI が QUERY_STRING を指定されずに単純に GET リクエストされた場合、 Waftは、__default__direct という名前のメソッドを起動する。

    http://www/mywebapp.cgi

    $self->__default__direct を起動する

form.html というページをリクエストされた場合は、__form__direct という名前の メソッドを起動する。

    http://www/myapp.cgi?p=form.html

    $self->__form__direct を起動する

form.html から "send" という名前の SUBMIT によりリクエストされた場合は、 __form__send という名前のメソッド。

    http://www/myapp.cgi?s=form.html&v=&send=

    $self->__form__send を起動する

メソッド __form__send が、"confirm.html" を戻した場合は、Waft は次に、 __confirm__indirect という名前のメソッドを起動する。

    sub __form__send {
        my ($self) = @_;

        return 'confirm.html';
    }

    $self->__confirm__indirect を起動する

ACTION METHOD

Waft がディスパッチするメソッドをアクションメソッドと呼ぶ。 アクションメソッドの名前は、page_idaction_id で構成する。

  • page

    Web の 1ページに相当する単位で、アクションメソッド名の構成と テンプレートの選択のために使用する。$self->page で取得できる。

  • page_id

    page の英数字以外の文字をアンダースコアに変換し、拡張子を除いた文字列。 form.html の場合は "form"、form/header.html の場合は、"form_header" となる。 $self->page_id で取得できる。

  • action

    page へのリクエストの種別。page とともに、 アクションメソッド名を構成する。リンクによるリクエストの場合は "direct"、 FORM からの SUBMIT によるリクエストの場合はその SUBMIT の NAME(以下の例では "send")、

        <input type="submit" name="send" />
                                   ^^^^

    クライアントからのリクエストではなく、メソッドの戻り値で指定された page への内部のページ遷移の場合は "indirect" となる。

    なお、FORM からの SUBMIT によるリクエストにおいて、SUBMIT に NAME が指定されていない場合、action は "submit" となる。

        <input type="submit" />
  • action_id

    action の先頭から . までの文字列。direct の場合は "direct"、move.map.x の場合は "move" となる。

アンダースコア 2つ、page_id、アンダースコア 2つ、action_id を連結した文字列をアクションメソッドの名前とする。

__ page_id __ action_id

return $page

アクションメソッドの戻り値を次に処理する page として、 引き続きアクションメソッドのディスパッチを行う。この場合、action は "indirect" とする。

    return 'confirm.html'; # Waft は次に __confirm__indirect を起動する

ただし、戻り値を以下のように指定する事で、action に "indirect" 以外の値も指定できる。

    return ['form.html', 'direct']; # Waft は次に __form__direct を起動する

もしくは、

    return { page => 'form.html', action => 'direct' }; # same as above

'CURRENT'

"CURRENT" は、"現在のページ" を意味する。すなわち return 'CURRENT' は、 return $self->page と同義である。

    return 'CURRENT';

    return $self->page; # same as above

return 'TEMPLATE'

アクションメソッドの戻り値が "TEMPLATE" の場合、 Waft はアクションメソッドのディスパッチを終了して、page のテンプレート処理に移行する。

    sub __form__direct {

        return 'TEMPLATE'; # form.html のテンプレート処理に移行する
    }

Waft は、"CURRENT" の場合と同様に page を 変更せず、action を "template" として処理する。すなわち return 'TEMPLATE' は以下と同義である。

    return ['CURRENT', 'template'];

もしくは、

    return { page => 'CURRENT', action => 'template' };

begin

Waft の処理の開始時にディスパッチされるメソッド。

         begin
           |
           |<---------------------------+
         before                         |
           |                            |
     ACTION METHOD  return 'other.html' |
           +----------------------------+
           | return 'TEMPLATE'
           |
         before
           |
    TEMPLATE PROCESS
           |
           |
          end

beginbefore の戻り値は、アクションメソッドのそれと同様に処理される。

    sub begin {

        return 'TEMPLATE'; # アクションメソッドをディスパッチせずにテンプレー
                           # ト処理に移行する
    }

before

アクションメソッドをディスパッチする前、およびテンプレート処理を行う前に ディスパッチされるメソッド。

    sub before {
        my ($self) = @_;

        return if $self->page eq 'login.html';

        return 'login.html' if not $self->login_ok;

        return;
    }

end

Waft の処理の終了時にディスパッチされるメソッド。

OBJECT VALUE

Waft が生成するオブジェクトが持つ値をオブジェクト変数と呼ぶ。 オブジェクト変数は QUERY_STRING および FORM に展開され、 ページ遷移後に生成されるオブジェクトに引き継がれる。

    sub __default__direct {
        my ($self) = @_;

        $self->{page} = 0;
        $self->{sort} = 'id';

        return 'TEMPLATE';
    }

    <a href="<% = $self->url('page.html', 'ALL_VALUES') %>">

    page.html へ遷移するリンクの QUERY_STRING にオブジェクト変数が展開される


    sub __page__direct {
        my ($self) = @_;

        $self->{page} # 0
        $self->{sort} # 'id'

QUERY_STRING の場合は、引き継ぐ値、もしくは "ALL_VALUES" の指定が 必要であるが、FORM の場合はメソッド compile_template が自動的に展開する。

    <form action="<% = $self->url %>">
    <input type="submit" />
    </form>

    compile_template が <form></form> の中に自動的に展開する

オブジェクト変数は 1次元のハッシュ変数で管理されるため、 リファレンスを引き継ぐ事はできない。また、undef も引き継ぐ事ができない。

ただし、メソッド set_valuesget_values により 1つのキーでリストを扱う事 ができる。

    $self->set_values( sort => qw( id ASC ) );

    $self->{sort}                # 'id'
    $self->get_value('sort')     # same as above
    $self->get_values('sort')    # ('id', 'ASC')
    $self->get_values('sort', 1) # ('ASC')

TEMPLATE PROCESS

Waft は、Perl コードをスクリプトレットとして処理するテンプレート処理機能を 持つ。

page をテンプレートファイルとして処理する。 テンプレートファイルはアプリケーションクラスおよびその基底クラスのモジュールが 配置されているディレクトリから検索される。

アプリケーションクラス "MyWebApp" が、基底クラス "Waft::CGISession"、"Waft" を 継承している場合、default.html は以下の順に検索される。

    lib/MyWebApp.template/default.html
    lib/MyWebApp/default.html
    lib/Waft/CGISession.template/default.html
    lib/Waft/CGISession/default.html
    lib/Waft.template/default.html
    lib/Waft/default.html

page@Waft::Allow_template_file_exts に定義されていない拡張子 (.html、.css、.js、.txt 以外の拡張子)である場合は、検索されるディレクトリは .template のみとなる。

    lib/MyWebApp.template/module.pm
    lib/Waft/CGISession.template/module.pm
    lib/Waft.template/module.pm

最初に見つかったファイルをテンプレートファイルとして処理する。

テンプレートファイル内の "<%" と "%>" で囲まれた部分はスクリプトレットとして 処理される。

    <% for ( 1 .. 10 ) { %>
        <br />
    <% } %>

"<%word=" と "%>" で囲まれた部分は、評価結果がエスケープされて出力される。

    <% for ( 1 .. 4 ) { %>
        <%word= $_ %> * 2 = <%word= $_ * 2 %><br />
    <% } %>

    1 * 2 = 2
    2 * 2 = 4
    3 * 2 = 6
    4 * 2 = 8


    <% my $break = '<br />'; %>
    <%word= $break %>

    &lt;br /&gt;

"<%word=" は "<%w=" もしくは "<%=" に省略できる。スペースを空ける事もできる。

    <%word=$self->url%>
    <%w= $self->url %>  <!-- same as above -->
    <% = $self->url %>  <!-- same as above -->

"<%text=" と "%>" で囲まれた部分は、評価結果がエスケープされ、 さらにタブ文字の展開と改行タグの挿入が行われて出力される。

    <% my $text = "Header\n\tItem1\n\tItem2"; %>
    <%text= $text %>

    Header<br />
    &nbsp; &nbsp; &nbsp; &nbsp; Item1<br />
    &nbsp; &nbsp; &nbsp; &nbsp; Item2

"<%text=" は "<%t=" に省略できる。 "<%word=" と同様にスペースを空ける事もできる。

    <%text=$self->{text}%>
    <% t = $self->{text} %> <!-- same as above -->

"<%jsstr=" と "%>" で囲まれた部分は、JavaScript に必要なエスケープが行われる。

    alert('<%jsstr= '</script>' %>');

    alert('\x3C\/script\x3E');

"<%jsstr=" は "<%j=" に省略できて、他と同様にスペースも空けられる。

METHODS

set_waft_backword_compatible_version

引数: $version

クラスメソッド。Waft の過去のバージョンを保持する。いくつかのメソッドと処理が 指定バージョンの仕様になる。

use_utf8

クラスメソッド。内部処理を UTF-8 で行う。5.8.1 以上の Perl と 3.21 以上の CGI が必要。

set_allow_template_file_exts

引数: @extensions

クラスメソッド。クラスのモジュールが配置されているディレクトリから検索する 対象とするテンプレートファイルの拡張子を保持する。詳細は "TEMPLATE PROCESS" を参照の事。

set_default_content_type

引数: $content_type

クラスメソッド。"header" で Content-Type が指定されない場合の値を保持する。 デフォルトは text/html。

waft

引数: @arguments?

戻り値: @return_values

オブジェクトの生成("new")、初期化("initialize")を行い、Waft の処理を 行う。オブジェクトメソッドの場合は Waft の処理のみを行う。Waft の処理の詳細は "DISPATCH" を参照の事。指定された引数を最初に呼ぶメソッドに渡し、最後に 呼んだメソッドの戻り値を戻す。

new

戻り値: $object

クラスメソッド。オブジェクトの生成を行う。

initialize

戻り値: $object

オブジェクトの初期化を行う。

cgi

戻り値: $cgi

CGI オブジェクトを戻す。

set_value

引数: $key, $value

オブジェクト変数に値を保持する。

set_values

引数: $key, @values?

オブジェクト変数に複数の値を保持する。

get_value

引数: $key, $i?

戻り値: $value

オブジェクト変数の値を戻す。指定された引数を複数の値に対する添え字とする。

get_values

引数: $key, @i?

戻り値: @values

オブジェクト変数の複数の値を戻す。指定された引数を添え字とする。

clear_values

オブジェクト変数を全て削除する。

page

戻り値: $page

page を戻す。

action

戻り値: $action

action を戻す。

引数: $response_header

レスポンスヘッダを保持する。"output" が呼ばれるまでに呼ばれる必要がある。 add_header という別名もある。

http_status

引数: $http_status?

戻り値: $http_status

Status: ヘッダを保持する。Status: ヘッダが存在する場合は置き換える。

引数が指定されない場合は、出力した Status: ヘッダの値を戻す。

content_type

引数: $content_type?

戻り値: $content_type

Content-Type: ヘッダを保持する。Content-Type: ヘッダが存在する場合は 置き換える。

引数が指定されない場合は、出力した Content-Type: ヘッダの値を戻す。

call_template

引数: $page or $template_path, @arguments?

戻り値: @return_values

引数に指定されたページ、またはパスのファイルのテンプレート処理を行う。詳細は "TEMPLATE PROCESS" を参照の事。include という別名もある。

url

引数: $page, \@keys? and/or @key_value_pairs?

戻り値: $url

URL を戻す。引数に指定されたページとオブジェクト変数のキー、キー値ペアを クエリ文字列に構成する。

    $self->{page} = 0;
    $self->{sort} = 'id';

    $self->url('CURRENT', ['page', 'sort']);
    # { page => 0, sort => 'id' } となる URL

    $self->url('CURRENT', ['page']);
    # { page => 0 } となる URL

    $self->url('CURRENT', ['page'], sort => 'name');
    # { page => 0, sort => 'name' } となる URL

    $self->url('CURRENT', page => 1, sort => 'name');
    # { page => 1, sort => 'name' } となる URL

absolute_url

引数: $page, \@keys? and/or @key_value_pairs?

戻り値: $absolute_url

http://、または https:// から始まる URL を戻す。

output

引数: @strings?

引数に指定された値を出力する。テンプレート処理でも使用する。最初に 呼ばれた時には、"header" で指定されたレスポンスヘッダも出力する。

get_content

引数: $coderef, @arguments?

戻り値: $content, @return_values

引数で指定された無名サブルーチンを呼ぶ。その間 "output" に値を出力させずに バッファリングさせて、バッファの内容を戻す。

stash

引数: $class?

戻り値: $hashref

クラスの名前(引数に指定されたクラス、引数が指定されない場合は呼び出し元の クラスの名前)毎に保持する stash のリファレンスを戻す。stash は アプリケーションが自由に使用できるハッシュ変数。

html_escape

引数: @values

戻り値: @escaped_values

エスケープを行う。テンプレート処理でも使用する。

jsstr_escape

引数: @values

戻り値: @escaped_values

JavaScript に必要なエスケープを行う。テンプレート処理でも使用する。

url_encode

引数: @values

戻り値: @encoded_values

URL エンコードを行う。"url""absolute_url" でも使用する。

warn

引数: @messages?

アプリケーションクラスを呼び出し元とする警告メッセージを出力する。

    package MyWebApp::Base;

    use base qw( Waft );

    use Carp;

    sub foo {
        my ($self) = @_;

        warn 'error';         # error at - line 10. # here
        carp 'error';         # error at - line 31
        $self->warn('error'); # error at - line 24.

        return;
    }

    package MyWebApp;

    use base qw( MyWebApp::Base );

    sub foo {
        my ($self) = @_;

        $self->next;          # line 24

        return;
    }

    package main;

    MyWebApp->new->foo;       # line 31

die

引数: @messages?

戻り値: ( $page?, @messages )?

"warn" と同様のメッセージを出力する。無効コンテキストの場合は例外を 発生させる。

無効コンテキストでない場合、例外は発生させない。"output" が呼ばれていない 場合は、"internal_server_error", @messages を戻す。これは return への 引数として使用する事を想定した動作である。

    return $self->die('Permission denied');

この結果、Waft に定義されているアクションメソッド __internal_server_error__indirect を呼び、Waft の処理を完了する。

"output" が呼ばれている場合は、@messages のみを戻す。

next

引数: @arguments

戻り値: @return_values

継承元の同名のメソッドを呼ぶ。

AUTHOR

Yuji Tamashiro, <yuji@tamashiro.org>

COPYRIGHT AND LICENSE

Copyright (C) 2007-2009 by Yuji Tamashiro

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.