2012/08/15

Recent entries from same category

  1. PerlでWindowsと親和性の高いreadlineが欲しい → あった「Caroline」
  2. Perl をゆるふわと語ろう
  3. cpanfile とは何か、なぜそれを使いたいのか
  4. plackup の --path 引数
  5. Github Notification API が出たので通知を Growl するの書いた。

MojoliciousとCPANモジュールで作る「Nopaste」チュートリアル - ゆーすけべー日記
http://yusukebe.com/archives/20120627/181253.html
yusukebe さんが Mojolicious だったので僕は Amon2::Lite でやってみた。
おんなじ調子でやってもしょうが無いので、ちょっとキャラを変えてやってみる。

まず amon2-setup で外枠を作りやがれ。
Nopaste くらいならフレーバーは Lite で十分だ。お前の作る物なんか Lite で十分だって事だ。ヒャッハーーー!
$ amon2-setup --flavor=Lite nopaste
-- Running flavor: Lite --
[Flavor::Lite] writing app.psgi
[Flavor::Lite] writing Makefile.PL
[Flavor::Lite] writing t/Util.pm
[Flavor::Lite] writing t/01_root.t
[Flavor::Lite] writing xt/03_pod.t

$ cd nopaste
ディレクトリ構造はこんな感じだ。見たところでお前なんかに分かるのか?フハハハハハ!
|   app.psgi
|   Makefile.PL
|   
+---t
|       01_root.t
|       Util.pm
|       
`---xt
        03_pod.t
        
ちっちぇなー。お前みたいだぜ!ちょっと中身見せてみろよ!!
use strict;
use warnings;
use utf8;
use File::Spec;
use File::Basename;
use lib File::Spec->catdir(dirname(__FILE__), 'extlib''lib''perl5');
use lib File::Spec->catdir(dirname(__FILE__), 'lib');
use Plack::Builder;
use Amon2::Lite;

# put your configuration here
sub config {
    +{
    }
}

get '/' => sub {
    my $c = shift;
    return $c->render('index.tt');
};

# for your security
__PACKAGE__->add_trigger(
    AFTER_DISPATCH => sub {
        my ( $c$res ) = @_;
        $res->header'X-Content-Type-Options' => 'nosniff' );
        $res->header'X-Frame-Options' => 'DENY' );
    },
);

# load plugins
__PACKAGE__->load_plugins(
    'Web::CSRFDefender',
);

builder {
    enable 'Plack::Middleware::Static',
        path => qr{^(?:/static/|/robot\.txt$|/favicon.ico$)},
        root => File::Spec->catdir(dirname(__FILE__));
    enable 'Plack::Middleware::ReverseProxy';
    enable 'Plack::Middleware::Session';

    __PACKAGE__->to_app();
};

__DATA__

@@ index.tt
<!doctype html>
<html>
<head>
    <met charst="utf-8">
    <title>nopaste</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    nopaste
</body>
</html>
意外としっかりしてやがるじゃねぇか!ヒャッハーーーー!
タイトルと本文を入力させて、DBに格納しつつエントリを表示する様な物に仕立て上げてやるぜぇぇぇ!
テメエら行くぞ!ブロロロロロ・・・

項目が決まったら、さっさと入力画面を作りやがれ!

ちゃんと見ろよ! __DATA__ 部に index.tt ってあるだろ!直せ、直すんだよ!
<!doctype html>
<html>
<head>
    <met charst="utf-8">
    <title>nopaste</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
#title { width400px}
#content { width400pxheight400px}
</style>
</head>
<body>
  <form action="/" method="post">
  <label for="title">Title:</label><br />
  <input id="title" name="title" type="text" value="[% title|escape %]" /><br />
  <label for="content">Content:</label><br />
  <textarea id="content" name="content">[% content|escape %]</textarea><br />
  <input type="submit">
  </form>
</body>
</html>
ちょっと待ってろ見てやっからよぉ!
$ plackup ブラウザ Chrome かぁ?お前なんかには高機能すぎるだろ!
http://localhost:5000 を開いて今のうちにデザインでも弄っとくんだな!ヒーーーヒィーーー!
nopaste1
何ボケっとしてんだよ!POST されたらDBに入れるだろ!
config だよ!app.psgi の上見ろよ上!
__PACKAGE__->load_plugins('DBI');

# put your configuration here
sub config {
    +{
        'DBI' => [
            "dbi:SQLite:dbname=nopaste.db",
            '',
            '',
            +{
                sqlite_unicode => 1,
            }
        ],
    }
}
Amon2 ではこの load_plugins というおまじないだけで $c というコンテキストに dbh というハンドラが出来上がります。
オイッ!お前 SQL 書けるんだってな!ちょっと書いてみろよ!
create table nopaste (
  id integer not null primary key,
  title string,
  content string
);
書けるじゃねぇか。最初っから言えよ!
$ sqlit3 nopaste.db < nopaste.sql さてと!お前の脳みそに title と content をブチ込んでやるぜ!ヒャーーーーッハーーー!
post '/' => sub {
    my $c = shift;
    my $title = $c->req->param('title');
    my $content = $c->req->param('content');
    unless ($title && $content) {
        $c->redierct('/');
        return;
    }
    $c->dbh->do(q{INSERT INTO nopaste (title, content) VALUES (?, ?)}, {},
        $title$content);
    my $id = $c->dbh->last_insert_id(undefundefundefundef);
    return $c->redirect("/paste/" . $id);
};
タイトルが空だったら問答無用で / にリダイレクトしてやるぜ!ヒャーーーッハーー!
入力データを nopaste テーブルにインサートし、last_insert_id から得た ID へリダイレクトします。
本当は Data::GUID 等を使って ID 自身が皆に分からない様にすべきですが、ここでは割愛します。
お前にちょっと見せ場作ってやるぜ!nopaste のエントリページでな!
index.tt の下に entry.tt を追加します。
@@ entry.tt
<!doctype html>
<html>
<head>
    <met charst="utf-8">
    <title>nopaste - [% title|html %]</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link media="all" rel="stylesheet" href="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css" type="text/css" />
    <script src="http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js"></script>
</head>
<body onload="prettyPrint()">
  <h3 id="title">[% title|html %]</h3>
  <pre id="content" class="prettyprint"><code>[% content|html %]</code></pre><br />
  <a href="/">back</a>
</body>
</html>
title と content を html フィルタで表示します。シンタックスハイライトは google code pretty を使います。

お前に最後の仕事をくれてやるぜ。ちょっとDBからエントリ持ってきな! get '/paste/{id}' => sub {
    my ($c$args) = @_;
    my $id = $args->{id};
    unless ($id) {
        $c->redierct('/');
        return;
    }
    my ($title$content) = $c->dbh->selectrow_array(q{
        SELECT title, content FROM nopaste WHERE id = ? LIMIT 1
    }, {}, $id);
    return $c->render('entry.tt', {
        title => $title,
        content => $content,
    });
};
やりゃぁ出切るじゃねぇか!ハァ!?簡単だっただぁ?黙ってろ、クソが!

nopaste2

ねっ簡単でしょ?
Posted at by