File Coverage

blib/lib/Autocache.pm
Criterion Covered Total %
statement 122 139 87.7
branch 22 30 73.3
condition 1 2 50.0
subroutine 26 29 89.6
pod 0 13 0.0
total 171 213 80.2


line stmt bran cond sub pod time code
1             package Autocache;
2              
3 5     5   189244 use strict;
  5         14  
  5         200  
4 5     5   25 use warnings;
  5         14  
  5         432  
5              
6             our $VERSION = '0.004';
7             $VERSION = eval $VERSION;
8              
9 5     5   2630 use Autocache::Config;
  5         22  
  5         188  
10 5     5   8973 use Autocache::Request;
  5         17  
  5         1648  
11 5     5   8359 use Autocache::Strategy::Store::Memory;
  5         17  
  5         171  
12 5     5   4413 use Autocache::WorkQueue;
  5         15  
  5         193  
13 5     5   30 use Autocache::Logger qw(get_logger);
  5         8  
  5         205  
14 5     5   27 use Carp;
  5         12  
  5         4421  
15              
16             require Exporter;
17              
18             our @ISA = qw( Exporter );
19             our @EXPORT = qw( autocache );
20              
21             my $SINGLETON;
22              
23             sub autocache
24             {
25 2     2 0 17 my ($name,$args) = @_;
26 2         10 get_logger()->debug( "autocache $name" );
27 2         6 my $package = caller;
28 2         13 __PACKAGE__->singleton->_cache_function( $package, $name, $args );
29             }
30              
31             sub singleton
32             {
33 5     5 0 13 my $class = shift;
34 5 100       40 __PACKAGE__->initialise()
35             unless $SINGLETON;
36 5         37 return $SINGLETON;
37             }
38              
39             sub initialise
40             {
41 5     5 0 58 my $class = shift;
42 5         30 $SINGLETON = $class->new( @_ );
43 5         22 $SINGLETON->configure;
44 2         6 my %args = @_;
45 2 50       18 Autocache::Logger->initialise(logger => $args{logger})
46             if $args{logger};
47             }
48              
49             sub new
50             {
51 5     5 0 28 my ($class,%args) = @_;
52 5         61 my $config = Autocache::Config->new( $args{filename} );
53 5         57 my $self =
54             {
55             config => $config,
56             strategy => {},
57             default_strategy => undef,
58             work_queue => undef,
59             };
60 5         14 bless $self, $class;
61 5         16 return $self;
62             }
63              
64             sub configure
65             {
66 5     5 0 10 my ($self) = @_;
67              
68 5         55 foreach my $node ( $self->{config}->get_node( 'strategy' )->children )
69             {
70 4         20 my $name = $node->name;
71 4         160 my $package = $node->value;
72 4         21 _use_package( $package );
73              
74 4         7 my $strategy;
75              
76             eval
77 4         10 {
78 4         36 $strategy = $package->new( $node );
79             };
80 4 100       1257 if( $@ )
81             {
82 3         1583 confess "cannot create strategy $name using package $package - $@";
83             }
84 1         9 $self->{strategy}{$node->name} = $strategy;
85             }
86              
87 2         11 $self->configure_functions( $self->{config}->get_node( 'fn' ) );
88              
89 2 100       16 if( $self->{config}->node_exists( 'default_strategy' ) )
90             {
91 1         5 $self->{default_strategy} = $self->get_strategy(
92             $self->{config}->get_node( 'default_strategy' )->value );
93             }
94             }
95              
96             sub configure_functions
97             {
98 2     2 0 5 my ($self,$node,$namespace) = @_;
99              
100 2   50     15 $namespace ||= '';
101              
102 2 50       7 if( $node->value )
103             {
104 0         0 get_logger()->debug( "fn: $namespace -> " . $node->value );
105              
106 0         0 $self->{fn}{$namespace}{strategy} = $node->value;
107             }
108              
109 2         9 foreach my $child ( $node->children )
110             {
111 0         0 $self->configure_functions( $child, $namespace . '::' . $child->name );
112             }
113             }
114              
115             sub cache_function
116             {
117 0     0 0 0 my ($self,$name,$args) = @_;
118 0         0 get_logger()->debug( "cache_function '$name'" );
119 0         0 my $package = caller;
120 0         0 $self->_cache_function( $package, $name, $args );
121             }
122              
123             sub _cache_function
124             {
125 2     2   5 my ($self,$package,$name,$args) = @_;
126              
127 2         10 get_logger()->debug( "_cache_function '$name'" );
128              
129             # r : cache routine name
130 2         7 my $r = '::' . $package . '::' . $name;
131              
132             # n : cache routine normaliser name
133 2         5 my $n = '::' . $package . '::_normalise_' . $name;
134              
135             # g : generator routine name
136 2         6 my $g = __PACKAGE__ . '::G' . $r;
137              
138 2         7 get_logger()->debug( "cache : $r / $g" );
139              
140 5     5   112 no strict 'refs';
  5         9  
  5         562  
141              
142             # get generator routine ref
143 2         4 my $gsub = *{$r}{CODE};
  2         10  
144              
145             # see if we have a normaliser
146 2         2 my $gsub_norm = *{$n}{CODE};
  2         11  
147              
148 2 50       15 unless( defined $gsub_norm )
149             {
150 2         7 get_logger()->debug( "no normaliser, using default" );
151 2         8 $gsub_norm = $self->get_default_normaliser();
152             }
153              
154 2         10 my $rsub = $self->_generate_cached_fn( $r, $gsub_norm, $gsub );
155              
156             {
157             # avoid "subroutine redefined" warning
158 5     5   29 no warnings;
  5         9  
  5         4585  
  2         5  
159             # setup cached routine for caller
160 2         4 *{$r} = $rsub;
  2         10  
161             }
162 2         15 1;
163             }
164              
165             sub run_work_queue
166             {
167 0     0 0 0 my($self) = @_;
168 0         0 get_logger()->debug( "run_work_queue" );
169 0         0 $self->get_work_queue()->execute();
170             }
171              
172             sub get_work_queue
173             {
174 0     0 0 0 my ($self) = @_;
175 0         0 get_logger()->debug( "get_work_queue" );
176 0 0       0 unless( $self->{work_queue} )
177             {
178 0         0 $self->{work_queue} = Autocache::WorkQueue->new();
179             }
180 0         0 return $self->{work_queue};
181             }
182              
183             sub get_strategy_for_fn
184             {
185 129     129 0 188 my ($self,$name) = @_;
186 129         290 get_logger()->debug( "get_strategy_for_fn '$name'" );
187              
188 129 50       546 return $self->get_default_strategy()
189             unless exists $self->{fn}{$name}{strategy};
190              
191 0         0 return $self->get_strategy( $self->{fn}{$name}{strategy} );
192             }
193              
194             sub get_strategy
195             {
196 4     4 0 10 my ($self,$name) = @_;
197 4         17 get_logger()->debug( "get_strategy '$name'" );
198 4 100       824 confess "cannot find strategy $name"
199             unless $self->{strategy}{$name};
200 1         4 return $self->{strategy}{$name};
201             }
202              
203             sub get_default_strategy
204             {
205 129     129 0 160 my ($self) = @_;
206 129         280 get_logger()->debug( "get_default_strategy" );
207 129 100       322 unless( $self->{default_strategy} )
208             {
209 1         14 $self->{default_strategy} = Autocache::Strategy::Store::Memory->new;
210             }
211 129         296 return $self->{default_strategy};
212             }
213              
214             sub get_default_normaliser
215             {
216 2     2 0 4 my ($self) = @_;
217 2         8 get_logger()->debug( "get_default_normaliser" );
218 2         6 return \&_default_normaliser;
219             }
220              
221             sub _generate_cached_fn
222             {
223 2     2   6 my ($self,$name,$normaliser,$coderef) = @_;
224 2         7 get_logger()->debug( "_generate_cached_fn $name" );
225              
226             return sub
227             {
228 129     129   789 get_logger()->debug( "CACHE $name" );
229 129 50       355 return unless defined wantarray;
230 129 100       229 my $context = wantarray ? 'L' : 'S';
231              
232 129         292 get_logger()->debug( "calling context: $context" );
233              
234 129         1440 my $request = Autocache::Request->new(
235             name => $name,
236             normaliser => $normaliser,
237             generator => $coderef,
238             args => \@_,
239             context => $context,
240             );
241              
242 129         621 my $strategy = $self->get_strategy_for_fn( $name );
243              
244 129         330 my $rec = $strategy->get( $request );
245              
246 129 100       253 unless( $rec )
247             {
248 67         381 $rec = $strategy->create( $request );
249 67         195 $strategy->set( $request, $rec );
250             }
251              
252 129         334 my $value = $rec->value;
253              
254 129 100       1067 return wantarray ? @$value : $value;
255 2         23 };
256             }
257              
258             sub _default_normaliser
259             {
260 129     129   296 get_logger()->debug( "_default_normaliser" );
261 129         1197 return join ':', @_;
262             }
263              
264             sub _use_package
265             {
266 4     4   10 my ($name) = @_;
267 4         20 get_logger()->debug( "use $name" );
268 4     4   2267 eval "use $name";
  4         9  
  4         82  
  4         794  
269 4 50       28 if( $@ )
270             {
271 0           confess $@;
272             }
273             }
274              
275             1;
276              
277             __END__