File Coverage

blib/lib/Parse/CPAN/Cached.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Parse::CPAN::Cached;
2              
3 1     1   2233 use Moose;
  0            
  0            
4             use Carp qw<carp>;
5             use CPAN::Mini;
6             use Path::Class;
7             use App::Cache;
8             use Parse::CPAN::Authors;
9             use Parse::CPAN::Packages;
10             use Parse::CPAN::Whois;
11              
12             our $VERSION = '0.02';
13              
14             has 'cpan_mini_config' => (
15             is => 'ro',
16             isa => 'HashRef',
17             default => sub { return { CPAN::Mini->read_config } },
18             );
19             has 'cache' => (
20             is => 'ro',
21             isa => 'Object',
22             default => sub { return App::Cache->new() },
23             documentation => 'optional App::Cache compatible object',
24             );
25             has 'cache_dir' => (
26             is => 'ro',
27             isa => 'Str',
28             lazy_build => 1, # we're using other constructor params
29             init_arg => undef, # private. can't be set via constructor
30             );
31             has 'parsers' => (
32             is => 'rw',
33             isa => 'HashRef',
34             default => sub { return {
35             packages => {
36             file => '02packages.details.txt.gz',
37             subdir => 'modules',
38             parser => 'Parse::CPAN::Packages',
39             },
40             authors => {
41             file => '01mailrc.txt.gz',
42             subdir => 'authors',
43             parser => 'Parse::CPAN::Authors',
44             },
45             whois => {
46             file => '00whois.xml',
47             subdir => 'authors',
48             parser => 'Parse::CPAN::Whois',
49             },
50             } },
51             );
52             has 'info' => (
53             is => 'rw',
54             isa => 'CodeRef',
55             default => sub { sub { } },
56             documentation => q{coderef called with single string param of debug info},
57             );
58              
59             sub _build_cache_dir {
60             my ($self) = @_;
61             my $dir = $self->cpan_mini_config->{local};
62             die 'Have you loaded minicpan? No local dir in config' if !defined $dir;
63             my @a = glob $dir;
64             die "local dir in cpan_mini_config '$dir' not valid" if !@a;
65             die "local dir in cpan_mini_config '$dir' matches multiple files" if @a > 1;
66             return $a[0];
67             }
68              
69             sub parse_cpan {
70             my ($self, $type, $upgrade) = @_;
71              
72             die 'No type' if !defined $type;
73             die "Unknown cpan type '$type'\n"
74             if !$self->parsers->{$type};
75              
76             # Silently upgrade authors to whois iff available
77             if ($type eq 'authors') {
78             my $whois = $self->parse_cpan(whois => 1);
79             return $whois if $whois;
80             }
81              
82             my $filename = file(
83             $self->cache_dir,
84             $self->parsers->{$type}{subdir},
85             $self->parsers->{$type}{file}
86             )->stringify;
87              
88             return
89             if $type eq 'whois'
90             && !-f $filename
91             && $upgrade;
92              
93             die "$filename not found"
94             if !-f $filename;
95              
96             my $real_type = $type eq 'whois' && $upgrade ? 'authors' : $type;
97             return $self->cache->get_code(
98             $filename,
99             sub {
100             $self->info->("Caching '$filename' for $real_type");
101             $self->parsers->{$type}{parser}->new($filename);
102             }
103             );
104             }
105              
106             1;
107              
108             __END__
109              
110             =head1 NAME
111              
112             Parse::CPAN::Cached - Parse CPAN meta files & cache the results
113              
114             =head1 VERSION
115              
116             Version 0.02
117              
118             =cut
119              
120             =head1 SYNOPSIS
121              
122             Ensure you already have a L<CPAN::Mini> mirror setup, then:
123              
124             use Parse::CPAN::Cached;
125             my $parsers = Parse::CPAN::Cached->new();
126              
127             # $authors is a Parse::CPAN::Authors (or Parse::CPAN::Whois) object
128             my $authors = $parsers->parse_cpan('authors');
129              
130             # $distributions is a Parse::CPAN::Packages object
131             my $distributions = $parsers->parse_cpan('packages');
132              
133             =head1 DESCRIPTION
134              
135             Parsing the CPAN meta data files can take a few seconds if you do it normally:
136              
137             my $p = Parse::CPAN::Packages->new($filename);
138              
139             this wraps the parsing/loading with App::Cache which in turn stores the initial
140             parse in a storable file.
141              
142             Provided the cache hasn't expired, subsequent calls are loaded from this
143             storable file rather than being re-parsed from the original cpan metadata file.
144             If the cache has expired, we re-parse the source.
145              
146             This is probably redundant unless you are repeatadly opening these files (in
147             different processes perhaps).
148              
149             Note: 02packages.details.txt.gz (circa 2009-03) is ~730KB on disk but 13MB as a
150             (App::Cached generated) Storable file. We're trading disk & memory for speed.
151              
152             =head1 CONSTRUCTOR METHODS
153              
154             All are optional.
155              
156             =head2 cpan_mini_config
157              
158             Defaults to the result of calling CPAN::Mini->read_config. We only use the
159             'local' value returned, so you could say:
160              
161             my $parsers = Parse::CPAN::Cached->new(
162             cpan_mini_config => { local => '/path/to/mini_cpan/' }
163             );
164              
165             =head2 cache
166              
167             Defaults to App::Cache->new(). If you want to change any of the defaults in
168             App::Cache, construct your own App::Cache first and pass it in.
169              
170             =head2 info
171              
172             A coderef that is called to emit some information about what is going on. By
173             default, we're silent under normal operation but if you want a little more
174             detail about what is happening pass in a coderef that accepts a single string
175             parameter.
176              
177             my $parsers = Parse::CPAN::Cached->new(
178             info => sub { warn @_, "\n" }
179             );
180              
181             Currently the only time this is used is when we're about to parse one of the
182             cpan meta data files form scratch, rather than loading in the data via the
183             cache.
184              
185             =head1 METHODS
186              
187             There is only one.
188              
189             =head2 parse_cpan
190              
191             Give it the key, get back the appropriate Parse::CPAN::Foo object.
192              
193             my $parsers = Parse::CPAN::Cached->new();
194             my $result = $parsers->parse_cpan($key);
195              
196             Where $key is one of:
197              
198             =head3 packages
199              
200             Returns a Parse::CPAN::Packages object.
201              
202             =head3 authors
203              
204             Returns either a Parse::CPAN::Authors object or a (api compatible)
205             Parse::CPAN::Whois object if the 00whois.xml file exists.
206              
207             =head3 whois
208              
209             Returns a Parse::CPAN::Whois object.
210              
211             =head1 AUTHOR
212              
213             Sysmon, C<< <sysmonblog at googlemail.com> >>
214              
215             =head1 BUGS
216              
217             Please report any bugs or feature requests to C<bug-parse-cpan-cached at
218             rt.cpan.org>, or through the web interface at
219             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Parse-CPAN-Cached>. I will be
220             notified, and then you'll automatically be notified of progress on your bug as
221             I make changes.
222              
223             =head1 SUPPORT
224              
225             You can find documentation for this module with the perldoc command.
226              
227             perldoc Parse::CPAN::Cached
228              
229             =over 4
230              
231             =item * RT: CPAN's request tracker
232              
233             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Parse-CPAN-Cached>
234              
235             =item * AnnoCPAN: Annotated CPAN documentation
236              
237             L<http://annocpan.org/dist/Parse-CPAN-Cached>
238              
239             =item * CPAN Ratings
240              
241             L<http://cpanratings.perl.org/d/Parse-CPAN-Cached>
242              
243             =item * Search CPAN
244              
245             L<http://search.cpan.org/dist/Parse-CPAN-Cached>
246              
247             =back
248              
249             =head1 COPYRIGHT & LICENSE
250              
251             Copyright 2009 Sysmon, all rights reserved.
252              
253             This program is free software; you can redistribute it and/or modify it
254             under the same terms as Perl itself.
255              
256             =cut