Plack::Request と Hash::MultiValue の話

HEAD の Plack::Request では Hash::MultiValues が導入されてる。Hash::MultiValue は多値をストアできるハッシュ風オブジェクト。

use Plack::Request;
use Test::More;

my $r = Plack::Request->new({
    QUERY_STRING   => 'bar=aaa&bar=bbb',
    REQUEST_METHOD => 'GET',
});
is_deeply $r->parameters->{bar}, [qw/aaa bbb/];

みたいなコードが昔はとおってたけど、HEAD だととおらない。

なんでかというと、Plack::Request->parameters->{...} が str or arrayref をかえすのがよくないからなおしたというはなし(see http://bulknews.typepad.com/blog/2009/12/perl-why-parameters-sucks-and-what-we-can-do.html))で、多値をとりたいときは以下のように Hash::MultiValues のメソッドをよべばいい。

my $r = Plack::Request->new({
    QUERY_STRING   => 'bar=aaa&bar=bbb',
    REQUEST_METHOD => 'GET',
});
is_deeply [$r->parameters->get_all('bar')], [qw/aaa bbb/];

ここで一個注意しておきたいのが $r->parameters() の返り値である Hash::MultiValue は Inside Out テクニックをつかっているので、Dumper すると、以下のように、一個しか値がはいってないようにみえたりするんだけど、実際には複数はいってるので安心した方がいいということ。

$VAR1 = bless( {
                 'bar' => 'bbb'
               }, 'Hash::MultiValue' );

Hash::MultiValue 0.05 以上だと ->mixed というメソッドがつかえるようになってます。従来式の str or arrayref がほしいときは以下のようにするとよいです。

use Plack::Request;
use Test::More;

my $r = Plack::Request->new({
    QUERY_STRING   => 'bar=aaa&bar=bbb',
    REQUEST_METHOD => 'GET',
});
is_deeply $r->parameters->mixed->{bar}, [qw/aaa bbb/];

なお、->multi をつかうと、常に arrayref がかえってきます。