2013年02月28日

Perlの女神降臨!「WiiRemoteハック」で鮮魚を喰らう

―― Perlの女神さんはブログでPerlのソースコードを公開してますけど、プログラミングはいつ覚えたんですか?
―― それまではプログラミングは全然経験なし?
―― WiiRemoteって、マウスを使わないでプレゼン資料を操作するデバイスですよね。ダイエットなんかもできる。
―― 鮮魚を喰らう……鮮魚を。
―― ところで、なぜ「鮮魚」の研究を始めたんですか?
(中略)
―― Perl女神さんはWebアプリを開発できますし、ハードウェアとの連携も経験している。後はサーバーでも覚えたら完璧なエンジニアですね。
―― では、すっかりエンジニアのPerl女神さんから、読者のエンジニアに何かメッセージを。

そんなPerl女神さんのインタビュー全編はこちら

Posted by Yappo at 17:46 | Comments (0) | TrackBack

2013年02月21日

シェル関数でHTTP のステータスコードをすばやくしらべる! そしてメンテナンスフリー!

一般的な Web Programmer ならば、HTTP Status code はすべて暗記していると聞きました。
しかし、僕は初心者なので、なかなか覚えきれていないので、HTTPのステータスコードをさがすのに便利なシェル関数を用意しました。httpstatus.sh です。.basrc とかに書いとくだけです。

使い方は以下のとおりです。

4xx なコードを列挙する。

$ httpstatus 4
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Request Entity Too Large
414 Request-URI Too Long
415 Unsupported Media Type
416 Requested Range Not Satisfiable
417 Expectation Failed
422 Unprocessable Entity
423 Locked
424 Failed Dependency
425 (Reserved for WebDAV advanced collections expired proposal)
426 Upgrade Required
428 Precondition Required
429 Too Many Requests
431 Request Header Fields Too Large
451 Unavailable For Legal Reasons

40x なコードを列挙する

$ httpstatus 40
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict

500 ってなんだっけ?

$ httpstatus 500
500 Internal Server Error

403 ってなんだっけ?

$ httpstatus 403
403 Forbidden

Bad なんとかってなんだっけ?

$ httpstatus Bad
400 Bad Request
502 Bad Gateway

とりあえず全部みるか。

$ httpstatus Bad

欠点としては毎回 www.studyinghttp.net につなぎに行くことですが、一度入れれば status code 増えても安心設計です!

