File Coverage

blib/lib/PPI/Cache.pm
Criterion Covered Total %
statement 70 75 93.3
branch 20 34 58.8
condition 3 9 33.3
subroutine 19 19 100.0
pod 5 5 100.0
total 117 142 82.3


line stmt bran cond sub pod time code
1             package PPI::Cache;
2              
3             =pod
4              
5             =head1 NAME
6              
7             PPI::Cache - The PPI Document Caching Layer
8              
9             =head1 SYNOPSIS
10              
11             # Set the cache
12             use PPI::Cache path => '/var/cache/ppi-cache';
13            
14             # Manually create a cache
15             my $Cache = PPI::Cache->new(
16             path => '/var/cache/perl/class-PPI',
17             readonly => 1,
18             );
19              
20             =head1 DESCRIPTION
21              
22             C provides the default caching functionality for L.
23              
24             It integrates automatically with L itself. Once enabled, any attempt
25             to load a document from the filesystem will be cached via cache.
26              
27             Please note that creating a L from raw source or something
28             other object will B be cached.
29              
30             =head2 Using PPI::Cache
31              
32             The most common way of using C is to provide parameters to
33             the C statement at the beginning of your program.
34              
35             # Load the class but do not set a cache
36             use PPI::Cache;
37            
38             # Use a fairly normal cache location
39             use PPI::Cache path => '/var/cache/ppi-cache';
40              
41             Any of the arguments that can be provided to the C constructor can
42             also be provided to C.
43              
44             =head1 METHODS
45              
46             =cut
47              
48 2     2   2565 use strict;
  2         4  
  2         60  
49 2     2   15 use Carp ();
  2         4  
  2         32  
50 2     2   12 use File::Spec ();
  2         3  
  2         22  
51 2     2   11 use File::Path ();
  2         3  
  2         36  
52 2     2   1572 use Storable 2.17 ();
  2         7666  
  2         65  
53 2     2   15 use Digest::MD5 2.35 ();
  2         39  
  2         47  
54 2     2   21 use Params::Util qw{_INSTANCE _SCALAR};
  2         10  
  2         110  
55 2     2   14 use PPI::Document ();
  2         2  
  2         91  
56              
57             our $VERSION = '1.277';
58              
59 2     2   15 use constant VMS => !! ( $^O eq 'VMS' );
  2         4  
  2         1900  
