僕のYak Shavingは終わらない

車輪の再発明をやめたらそこには壮大なYakの群れが

Perlの軽量フレームワークAmon2::Liteでmarkdownその他のリアルタイムプレビュー、にTracを追加!!

最近もっとPerl使いになりたい!って思ったのとCatalyst以外のフレームワークを使ってみたいって気持ちが相まって探していたら以下の記事を発見。

TinyURLをつくってみよう 〜 軽量フレームワークAmon2入門 (4) 〜 - tokuhirom's blog.
Amon2::Liteでmarkdownその他のリアルタイムプレビュー - すぎゃーんメモ

Mojolicious::Liteにしようか迷いましたが、

  • すでに使っている人がいたこと
  • Mojoって聞いた時点で「喪女」が出てきてry
  • 「あもん」ってなんだか言いやすい

ということでAmon2を選びました。

Amon2の詳しい解説は本家を御覧ください(そういえばTwitterでなぜかブロックされてる…)。

普段Catalystしかいじってない自分にとっては軽量WAFであることとSinatra風ということでかなりウキウキしてます♪

基本的にはすぎゃーんさんの記事をパクってTrac記法を追加しただけですが個人的にとても勉強になりました!

(使いたい時は各自のマシンにColinuxやVMに入れる等してくださいね!)

まずインストール方法とソースです。

インストール方法は本家から持って来ました。

% curl -L http://cpanmin.us | perl - Amon2 Amon2::DBI

これで一発!(DBIは今回はいらないか)

次にプロジェクトを作ります。

% amon2-setup.pl --flavor=Lite RealTimeMarkUpViewer
-- Running flavor: Lite --
writing app.psgi
writing Makefile.PL
writing t/Util.pm
writing t/01_root.t
writing xt/03_pod.t

こんな感じになります。

% tree RealTimeMarkUpViewer
RealTimeMarkUpViewer/
|-- Makefile.PL
|-- app.psgi
|-- t
|   |-- 01_root.t
|   `-- Util.pm
`-- xt
    `-- 03_pod.t
2 directories, 5 files

階層もシンプルですね(はじめてCatalystを見たときはすでに大分開発すすんでいたこともあって何がなんだか…)。
そして変更するのはディレクトリ内のapp.psgiのみです。
ひとつのファイルしかいじらなくていい!っていうのがすごい楽ですね。

cd RealTimeMarkUpViewer
vi app.psgi

以下のようにします。
すぎゃーんさんのほぼパクリですがTrac記法かけるように追加しています。

#!/usr/bin/env plackup
use strict;
use warnings;

use Amon2::Lite;
use Encode 'encode_utf8';
use Text::Markdown 'markdown';
use Text::Xatena;
use Text::Trac;
use Pod::Simple::XHTML;

my $converters = {
    markdown => sub {
        my $text = shift;
        return markdown($text);
    },
    xatena => sub {
        my $text = shift;
        return Text::Xatena->new->format($text);
    },
    pod => sub {
        my $text = shift;
        my $parser = Pod::Simple::XHTML->new;
        $parser->html_header('');
        $parser->html_footer('');
        $parser->output_string(\my $html);
        $parser->parse_string_document($text);
        return $html;
    },
    trac => sub {
        my $text = shift;
        my $parser = Text::Trac->new();
        $parser->parse($text);
        return $parser->html;
    },
};

get '/' => sub {
    my ($c) = @_;
    return $c->render('index.tt');
};
post '/preview' => sub {
    my ($c) = @_;
    my $converter = $converters->{$c->req->param('format')};
    my $html = $converter ? $converter->($c->req->param('text')) : '';
    return $c->create_response(200, ['Content-Type' => 'text/plain'], [encode_utf8($html)]);
};

__PACKAGE__->to_app;

__DATA__

@@ index.tt
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>りあるたいむぷれびゅー</title>
    <style>
    </style>
  </head>
  <style>
    body {
      background-color: lightgray;
      margin: 10px;
    }
    textarea {
      width: 100%;
      height: 100px;
    }
    div#preview {
      background-color: white;
      padding: 5px;
    }
  </style>
  <script type="text/javascript" src="https://www.google.com/jsapi"></script>
  <script type="text/javascript">google.load("jquery", "1.6.2");</script>
  <script type="text/javascript">
    $(function () {
      var preview = $('#preview');
      preview.css({
        height: $(window).height() - preview.offset().top - 20,
        overflow: 'auto'
      });
      $('textarea').focus().keyup(function () {
        var text   = $(this).val();
        var format = $('input:radio[name=format]:checked').val();
        $.ajax({
          url: '/preview',
          type: 'POST',
          data: {
            text: text,
            format: format
          },
          success: function (result) {
            preview.html(result);
          }
        });
      });
    });
  </script>
  <body>
    <input type="radio" name="format" id="radio1" value="markdown" checked="checked"><label for="radio1">Markdown</label>
    <input type="radio" name="format" id="radio2" value="xatena"><label for="radio2">はてな記法</label>
    <input type="radio" name="format" id="radio3" value="pod"><label for="radio3">Pod</label>
    <input type="radio" name="format" id="radio4" value="trac"><label for="radio4">Trac</label>
    <textarea></textarea>
    <hr>
    <div id="preview"></div>
  </body>
</html>

これを実行させます。

% plackup app.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/

これであとはhttp://0:5000/にアクセスすると表示されています。
こんなかんじ↓
f:id:kazuph1986:20110906215303j:image:w640

Trac使っているのでこれで確認作業しなくてもよさそう。

最近はAmon2をいじりながら色々してますが、
楽しくてしょうがないですね♪

おすすめです。