(今日の参考文献: http://blog.64p.org/entry/2013/02/21/121830)

Posted by Yappo at 17:26 | Comments (0) | TrackBack

2013年02月18日

Try::Lite 「より安全な例外キャッチを簡単に」

I wrote too safety exception handling module.
https://metacpan.org/release/Try-Lite

$@ の処理を安全に取り扱う例外処理モジュールとしては Try::Tiny があまりにも有名ですが、別の実装を作ってみました。

アプリケーションを作る時は、よく例外クラスを作ってから die bless {}, $foo_class; みたいな形のオブジェクトの例外を投げて、上流の方で eval で受け取ってから $@ の isa を調べて例外に応じた処理をする事が多いと思います。
ここで問題になるのが、受け取った例外の中から不要な物を、さらに上位に向けて rethrow するわけですが、 rethrow するのを忘れてしまうとクリティカルなバグを発生させる要因となります。

また普通の言語で良くあるような try {} catch (e = IOException) {} catch (e = PermissionException) {} のようなに、例外クラス毎の処理を可読性良く書きたかったいという問題もありました。当然 TryCatch.pm のような、そのものの文法を提供してくれるモジュールもあるのですが、あくまで黒魔術的な実装ではなくて、メンテナンスビリティの事を考えて誰が見てもわかる実装で用意したいという問題もありました。

そして、それらの問題を解決する手段として Try::Lite を書いたのです。

使い方は簡単で

use Try::Lite;

try {
    ...;
    IOException->throw('なんかメッセージ');
} (
    'IOException' => sub {
        say $@;
    }
);
の用に、最初に例外が発生するかもしれないコードブロックを書いてから、その後ろの引き数に受け取りたいクラス名と処理したい関数を渡してあげます。

ISA を見ているので、例外したオブジェクトが継承しているクラスを指定していてもキャッチ可能です。

package Exception;
use parent 'Exception::Tiny';
package IOException;
use parent --norequire, 'Exception';
package main;

try {
    ...;
    IOException->throw('なんかメッセージ');
} (
    'Exception' => sub {
        say $@;
    }
);

クラス名の変わりに * がワイルドカードとして指定出来ます。この場合は die 'aaa' 等の普通の文字列な例外も補足して処理可能になります。

try {
    ...;
    die 'foo';
} (
    '*' => sub {
        say $@;
    }
);

Exception::Tiny との組み合わせ

Try::Lite は blessed な $@ を発生させる例外のコードだったらどんな例外クラスを使ってても良いんですが、 Exception::Tiny との組み合わせ例も書いておきます。

# user table を引いて、レコードが無ければ 404 を返して、それ以外の例外は上流に rethrow させる
package Exception;
use parent 'Exception::Tiny';

...

my $user = try {
    Exception->throw if $error;
    get_user( user_id => $user_id );
} ( 'Exception' => sub { $@ } );
if (Exception->caught($user) {
    return $c->res_404;
}

以下のコードでも同じ事出来るし依存するモジュール減るのですが、 Try::Lite 使っとけば不意の retrhow 漏れが防げるので安全側に実装できるかな。と思います。
my $user = eval {
    Exception->throw if $error;
    get_user( user_id => $user_id );
};
if (my $e = $@) {
    if (Exception->caught($e) {
        return $c->res_404;
    }
    die $e;
}

Posted by Yappo at 18:06 | Comments (0) | TrackBack

2013年02月15日

Log::Dispatch::Screen::Color::Emotional も作ってみた

ref: http://blog.64p.org/entry/2013/02/15/152508
ref: http://d.hatena.ne.jp/hirose31/20130215/1360908384

変なプラガブル機構になっててめんどいし、最近 Log::Dispatch 使ってなくて自前で log メソッド書いてる。

Posted by Yappo at 16:28 | Comments (0) | TrackBack

2013年02月13日

Exception::Tiny - ちょー簡単な例外処理

I wrote too easy exception interface module.
https://metacpan.org/release/Exception-Tiny

既存の例外処理モジュールは、結構頑張ってるのが多くてドキュメント凄いいっぱいあったり実装が読みにくかったり痒い所がかけないので、おばあちゃんの孫の手的な実装をリリースしました。

例外処理に最低限必要な実装しか無いので使うのが簡単です。
例外クラスにアクセサを生やしたければ、お好きなアクセサーで生やすもよいし、例外の階層構造作りたければ普通に use parent すればいいし、既存の実装を変えたければ user parent 'Exception::Tiny'; で継承された側のモジュールでメソッドを上書きすればいいです。

Exception::Tiny 本体のお約束はなくて、普通に Perl のルールさえ知ってれば好きな例外処理を書けるのでとっても簡単ですね!

例えば以下のようにテラカンタンに書けます。

use strict;
use warnings;
use lib 'lib';
use 5.012;

package IOException;
use parent 'Exception::Tiny';
use Class::Accessor::Lite (
    ro => [qw/ fh /],
);

package FileException;
use parent -norequire, 'IOException';
use Class::Accessor::Lite (
    ro => [qw/ filepath /],
);

package NetworkException;
use parent -norequire, 'IOException';

package HTTPException;
use parent -norequire, 'NetworkException';
use Class::Accessor::Lite (
    ro => [qw/ uri code /],
);

sub as_string {
    my $self = shift;
    sprintf "HTTPException: message=%s, fh=%s, code=%s, uri=%s\n", $self->message, $self->fh, $self->code, $self->uri;
}

package OtherException;
use parent 'Exception::Tiny';

package RethrowException;
use parent 'Exception::Tiny';

package main;


sub exception (&) {
    my $cb = shift;
    eval { $cb->() };

    given ($@) {
        when (HTTPException->caught($_)) {
            warn "$_\n";
        }
        when (IOException->caught($_)) {
            printf STDERR "fh=%s\n", $_->fh;
            warn "$_\n";
            warn "-----------------------\n";
        }
        when (RethrowException->caught($_)) {
            $_->rethrow;
        }
        when (Exception::Tiny->caught($_)) {
            warn "$_\n";
            warn "-----------------------\n";
        }
        default {
            warn "$@\n";
            warn "-----------------------\n";
        }
    }
}

exception {
    die 'normal die';
};

exception {
    FileException->throw(
        filepath => '/foo/bar',
        fh       => 'FILE HANDLE',
    );
};

exception {
    HTTPException->throw(
        message => 'not found',
        code    => '404',
        uri     => 'http://example.com',
        fh      => 'TCP HANDLE',
    );
};

exception {
    OtherException->throw;
};

eval {
    exception {
        RethrowException->throw('rethrow');
    };
};
if (my $e = $@) {
    warn $e if RethrowException->caught($e);
}

__END__
normal die at ./winecall.pl line 69.

-----------------------
fh=FILE HANDLEFileException at ./winecall.pl line 73.
-----------------------
HTTPException: message=not found, fh=TCP HANDLE, code=404, uri=http://example.com
OtherException at ./winecall.pl line 89.
-----------------------
rethrow at ./winecall.pl line 94. at ./winecall.pl line 98.

happy exception!

Posted by Yappo at 13:03 | Comments (0) | TrackBack