60              
61             sub import {
62 2 50   2   36 my $class = ref $_[0] ? ref shift : shift;
63 2 100       17 return 1 unless @_;
64              
65             # Create a cache from the params provided
66 1         6 my $cache = $class->new(@_);
67              
68             # Make PPI::Document use it
69 1 50       5 unless ( PPI::Document->set_cache( $cache ) ) {
70 0         0 Carp::croak("Failed to set cache in PPI::Document");
71             }
72              
73 1         26 1;
74             }
75              
76              
77              
78              
79              
80             #####################################################################
81             # Constructor and Accessors
82              
83             =pod
84              
85             =head2 new param => $value, ...
86              
87             The C constructor creates a new standalone cache object.
88              
89             It takes a number of parameters to control the cache.
90              
91             =over
92              
93             =item path
94              
95             The C param sets the base directory for the cache. It must already
96             exist, and must be writable.
97              
98             =item readonly
99              
100             The C param is a true/false flag that allows the use of an
101             existing cache by a less-privileged user (such as the web user).
102              
103             Existing documents will be retrieved from the cache, but new documents
104             will not be written to it.
105              
106             =back
107              
108             Returns a new C object, or dies on error.
109              
110             =cut
111              
112             sub new {
113 2     2 1 2278 my $class = shift;
114 2         9 my %params = @_;
115              
116             # Path should exist and be usable
117             my $path = $params{path}
118 2 50       10 or Carp::croak("Cannot create PPI::Cache, no path provided");
119 2 50       35 unless ( -d $path ) {
120 0         0 Carp::croak("Cannot create PPI::Cache, path does not exist");
121             }
122 2 50 33     56 unless ( -r $path and -x $path ) {
123 0         0 Carp::croak("Cannot create PPI::Cache, no read permissions for path");
124             }
125 2 50 33     32 if ( ! $params{readonly} and ! -w $path ) {
126 0         0 Carp::croak("Cannot create PPI::Cache, no write permissions for path");
127             }
128              
129             # Create the basic object
130             my $self = bless {
131             path => $path,
132             readonly => !! $params{readonly},
133 2         15 }, $class;
134              
135 2         10 $self;
136             }
137              
138             =pod
139              
140             =head2 path
141              
142             The C accessor returns the path on the local filesystem that is the
143             root of the cache.
144              
145             =cut
146              
147 11     11 1 679 sub path { $_[0]->{path} }
148              
149             =pod
150              
151             =head2 readonly
152              
153             The C accessor returns true if documents should not be written
154             to the cache.
155              
156             =cut
157              
158 4     4 1 18 sub readonly { $_[0]->{readonly} }
159              
160              
161              
162              
163              
164             #####################################################################
165             # PPI::Cache Methods
166              
167             =pod
168              
169             =head2 get_document $md5sum | \$source
170              
171             The C method checks to see if a Document is stored in the
172             cache and retrieves it if so.
173              
174             =cut
175              
176             sub get_document {
177 5 50   5 1 757 my $self = ref $_[0]
178             ? shift
179             : Carp::croak('PPI::Cache::get_document called as static method');
180 5 50       13 my $md5hex = $self->_md5hex(shift) or return undef;
181 5         16 $self->_load($md5hex);
182             }
183              
184             =pod
185              
186             =head2 store_document $Document
187              
188             The C method takes a L as argument and
189             explicitly adds it to the cache.
190              
191             Returns true if saved, or C (or dies) on error.
192              
193             FIXME (make this return either one or the other, not both)
194              
195             =cut
196              
197             sub store_document {
198 2     2 1 732 my $self = shift;
199 2 50       23 my $Document = _INSTANCE(shift, 'PPI::Document') or return undef;
200              
201             # Shortcut if we are readonly
202 2 50       7 return 1 if $self->readonly;
203              
204             # Find the filename to save to
205 2 50       10 my $md5hex = $Document->hex_id or return undef;
206              
207             # Store the file
208 2         8 $self->_store( $md5hex, $Document );
209             }
210              
211              
212              
213              
214              
215             #####################################################################
216             # Support Methods
217              
218             # Store an arbitrary PPI::Document object (using Storable) to a particular
219             # path within the cache filesystem.
220             sub _store {
221 3     3   9 my ($self, $md5hex, $object) = @_;
222 3         11 my ($dir, $file) = $self->_paths($md5hex);
223              
224             # Save the file
225 3 50       1130 File::Path::mkpath( $dir, 0, 0755 ) unless -d $dir;
226 3         11 if ( VMS ) {
227             Storable::lock_nstore( $object, $file );
228             } else {
229 3         19 Storable::nstore( $object, $file );
230             }
231             }
232              
233             # Load an arbitrary object (using Storable) from a particular
234             # path within the cache filesystem.
235             sub _load {
236 6     6   1353 my ($self, $md5hex) = @_;
237 6         16 my (undef, $file) = $self->_paths($md5hex);
238              
239             # Load the file
240 6 100       126 return '' unless -f $file;
241 5         26 my $object = VMS
242             ? Storable::retrieve( $file )
243             : Storable::lock_retrieve( $file );
244              
245             # Security check
246 5 50       159 unless ( _INSTANCE($object, 'PPI::Document') ) {
247 0         0 Carp::croak("Security Violation: Object in '$file' is not a PPI::Document");
248             }
249              
250 5         26 $object;
251             }
252              
253             # Convert a md5 to a dir and file name
254             sub _paths {
255 9     9   15 my $self = shift;
256 9         20 my $md5hex = lc shift;
257 9         23 my $dir = File::Spec->catdir( $self->path, substr($md5hex, 0, 1), substr($md5hex, 0, 2) );
258 9         85 my $file = File::Spec->catfile( $dir, $md5hex . '.ppi' );
259 9         31 return ($dir, $file);
260             }
261              
262             # Check a md5hex param
263             sub _md5hex {
264 9     9   1234 my $either = shift;
265             my $it = _SCALAR($_[0])
266 9 100       38 ? PPI::Util::md5hex(${$_[0]})
  6         28  
267             : $_[0];
268 9 50 33     112 return (defined $it and ! ref $it and $it =~ /^[[:xdigit:]]{32}\z/s)
269             ? lc $it
270             : undef;
271             }
272              
273             1;
274              
275             =pod
276              
277             =head1 TO DO
278              
279             - Finish the basic functionality
280              
281             - Add support for use PPI::Cache auto-setting $PPI::Document::CACHE
282              
283             =head1 SUPPORT
284              
285             See the L in the main module.
286              
287             =head1 AUTHOR
288              
289             Adam Kennedy Eadamk@cpan.orgE
290              
291             =head1 COPYRIGHT
292              
293             Copyright 2005 - 2011 Adam Kennedy.
294              
295             This program is free software; you can redistribute
296             it and/or modify it under the same terms as Perl itself.
297              
298             The full text of the license can be found in the
299             LICENSE file included with this module.
300              
301             =cut