練習がてらMoose化してみた。これでいいのかな。

が、今思えばextendsで継承したほうが良かった気がする。

package MyMemcache;

use Moose;
use MooseX::ClassAttribute;
use UNIVERSAL::require;
use feature qw/:5.10/;
use Carp qw/ croak /;
use Digest::MD5 qw/ md5_hex /;
use Storable qw/ nfreeze /;


class_has opt => (
    is      => 'rw',
    isa     => 'HashRef',
    default => sub {
        +{
            servers => [ qw/ 127.0.0.1:11211 / ],
        }
    },
);

class_has cache_expire => (
    is      => 'rw',
    isa     => 'Int',
    default => 0,
);

class_has client_module => (
    is      => 'rw',
    isa     => 'Str',
    required => 1,
    default => 'Cache::Memcached::Fast',
);

has memd => (
    is      => 'rw',
    isa     => 'Object',
    required => 1,
    lazy    => 1,
    default => sub { shift->_init_memd },
    handles => {
        flush_cache => "flush_all",
    },
);


sub _init_memd {
    my $self = shift;
    my $class = ref $self;

    my $client = $class->client_module;
    $client->require or croak $@;

    return $client->new({
        %{ $class->opt },
        %{ $self },
    });
}

sub save_cache {
    my ($self, $namespace, $key, $value, $expire) = @_;

    my $class = ref $self;

    return $self->memd->set(
        $self->_create_cachekey($namespace, $key),
        $value,
        $expire // $class->cache_expire,
    );
}

sub save_cache_multi {
    my ($self, $namespace, @items) = @_;

    my $class = ref $self;

    return $self->memd->set_multi(
        map [
            $self->_create_cachekey($namespace, $_->[0]),
            $_->[1],
            $_->[2] // $class->cache_expire,
        ], @items
    );
}

sub load_cache {
    my ($self, $namespace, $key) = @_;

    return $self->memd->get(
        $self->_create_cachekey($namespace, $key),
    );
}

sub load_cache_multi {
    my ($self, $namespace, @keys) = @_;

    return $self->memd->get_multi(
        map { $self->_create_cachekey($namespace, $_) } @keys
    );
}

sub delete_cache {
    my ($self, $namespace, $key) = @_;

    if (! defined $key) {
        return $self->memd->incr($namespace, 1);
    } else {
        return $self->memd->delete(
            $self->_create_cachekey($namespace, $key)
        );
    }
}


# private //////////////////
sub _create_cachekey {
    my ($self, $namespace, $key) = @_;

    my $namespace_key = $self->memd->get($namespace) // do {
        $self->memd->set($namespace, 0);
        0;
    };

    $key = nfreeze($key) if ref $key;
    return join ":", $namespace, $namespace_key, md5_hex($key);
}