File Coverage

blib/lib/Cache/Weak.pm
Criterion Covered Total %
statement 65 76 85.5
branch 11 26 42.3
condition 2 2 100.0
subroutine 20 20 100.0
pod 10 11 90.9
total 108 135 80.0


line stmt bran cond sub pod time code
1             #
2             # $Id: Weak.pm 22 2008-04-22 13:28:19Z esobchenko $
3             package Cache::Weak;
4              
5 2     2   79554 use strict;
  2         87  
  2         117  
6 2     2   13 use warnings;
  2         4  
  2         72  
7              
8 2     2   2610 use version; our $VERSION = qv('1.0.3');
  2         15942  
  2         15  
9              
10 2     2   279 use Carp qw/carp croak/;
  2         6  
  2         307  
11 2     2   14 use Scalar::Util qw/weaken/;
  2         4  
  2         270  
12              
13             use constant {
14 2         2785 DEFAULT_NAMESPACE => '_',
15             DEFAULT_AUTO_PURGE_INTERVAL => 1000,
16             DEFAULT_AUTO_PURGE => 1,
17 2     2   14 };
  2         5  
18              
19             # data is stored in the form: $cache_data{$namespace}{$key} = $object
20             my %cache_data = ();
21             my %cache_meta = ();
22              
23             # private method: used in constructor to get it's arguments
24             sub _get_args {
25 2     2   5 my $proto = shift;
26              
27 2         5 my $args;
28 2 50       13 if ( scalar(@_) > 1 ) {
    50          
29 0 0       0 if ( @_ % 2 ) {
30 0         0 croak "odd number of parameters";
31             }
32 0         0 $args = { @_ };
33             } elsif ( ref $_[0] ) {
34 0 0       0 unless ( eval { local $SIG{'__DIE__'}; %{ $_[0] } || 1 } ) {
  0 0       0  
  0         0  
  0         0  
35 0         0 croak "not a hashref in args";
36             }
37 0         0 $args = $_[0];
38             } else {
39 2         8 $args = { namespace => shift };
40             }
41              
42 2         7 return $args;
43             }
44              
45             sub new {
46 2     2 0 32 my $class = shift;
47 2         14 my $self = $class->_get_args(@_);
48 2         13 return bless $self, $class;
49             }
50              
51             sub namespace {
52 53     53 1 995 my $self = shift;
53 53 100       162 if (@_) {
54 1         2 $self->{namespace} = shift;
55             }
56 53   100     437 return $self->{namespace} || DEFAULT_NAMESPACE;
57             }
58              
59             sub auto_purge_interval {
60 8     8 1 15 my $self = shift;
61 8 50       24 if (@_) {
62 0         0 $self->{auto_purge_interval} = shift;
63             }
64 8 50       33 return $cache_meta{ $self->namespace }{auto_purge_interval}
65             = defined $self->{auto_purge_interval} ?
66             $self->{auto_purge_interval} : DEFAULT_AUTO_PURGE_INTERVAL;
67             }
68              
69             sub auto_purge {
70 8     8 1 14 my $self = shift;
71 8 50       26 if (@_) {
72 0         0 $self->{auto_purge} = shift;
73             }
74 8 50       46 return $cache_meta{ $self->namespace }{auto_purge}
75             = defined $self->{auto_purge} ?
76             $self->{auto_purge} : DEFAULT_AUTO_PURGE;
77             }
78              
79             # private method: increment access counter for the given namespace and return it's value
80             sub _inc_count {
81 8     8   16 my $self = shift;
82 8         20 return $cache_meta{ $self->namespace }{count} += 1;
83             }
84              
85             # private method: return actual keys for current namespace
86             sub _keys {
87 5     5   14 my $self = shift;
88 5         63 return keys %{ $cache_data{ $self->namespace } };
  5         18  
89             }
90              
91             sub count {
92 4     4 1 15 my $self = shift;
93 4         13 return int scalar $self->_keys;
94             }
95              
96             sub get {
97 3     3 1 14 my ( $self, $key ) = @_;
98 3         15 return $cache_data{ $self->namespace }{$key};
99             }
100              
101             sub set {
102 8     8 1 59 my ( $self, $key, $object ) = @_;
103              
104 8 50       31 croak "attempting to set non-reference value" unless ref $object;
105              
106             # is it time to purge cache from dead objects?
107 8 50       27 if ( $self->auto_purge ) {
108 8 50       36 $self->purge unless ( $self->_inc_count % $self->auto_purge_interval );
109             }
110              
111 8         48 weaken ( $cache_data{ $self->namespace }{$key} = $object );
112 8         28 return 1;
113             }
114              
115             sub remove {
116 1     1 1 5 my ( $self, $key ) = @_;
117 1         6 delete $cache_data{ $self->namespace }{$key};
118 1         9 return 1;
119             }
120              
121             # XXX "exists" actually means "defined" in our case
122             sub exists {
123 6     6 1 18 my ( $self, $key ) = @_;
124 6         35 return defined $cache_data{ $self->namespace }{$key};
125             }
126              
127             sub purge {
128 1     1 1 998 my $self = shift;
129 1         6 my $cache = $cache_data{ $self->namespace };
130 1         7 delete @{ $cache }{ grep !$self->exists($_), $self->_keys };
  1         4  
131 1         8 return 1;
132             }
133              
134             sub clear {
135 1     1 1 2 my $self = shift;
136 1         2 delete $cache_data{ $self->namespace };
137 1         3 delete $cache_meta{ $self->namespace };
138 1         3 return 1;
139             }
140              
141             1;
142              
143             __END__