WebService::Simpleでキャッシュを使えない -解決-

とりあえず解決したのでメモ。

#!/usr/bin/perl

use strict;
use warnings;

use WebService::Simple;
use Data::Dumper;

{
    package MyCache;
    
    use Cache::File;
    use Safe;

    use base qw(Cache::File);

    my $safe = Safe->new;
    $safe->permit(qw(:default require));
    my $reval = sub { $safe->reval($_[0]) };

    sub set {
        my $self = shift;
        local $Storable::Deparse = 1;
        local $Storable::Eval = $reval;
        $self->SUPER::freeze(@_);
    }

    sub get {
        my $self = shift;
        local $Storable::Deparse = 1;
        local $Storable::Eval = $reval;
        $self->SUPER::thaw(@_);
    }
}

my $cache = MyCache->new(
    cache_root => "$ENV{HOME}/perl/tmp",
    lock_level => Cache::File::LOCK_LOCAL(),
    default_expires => '30 min',
);

my $google = WebService::Simple->new(
    base_url        => "http://ajax.googleapis.com/ajax/services/search/web",
    cache           => $cache,
    response_parser => 'JSON',
    params          => { v => "1.0", rsz=> "large" }
);

my $response =  $google->get( { q => "cat" , start=> 0 } );
print Dumper $response->parse_response;


まずStorableというモジュールを使うとオブジェクトを保存し、取り出すことができる。Cache::FileでStorableを使うようにするには、thaw()とfreeze()と使う。
404 Blog Not Found:perl - Cache::File と Storable

なにしろ、$cache->get()を$cache->thaw()に、$cache->set()を$cache->freeze()にそれぞれ変えればいいだけなのですから楽すぎます。

WebService::SimpleはCacheオブジェクトのget()とset()を呼び出しているので、Cache::Fileを継承して、get()でthaw()を、set()でfreeze()を呼び出すようにする。


ただし、thaw()とfreeze()に変えただけは以下のようなエラーが出るので、

Can't store CODE items at ../../lib/Storable.pm
(autosplit into ../../lib/auto/Storable/_freeze.al)
line 290, at /usr/lib/perl5/site_perl/5.8/Cache/Entry.pm line 317


下記のコードを参考にして、$Storable::Deparseと$Strable::Evalを設定する。
Storable - Perlデータ構造体の永続化

use Storable qw(freeze thaw);
use Safe;
use strict;
my $safe = new Safe;
# opcodeを"require"することを許すことは"use strict"を使う時には必須です
$safe->permit(qw(:default require));
local $Storable::Deparse = 1;
local $Storable::Eval = sub { $safe->reval($_[0]) };
my $serialized = freeze(sub { print "42\n" });
my $code = thaw($serialized);
$code->(); # prints 42