File Coverage

blib/lib/WWW/CPAN.pm
Criterion Covered Total %
statement 43 72 59.7
branch 5 14 35.7
condition 0 4 0.0
subroutine 9 13 69.2
pod 3 3 100.0
total 60 106 56.6


line stmt bran cond sub pod time code
1              
2             package WWW::CPAN;
3              
4 3     3   527418 use 5.006;
  3         12  
5 3     3   17 use strict;
  3         6  
  3         63  
6 3     3   23 use warnings;
  3         6  
  3         147  
7              
8             our $VERSION = '0.013';
9              
10 3     3   2245 use Class::Lego::Constructor 0.004 ();
  3         54801  
  3         90  
11 3     3   1592 use parent qw( Class::Accessor Class::Lego::Constructor );
  3         544  
  3         20  
12              
13             my $FIELDS = {
14             host => 'search.cpan.org',
15             ua => sub { # default useragent
16             my %options = ( agent => 'www-cpan/' . $VERSION, );
17              
18             # require LWP::UserAgent;
19             # return LWP::UserAgent->new( %options );
20             require LWP::UserAgent::Determined;
21             return LWP::UserAgent::Determined->new(%options);
22             },
23             j_loader => sub { # json loader sub
24             require JSON::MaybeXS;
25             my $j = JSON::MaybeXS->new;
26             return sub { $j->decode(shift); }
27             },
28             x_loader => sub { # xml loader sub
29             require XML::Simple;
30             my %options = (
31             ForceArray => [qw( module dist match )],
32             KeyAttr => [],
33             );
34             my $x = XML::Simple->new(%options);
35             return sub { $x->XMLin(shift); }
36             },
37             };
38              
39             __PACKAGE__->mk_constructor0($FIELDS);
40             __PACKAGE__->mk_accessors( keys %$FIELDS );
41              
42 3     3   11490 use Class::Lego::Myself;
  3         39191  
  3         22  
43             __PACKAGE__->give_my_self;
44              
45 3     3   944 use Carp qw( carp );
  3         7  
  3         1936  
46              
47             sub _build_distmeta_uri {
48 2     2   3 my $self = shift;
49 2         5 my $params = shift;
50              
51 2 50       10 if ( !ref $params ) {
52 2         6 $params = { dist => $params };
53             }
54 2         12 require URI;
55 2         15 my $uri = URI->new();
56 2         103 $uri->scheme('http');
57 2         338 $uri->authority( $self->host );
58 2         88 my @path = qw( meta );
59 2 50       8 if ( $params->{author} ) {
60 0         0 push @path, $params->{author};
61             }
62              
63 2         5 my $dist = $params->{dist};
64 2 50       9 if ( $params->{version} ) {
65 0         0 $dist .= '-' . $params->{version};
66             }
67 2         5 push @path, $dist;
68              
69 2         4 push @path, 'META.json'; # XXX support YAML as well
70 2         13 $uri->path_segments(@path);
71              
72 2         152 return $uri;
73             }
74              
75             sub fetch_distmeta {
76 2     2 1 326 ( my $self, @_ ) = &find_my_self;
77 2         24 my $uri = $self->_build_distmeta_uri(@_);
78 2         12 my $r = $self->ua->get($uri);
79 2 50       797319 if ( $r->is_success ) {
80              
81 2         50 my $content = $r->decoded_content;
82              
83             # Back to UTF8 (if needed)
84 2 50       513 utf8::encode($content)
85             unless utf8::is_utf8($content);
86              
87 2         20 return $self->j_loader->($content);
88             }
89             else {
90 0           carp $r->status_line; # FIXME needs more convincing error handling
91 0           return;
92             }
93             }
94              
95             # http://search.cpan.org/search?query=Archive&mode=all&format=xml
96             sub _build_query_uri {
97 0     0     my $self = shift;
98 0           my $params = shift;
99              
100 0 0         if ( !ref $params ) {
101 0           $params = { query => $params, mode => 'all', format => 'xml', };
102             }
103 0           require URI;
104 0           my $uri = URI->new();
105 0           $uri->scheme('http');
106 0           $uri->authority( $self->host );
107 0           my @path = qw( search );
108 0           $uri->path_segments(@path);
109              
110 0   0       $params->{mode} ||= 'all';
111 0   0       $params->{format} ||= 'xml';
112 0           $uri->query_form($params);
113              
114 0           return $uri;
115             }
116              
117             # other params: s (start), n (page size, should be <= 100)
118              
119             sub _basic_query {
120 0     0     my $self = shift;
121 0           my $uri = $self->_build_query_uri(@_);
122 0           my $r = $self->ua->get($uri);
123 0 0         if ( $r->is_success ) {
124 0           return $self->x_loader->( $r->content );
125             }
126             else {
127 0           carp $r->status_line; # FIXME needs more convincing error handling
128 0           return;
129             }
130             }
131              
132             sub search {
133 0     0 1   my $self = &find_my_self;
134 0           return $self->_basic_query(@_);
135             }
136              
137             # TODO fetch the entire result by default
138              
139             # &query is an alias to &search (see Method::Alias for the rationale)
140             sub query {
141 0     0 1   goto &{ $_[0]->can('search') };
  0            
142             }
143              
144             "I didn't do it! -- Bart Simpson";