« Form.Element.Observerの自動停止 | メイン | JSONとContent-Type »

クロージャの使用例 in Text::Hatena

id:naoya氏がclosureのpracticeをいくつか揚げていて非常に勉強になります。

ちょっと思いだしたのは、Text::Hatenaに含まれるText::Hatena::HTMLFilterで、HTML::Parser

$self->{parser} = HTML::Parser->new(
	api_version => 3,
	handlers => {
	    start => [$self->starthandler, 'tagname, attr, text'],
	    end => [$self->endhandler, 'tagname, text'],
	    text => [$self->texthandler, 'text'],
	    comment => [$self->commenthandler, 'text'],
	},
    );


こんな感じで呼び出しています。
各handlerがどうなっているのかと言えば、

sub texthandler {
    my $self = shift;
    return sub {
	my $text = shift;
	$text = &{$self->{context}->texthandler}($text, $self->{context});
	$self->{html} .= $text;
    }
}

のようになっていて、「$self」を保持しつつ無名サブルーチンを返しています。

実はこの方法を最近まで知らなくて、クロージャも理解してなく、HTML::Parserを継承してパーサクラスを書いてますた。ようやくきちんと理解できた気がする。

ところで、この連休はJavaScript(prototype.js有り)をずっと書いていたおかげで、

sub parser{
    $self->{parser} = HTML::Parser->new(
	api_version => 3,
	handlers => {
	    start => [$self->starthandler->bind($self), 'tagname, attr, text'],
	    end => [$self->endhandler->bind($self), 'tagname, text'],
	    text => [$self->texthandler->bind($self), 'text'],
	    comment => [$self->commenthandler->bind($self), 'text'],
	},
    );
}

sub texthandler {
    my $self = shift;
    my $text = shift;
    $text = &{$self->{context}->texthandler}($text, $self->{context});
    $self->{html} .= $text;
}

と書けたらいいかもとか少し思った。