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 6     6   81183 use strict;
  6         9  
  6         146  
4 5     5   18 use warnings;
  5         6  
  5         286  
5              
6             our $VERSION = '0.003_003';
7             $VERSION = eval $VERSION;
8              
9 5     5   1620 use Autocache::Config;
  5         12  
  5         146  
10 5     5   1680 use Autocache::Request;
  5         8  
  5         133  
11 5     5   1652 use Autocache::Strategy::Store::Memory;
  5         8  
  5         115  
12 5     5   1469 use Autocache::WorkQueue;
  5         7  
  5         121  
13 5     5   20 use Autocache::Logger qw(get_logger);
  5         7  
  5         165  
14 5     5   20 use Carp;
  5         5  
  5         3082  
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 3     3 0 19 my ($name,$args) = @_;
26 3         11 get_logger()->debug( "autocache $name" );
27 3         6 my $package = caller;
28 3         11 __PACKAGE__->singleton->_cache_function( $package, $name, $args );
29             }
30              
31             sub singleton
32             {
33 7     7 0 10 my $class = shift;
34 7 100       28 __PACKAGE__->initialise()
35             unless $SINGLETON;
36 7         24 return $SINGLETON;
37             }
38              
39             sub initialise
40             {
41 5     5 0 41 my $class = shift;
42 5         21 $SINGLETON = $class->new( @_ );
43 5         19 $SINGLETON->configure;
44 3         8 my %args = @_;
45             Autocache::Logger->initialise(logger => $args{logger})
46 3 50       13 if $args{logger};
47             }
48              
49             sub new
50             {
51 5     5 0 20 my ($class,%args) = @_;
52 5         46 my $config = Autocache::Config->new( $args{filename} );
53 5         25 my $self =
54             {
55             config => $config,
56             strategy => {},
57             default_strategy => undef,
58             work_queue => undef,
59             };
60 5         12 bless $self, $class;
61 5         12 return $self;
62             }
63              
64             sub configure
65             {
66 5     5 0 8 my ($self) = @_;
67              
68 5         42 foreach my $node ( $self->{config}->get_node( 'strategy' )->children )
69             {
70 5         17 my $name = $node->name;
71 5         12 my $package = $node->value;
72 5         16 _use_package( $package );
73              
74 5         7 my $strategy;
75              
76             eval
77 5         7 {
78 5         32 $strategy = $package->new( $node );
79             };
80 5 100       513 if( $@ )
81             {
82 2         176 confess "cannot create strategy $name using package $package - $@";
83             }
84 3         15 $self->{strategy}{$node->name} = $strategy;
85             }
86              
87 3         14 $self->configure_functions( $self->{config}->get_node( 'fn' ) );
88              
89 3 100       18 if( $self->{config}->node_exists( 'default_strategy' ) )
90             {
91             $self->{default_strategy} = $self->get_strategy(
92 2         7 $self->{config}->get_node( 'default_strategy' )->value );
93             }
94             }
95              
96             sub configure_functions
97             {
98 3     3 0 5 my ($self,$node,$namespace) = @_;
99              
100 3   50     16 $namespace ||= '';
101              
102 3 50       8 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 3         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 3     3   15 my ($self,$package,$name,$args) = @_;
126              
127 3         7 get_logger()->debug( "_cache_function '$name'" );
128              
129             # r : cache routine name
130 3         9 my $r = '::' . $package . '::' . $name;
131              
132             # n : cache routine normaliser name
133 3         6 my $n = '::' . $package . '::_normalise_' . $name;
134              
135             # g : generator routine name
136 3         4 my $g = __PACKAGE__ . '::G' . $r;
137              
138 3         10 get_logger()->debug( "cache : $r / $g" );
139              
140 5     5   23 no strict 'refs';
  5         3  
  5         387  
141              
142             # get generator routine ref
143 3         3 my $gsub = *{$r}{CODE};
  3         10  
144              
145             # see if we have a normaliser
146 3         4 my $gsub_norm = *{$n}{CODE};
  3         11  
147              
148 3 50       8 unless( defined $gsub_norm )
149             {
150 3         7 get_logger()->debug( "no normaliser, using default" );
151 3         8 $gsub_norm = $self->get_default_normaliser();
152             }
153              
154 3         9 my $rsub = $self->_generate_cached_fn( $r, $gsub_norm, $gsub );
155              
156             {
157             # avoid "subroutine redefined" warning
158 5     5   18 no warnings;
  5         4  
  5         2870  
  3         3  
159             # setup cached routine for caller
160 3         5 *{$r} = $rsub;
  3         9  
161             }
162 3         18 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 257     257 0 221 my ($self,$name) = @_;
186 257         317 get_logger()->debug( "get_strategy_for_fn '$name'" );
187              
188             return $self->get_default_strategy()
189 257 50       541 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 6     6 0 10 my ($self,$name) = @_;
197 6         13 get_logger()->debug( "get_strategy '$name'" );
198             confess "cannot find strategy $name"
199 6 100       369 unless $self->{strategy}{$name};
200 4         9 return $self->{strategy}{$name};
201             }
202              
203             sub get_default_strategy
204             {
205 257     257 0 204 my ($self) = @_;
206 257         331 get_logger()->debug( "get_default_strategy" );
207 257 100       350 unless( $self->{default_strategy} )
208             {
209 1         8 $self->{default_strategy} = Autocache::Strategy::Store::Memory->new;
210             }
211 257         249 return $self->{default_strategy};
212             }
213              
214             sub get_default_normaliser
215             {
216 3     3 0 6 my ($self) = @_;
217 3         6 get_logger()->debug( "get_default_normaliser" );
218 3         6 return \&_default_normaliser;
219             }
220              
221             sub _generate_cached_fn
222             {
223 3     3   6 my ($self,$name,$normaliser,$coderef) = @_;
224 3         6 get_logger()->debug( "_generate_cached_fn $name" );
225              
226             return sub
227             {
228 257     257   903 get_logger()->debug( "CACHE $name" );
229 257 50       360 return unless defined wantarray;
230 257 100       271 my $context = wantarray ? 'L' : 'S';
231              
232 257         335 get_logger()->debug( "calling context: $context" );
233              
234 257         1358 my $request = Autocache::Request->new(
235             name => $name,
236             normaliser => $normaliser,
237             generator => $coderef,
238             args => \@_,
239             context => $context,
240             );
241              
242 257         626 my $strategy = $self->get_strategy_for_fn( $name );
243              
244 257         397 my $rec = $strategy->get( $request );
245              
246 257 100       327 unless( $rec )
247             {
248 132         355 $rec = $strategy->create( $request );
249 132         213 $strategy->set( $request, $rec );
250             }
251              
252 257         347 my $value = $rec->value;
253              
254 257 100       991 return wantarray ? @$value : $value;
255 3         23 };
256             }
257              
258             sub _default_normaliser
259             {
260 257     257   296 get_logger()->debug( "_default_normaliser" );
261 257         1194 return join ':', @_;
262             }
263              
264             sub _use_package
265             {
266 5     5   12 my ($name) = @_;
267 5         15 get_logger()->debug( "use $name" );
268 4     4   954 eval "use $name";
  4         6  
  4         67  
  5         337  
269 5 50       20 if( $@ )
270             {
271 0           confess $@;
272             }
273             }
274              
275             1;
276              
277             __END__