2010-03-09

[plack] response body を変更する Middleware の試作

Web アプリケーションが見事にコードリファレンス一つに抽象化されている PSGI では、あるアプリケーションに前処理・後処理を追加して、動作をちょっと変更する Middleware という仕組みがあって、それで色々と面白いことができそうなので、試しにくだらないものを作ってみました。

今回作ったのは、実用性皆無ですが、後処理を追加することで、出力をすべて大文字にしてくれる Middleware です。

必要なモジュール: Plack, Twiggy

使い方: plackup -s Twiggy app.psgi で動かして、http://localhost:5000/stream などを見てみる。

package Plack::Middleware::UpperCase;
use strict;
use warnings;
use parent qw(Plack::Middleware);

sub call {
    my ($self, $env) = @_;

    my $res = $self->app->($env);

    return $self->response_cb($res, sub {
        my $res = shift;

        return sub {
            my $body_chunk = shift;

            if (defined $body_chunk) {
                return uc $body_chunk;
            } else {
                return;
            }
        };
    });
}

package main;
use strict;
use warnings;
use AnyEvent;
use Plack::Builder;
use Plack::Response;

builder {
#    enable 'Plack::Middleware::UpperCase';
    enable sub { Plack::Middleware::UpperCase->wrap(@_) };

    mount '/static' => sub {
        my $env = shift;

        my $res = Plack::Response->new(200);
        $res->content_type('text/plain');
        $res->body("static response");

        return $res->finalize;
    };

    mount '/handle' => sub {
        my $env = shift;

        my $res = Plack::Response->new(200);
        $res->content_type('text/plain');

        open my $io, '<', \'body handle';
        $res->body($io);

        return $res->finalize;
    };

    mount '/stream' => sub {
        my $env = shift;

        return sub {
            my ($write) = @_;

            my $writer = $write->([
                200,
                [
                    'Content-Type' => 'text/plain',
                ],
            ]);

            my $count = 0;
            my $t; $t = AE::timer 0, 0.5, sub {
                $writer->write("date:@{[ scalar localtime ]}, count:@{[ $count++ ]}\n");

                if ($count > 10) {
                    undef $t;
                    $writer->close;
                }
            };
        };
    };
};

hiratara さんの記事 PSGI 1.03のMiddlewareを書いてみる を参考にしながら作ってみたのですが、Plack::Component::response_cb の定義をよく見ると、body_filter として返すコードリファレンスの内容は、return undef をすると $res->[2] に無駄な undef が入るので、return () の方を使うこのコードの方がよいと思います。

2010-03-01

[javascript] call と apply のサンプル

JavaScript の関数オブジェクトについている不思議なメソッド、call と apply についての記事です。これを使うと使いたいメソッドを実行時に文字列で指定するような感じの動的メソッド呼び出しが実現できます。

call, apply の第一引数は、呼ばれた先でのthisを指定します。

callとapplyの違いは、引数の与え方です。例: fn.call(context, arg1, arg2, ...); fn.apply(context, [arg1, arg2, ...])

var list = [];
list.push("hoge0");
list["push"].call(list, "hoge1");

var m = "push";
list[m].apply(list, ["hoge2"]);

console.log(list); // output: ["hoge0", "hoge1", "hoge2"]