#!/usr/bin/perl
package Catalyst::Plugin::Cache;
-use base qw/Class::Data::Inheritable/;
+use base qw/Class::Data::Inheritable Class::Accessor::Fast/;
use strict;
use warnings;
use Carp ();
use NEXT;
+use Catalyst::Plugin::Cache::Curried;
+
__PACKAGE__->mk_classdata( "_cache_backends" );
+__PACKAGE__->mk_accessors( "_default_curried_cache" );
sub setup {
my $app = shift;
$ret;
}
+# don't die even if we don't have cache backends
sub setup_cache_backends { shift->NEXT::setup_cache_backends(@_) }
sub cache {
- my $c = shift;
+ my ( $c, @meta ) = @_;
- if ( @_ ) {
- my $name = shift;
- $c->get_cache_backend($name);
+ if ( @meta == 1 ) {
+ my $name = $meta[0];
+ return ( $c->get_preset_curried($name) || $c->get_cache_backend($name) );
+ } elsif ( !@meta ) {
+ # be nice and always return the same one for the simplest case
+ return ( $c->_default_curried_cache || $c->_default_curried_cache( $c->curry_cache( @meta ) ) );
} else {
- $c->default_cache_backend;
+ return $c->curry_cache( @meta );
}
}
+sub curry_cache {
+ my ( $c, @meta ) = @_;
+ return Catalyst::Plugin::Cache::Curried->new( $c, @meta );
+}
+
+sub get_preset_curried {
+ my ( $c, $name ) = @_;
+
+ if ( ref( my $preset = $c->config->{cache}{profiles}{$name} ) ) {
+ return $preset if Scalar::Util::blessed($preset);
+
+ my @meta = ( ( ref $preset eq "HASH" ) ? %$preset : @$preset );
+ return $c->curry_cache( @meta );
+ }
+
+ return;
+}
+
sub get_cache_backend {
my ( $c, $name ) = @_;
$c->_cache_backends->{$name};
--- /dev/null
+#!/usr/bin/perl
+
+package Catalyst::Plugin::Cache::Curried;
+
+use strict;
+use warnings;
+
+use base qw/Class::Accessor::Fast/;
+
+use Scalar::Util ();
+
+__PACKAGE__->mk_accessors(qw/c meta/);
+
+sub new {
+ my ( $class, $c, @meta ) = @_;
+
+ my $self = $class->SUPER::new({
+ c => $c,
+ meta => \@meta,
+ });
+
+ Scalar::Util::weaken( $self->{c} );
+
+ return $self;
+}
+
+sub backend {
+ my ( $self, $key ) = @_;
+ $self->c->choose_cache_backend( @{ $self->meta }, key => $key )
+}
+
+sub set {
+ my ( $self, $key, $value ) = @_;
+ $self->c->cache_set( $key, $value, @{ $self->meta } );
+}
+
+sub get {
+ my ( $self, $key ) = @_;
+ $self->c->cache_get( $key, @{ $self->meta } );
+}
+
+sub delete {
+ my ( $self, $key ) = @_;
+ $self->c->cache_delete( $key, @{ $self->meta } );
+}
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Cache::Curried - Curried versions of C<cache_set>,
+C<cache_get> and C<cache_delete> that look more like a backend.
+
+=head1 SYNOPSIS
+
+ sub begin : Private {
+
+ }
+
+=head1 DESCRIPTION
+
+=cut
+
+
package MockApp;
use base qw/Catalyst::Plugin::Cache/;
+ my %config;
+ sub config { \%config };
+
package MemoryCache;
use Storable qw/freeze thaw/;
can_ok( $c, "default_cache_backend" );
-is( $c->default_cache_backend, $c->cache, "cache with no args retrurns default" );
can_ok( $c, "choose_cache_backend_wrapper" );
can_ok( $c, "choose_cache_backend" );
is( $c->cache_get("foo"), undef, "set to custom backend (get from non custom)" );
is( $c->cache_get("foo", backend => "elk"), "gorch", "set to custom backend (get from custom)" );
+my $cache_elk = $c->cache( backend => "elk" );
+my $cache_norm = $c->cache();
+
+is( $cache_norm->get("foo"), undef, "default curried cache has no foo");
+is( $cache_elk->get("foo"), "gorch", "curried custom backend has foo" );
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Scalar::Util qw/refaddr/;
+
+use ok "Catalyst::Plugin::Cache";
+
+{
+ package MockApp;
+ use base qw/Catalyst::Plugin::Cache/;
+
+ my %config = (
+ cache => {
+ profiles => {
+ foo => {
+ bah => "foo",
+ },
+ bar => MemoryCache->new,
+ },
+ },
+ );
+ sub config { \%config };
+
+ package MemoryCache;
+ use Storable qw/freeze thaw/;
+
+ sub new { bless {}, shift }
+ sub get { ${thaw($_[0]{$_[1]}) || return} };
+ sub set { $_[0]{$_[1]} = freeze(\$_[2]) };
+ sub delete { delete $_[0]{$_[1]} };
+}
+
+MockApp->setup;
+my $c = bless {}, "MockApp";
+
+MockApp->register_cache_backend( default => MemoryCache->new );
+
+can_ok( $c, "curry_cache" );
+can_ok( $c, "get_preset_curried" );
+
+isa_ok( $c->cache, "Catalyst::Plugin::Cache::Curried" );
+
+is( refaddr($c->cache), refaddr($c->cache), "default cache is memoized, so it is ==");
+
+isa_ok( $c->cache("foo"), "Catalyst::Plugin::Cache::Curried", "cache('foo')" );
+
+is_deeply( $c->cache("foo")->meta, [ bah => "foo" ], "meta is in place" );
+
+is( refaddr( $c->cache("bar") ), refaddr( $c->cache("bar") ), "since bar is hard coded as an object it's always the same" );
+
MockApp->register_cache_backend( foo_store => MemoryCache->new );
MockApp->register_cache_backend( bar_store => MemoryCache->new );
-is( $c->choose_cache_backend_wrapper( key => "baz" ), $c->cache, "chose default" );
-is( $c->choose_cache_backend_wrapper( key => "foo" ), $c->cache("foo_store"), "chose foo" );
-is( $c->choose_cache_backend_wrapper( key => "bar" ), $c->cache("bar_store"), "chose bar" );
+is( $c->choose_cache_backend_wrapper( key => "baz" ), $c->default_cache_backend, "chose default" );
+is( $c->choose_cache_backend_wrapper( key => "foo" ), $c->get_cache_backend("foo_store"), "chose foo" );
+is( $c->choose_cache_backend_wrapper( key => "bar" ), $c->get_cache_backend("bar_store"), "chose bar" );
$c->cache_set( foo_laa => "laa" );
$c->cache_set( bar_laa => "laa" );
$c->cache_set( baz_laa => "laa" );
-is( $c->cache->get("baz_laa"), "laa", "non match stored in default" );
-is( $c->cache->get("foo_laa"), undef, "no foo key" );
-is( $c->cache->get("bar_laa"), undef, "no bar key" );
+is( $c->default_cache_backend->get("baz_laa"), "laa", "non match stored in default" );
+is( $c->default_cache_backend->get("foo_laa"), undef, "no foo key" );
+is( $c->default_cache_backend->get("bar_laa"), undef, "no bar key" );
-is( $c->cache("foo_store")->get("baz_laa"), undef, "no non match in foo store" );
-is( $c->cache("foo_store")->get("foo_laa"), "laa", "has foo key" );
-is( $c->cache("foo_store")->get("bar_laa"), undef, "no bar key" );
+is( $c->get_cache_backend("foo_store")->get("baz_laa"), undef, "no non match in foo store" );
+is( $c->get_cache_backend("foo_store")->get("foo_laa"), "laa", "has foo key" );
+is( $c->get_cache_backend("foo_store")->get("bar_laa"), undef, "no bar key" );
-is( $c->cache("bar_store")->get("baz_laa"), undef, "no non match in bar store" );
-is( $c->cache("bar_store")->get("foo_laa"), undef, "no foo key" );
-is( $c->cache("bar_store")->get("bar_laa"), "laa", "has bar key" );
+is( $c->get_cache_backend("bar_store")->get("baz_laa"), undef, "no non match in bar store" );
+is( $c->get_cache_backend("bar_store")->get("foo_laa"), undef, "no foo key" );
+is( $c->get_cache_backend("bar_store")->get("bar_laa"), "laa", "has bar key" );