File Coverage

lib/App/Cache.pm
Criterion Covered Total %
statement 105 106 99.0
branch 31 40 77.5
condition 4 6 66.6
subroutine 21 21 100.0
pod 8 8 100.0
total 169 181 93.3


line stmt bran cond sub pod time code
1             package App::Cache;
2 1     1   602 use strict;
  1         1  
  1         34  
3 1     1   5 use warnings;
  1         2  
  1         25  
4 1     1   894 use File::Find::Rule;
  1         9852  
  1         10  
5 1     1   11749 use File::HomeDir;
  1         14803  
  1         83  
6 1     1   11 use File::Path qw( mkpath );
  1         2  
  1         60  
7 1     1   1104 use File::stat;
  1         11509  
  1         10  
8 1     1   1400 use HTTP::Cookies;
  1         16145  
  1         37  
9 1     1   1045 use LWP::UserAgent;
  1         59770  
  1         37  
10 1     1   940 use Path::Class;
  1         55843  
  1         85  
11 1     1   10 use Storable qw(nstore retrieve);
  1         1  
  1         72  
12 1     1   4 use base qw( Class::Accessor::Chained::Fast );
  1         2  
  1         1088  
13             __PACKAGE__->mk_accessors(qw( application directory ttl enabled ));
14             our $VERSION = '0.37';
15              
16             sub new {
17 8     8 1 658581 my $class = shift;
18 8         51 my $self = $class->SUPER::new(@_);
19              
20 8 50       100 unless ( $self->application ) {
21 8         88 my $caller = (caller)[0];
22 8         24 $self->application($caller);
23             }
24              
25 8 100       80 unless ( $self->directory ) {
26 6         62 my $dir = dir( home(), "." . $self->_clean( $self->application ),
27             "cache" );
28 6         665 $self->directory($dir);
29             }
30 8         65 my $dir = $self->directory;
31 8 100       93 unless ( -d "$dir" ) {
32 2 50       256 mkpath("$dir")
33             || die "Error mkdiring " . $self->directory . ": $!";
34             }
35              
36 8 100       595 unless ( defined $self->enabled ) {
37 7         52 $self->enabled(1);
38             }
39              
40 8         132 return $self;
41             }
42              
43             sub clear {
44 2     2 1 11569 my $self = shift;
45 2         27 foreach
46             my $filename ( File::Find::Rule->new->file->in( $self->directory ) )
47             {
48 12 50       4288 unlink($filename) || die "Error unlinking $filename: $!";
49             }
50 2         33 foreach my $dirname ( sort { length($b) <=> length($a) }
  1         1599  
51             File::Find::Rule->new->directory->in( $self->directory ) )
52             {
53 3 100       1021 next if $dirname eq $self->directory;
54 1 50       149 rmdir($dirname) || die "Error unlinking $dirname: $!";
55             }
56             }
57              
58             sub delete {
59 4     4 1 4194 my ( $self, $key ) = @_;
60 4         13 my $filename = $self->_clean_filename($key);
61 4 100       16 return unless -f $filename;
62 3 50       144 unlink($filename) || die "Error unlinking $filename: $!";
63             }
64              
65             sub get {
66 12     12 1 2001697 my ( $self, $key ) = @_;
67 12 100       51 return unless $self->enabled;
68 11   100     210 my $ttl = $self->ttl || 60 * 30; # default ttl of 30 minutes
69 11         105 my $filename = $self->_clean_filename($key);
70 11 100       51 return undef unless -f $filename;
71 7         594 my $now = time;
72 7   50     125 my $stat = stat($filename) || die "Error stating $filename: $!";
73 7         1819 my $ctime = $stat->ctime;
74 7         48 my $age = $now - $ctime;
75 7 100       27 if ( $age < $ttl ) {
76 4   50     13 my $value = retrieve("$filename")
77             || die "Error reading from $filename: $!";
78 4         497 return $value->{value};
79             } else {
80 3         14 $self->delete($key);
81 3         1806 return undef;
82             }
83             }
84              
85             sub get_code {
86 3     3 1 2001767 my ( $self, $key, $code ) = @_;
87 3         11 my $data = $self->get($key);
88 3 100       93 unless ($data) {
89 2         9 $data = $code->();
90 2         23 $self->set( $key, $data );
91             }
92 3         620 return $data;
93             }
94              
95             sub get_url {
96 3     3 1 2001289 my ( $self, $url ) = @_;
97 3         16 my $data = $self->get($url);
98 3 100       63 unless ($data) {
99 2         23 my $ua = LWP::UserAgent->new;
100 2         516 $ua->cookie_jar( HTTP::Cookies->new() );
101 2         222 my $response = $ua->get($url);
102 2 50       4106 if ( $response->is_success ) {
103 2         28 $data = $response->content;
104             } else {
105 0         0 die "Error fetching $url: " . $response->status_line;
106             }
107 2         27 $self->set( $url, $data );
108             }
109 3         781 return $data;
110             }
111              
112             sub scratch {
113 1     1 1 7 my $self = shift;
114 1         4 my $directory = $self->_clean_filename("_scratch");
115 1 50       4 unless ( -d $directory ) {
116 1 50       55 mkdir($directory) || die "Error mkdiring $directory: $!";
117             }
118 1         136 return $directory;
119             }
120              
121             sub set {
122 7     7 1 1461 my ( $self, $key, $value ) = @_;
123 7 100       25 return unless $self->enabled;
124 6         49 my $filename = $self->_clean_filename($key);
125 6 50       34 nstore( { value => $value }, "$filename" )
126             || die "Error writing to $filename: $!";
127             }
128              
129             sub _clean {
130 28     28   1615 my ( $self, $text ) = @_;
131 28         61 $text = lc $text;
132 28         189 $text =~ s/[^a-z0-9]+/_/g;
133 28         100 return $text;
134             }
135              
136             sub _clean_filename {
137 22     22   39 my ( $self, $key ) = @_;
138 22         54 $key = $self->_clean($key);
139 22         73 my $filename = file( $self->directory, $key );
140 22         2512 return $filename;
141             }
142              
143             1;
144              
145             __END__