File Coverage

blib/lib/WWW/CPAN.pm
Criterion Covered Total %
statement 21 73 28.7
branch 0 14 0.0
condition 0 4 0.0
subroutine 7 13 53.8
pod 3 3 100.0
total 31 107 28.9


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