モダンPerlの世界へようこそ

第9回 Jifty:一足早いクリスマスプレゼント

この記事を読むのに必要な時間:およそ 5.5 分

ビューもDSLで

続いてビューを作成しましょう。エディタでこのようなlib/MyApp/View.pmを作成してください。テンプレートには,当初はHTML::Masonが使われていましたが,いまはTemplate::Declareを利用するのが主流になっています。

package MyApp::View;

use strict;
use warnings;
use Jifty::View::Declare -base;
use Time::Piece;

template 'list' => page {
  my $user = get('user');

  if (Jifty->web->current_user->id == $user->id) {
    h1 { "Your tweets" }
    show 'form';
  }
  else {
    h1 { "Tweets by $name..." }
  }

  my $entries = MyApp::Model::EntryCollection->new;

  $entries->order_by( column => 'epoch', order => 'DESC' );
  $entries->rows_per_page(15);
  $entries->limit( column => 'user_id', value => $user->id );

  while (my $entry = $entries->next) {
    show('_entry' => $entry);
  }
};

template 'entry' => page {
  my $entry = get('entry');

  show('_entry' => $entry);
};

設定がメインのJiftyのDSLとは違って,こちらは出力がメインなので連結詞は使われていませんが,注意深い方なら当然セミコロンがあるべきはずのいくつかの場所にセミコロンがないことに気がつかれたかもしれません。かならずしもすべてのセミコロンを省略できるわけではありませんし,特にJavaScriptが絡むところでセミコロンを省略すると思いがけないバグに遭遇する可能性も高くなるのですが,これもTemplate::Declareの魔法のひとつです。

private template '_entry' => sub {
  my ($self, $entry) = @_;

  div { $entry->body }
  p {
    my $time = localtime($entry->epoch);
    span { outs "by " . $entry->user->name .
                " at " . $time->date . ' ' . $time->time }
    span {
      my $url = join '/', "/user", 
                          $entry->user->name,
                          $entry->epoch;
      hyperlink( url => $url, label => 'permalink' );
    }
  }
};

一覧と個別のエントリで共通に使える小さな部品はプライベートテンプレートとしてくくりだしておきました。$entry->user->nameの部分では外部キーによる参照を行っています。

private template 'form' => sub {
  my $user = get('user');
  my $name = $user->name;

  my $action = new_action(
    class   => 'MyApp::Action::CreateEntry',
    moniker => 'create_entry',
  );

  div { attr { class => 'Form' }
    Jifty->web->form->start(submit_to => "/user/$name/post");
    div {
      render_param( $action => 'body', focus => 1 );
      Jifty->web->return(
        submit    => $action,
        label     => 'Tweet',
        as_button => 1,
      );
    };
    Jifty->web->form->end;
  }
};

1;

Jiftyのフォームはふつう対応するアクションと密接に結びついています。データベースのCRUDや検索はすべて専用のアクションを用意するのがJiftyの流儀です※2)⁠

※2

もっとも,標準的な動作をさせたいだけならわざわざアクションを用意する必要はありません。Jiftyがモデルの定義を見て自動的に用意してくれます。

Jiftyのアクション

ここではとりあえず作成用のアクションだけ用意しましょう。シェルから次のコマンドを実行してください。Entryモデルにひもづけられたアクションのひな形が用意されます。

> jifty action --name CreateEntry

アクションにはモデルの定義によく似たパラメータの定義を用意できます。monikerはこのアクションの識別名です(省略すると自動生成されますが,このように明示的にアクションを用意する場合は省略しないほうが無難のようです)⁠

use Jifty::Action schema {
  param body =>
    label is '',
    type is 'text',
    display_length is 40,
    max_length is 255,
    sticky is 0;
};

sub moniker { 'create_entry' }

実際のアクションの中身はtake_actionというメソッドの中に書きます。ここではエントリを作成したあと,/homeにリダイレクトさせています。

sub take_action {
  my $self = shift;

  my $entry = MyApp::Model::Entry->new;
  $entry->create(
    body    => $self->argument_value('body'),
    epoch   => time,
    user_id => $self->current_user->id,
  );

  Jifty->web->next_page("/home");

  $self->report_success if not $self->result->failure;
  return 1;
}

これでひとまず動くアプリケーションができました。サーバを起動して,JavaScriptのオンオフを切り替えたりしながらアプリケーションの挙動を確かめてみてください。

単純に比較するのは間違っていますが

なるべく本体は軽くしてCPANモジュールの触媒,⁠のり」に徹することを目指したCatalystと,インストールしたらすぐに使える便利なフレームワークを目指したJiftyを,そのままの状態で比較するのは不公平というものでしょう。

でも,いくらCatalystに定番のコンポーネントを追加したところで(それどころか,前回取り上げたReactionを追加してさえ)⁠Jiftyが(あるいはRuby on Railsや,Rails以降の各種フレームワークが)標準で提供している使い勝手には届かないのも厳然たる事実です。

もちろんCatalystにはCatalystの長所がありますし,JiftyにはJiftyの短所もあるのですが,もし身近に「PerlのフレームワークなんてWeb 1.0的なものばかりじゃないか」とお嘆きの方がいるようでしたら,ぜひJiftyをすすめてみてください。

国内ではあまり大きな採用実績はありませんが,海外ではJiftyの開発元であるBest Practical Solutions社が展開するHiveminderというサービスのほか,CPANのバグトラッキングシステムとして採用されているRTの次期バージョンがJiftyベースで書き直されて,いま最後の調整段階に入っているところです。

著者プロフィール

石垣憲一(いしがきけんいち)

あるときは翻訳家。あるときはPerlプログラマ。先日『カクテルホントのうんちく話』(柴田書店)を上梓。最新刊は『ガリア戦記』(平凡社ライブラリー)。

URLhttp://d.hatena.ne.jp/charsbar/

コメント

コメントの記入