File Coverage

blib/lib/CPANPLUS/Internals/Source/MetaCPAN/Tie.pm
Criterion Covered Total %
statement 95 132 71.9
branch 17 44 38.6
condition 3 9 33.3
subroutine 15 21 71.4
pod n/a
total 130 206 63.1


line stmt bran cond sub pod time code
1             package CPANPLUS::Internals::Source::MetaCPAN::Tie;
2             {
3             $CPANPLUS::Internals::Source::MetaCPAN::Tie::VERSION = '0.08';
4             }
5              
6             #ABSTRACT: A tie for the MetaCPAN source engine
7              
8 1     1   7 use strict;
  1         3  
  1         53  
9 1     1   7 use warnings;
  1         7  
  1         40  
10              
11 1     1   6 use CPANPLUS::Error;
  1         5  
  1         74  
12 1     1   8 use CPANPLUS::Module;
  1         2  
  1         29  
13 1     1   5 use CPANPLUS::Module::Fake;
  1         2  
  1         25  
14 1     1   11 use CPANPLUS::Module::Author::Fake;
  1         3  
  1         24  
15 1     1   5 use CPANPLUS::Internals::Constants;
  1         3  
  1         647  
16              
17              
18 1     1   7 use Params::Check qw[check];
  1         2  
  1         51  
19 1     1   6 use Module::Load::Conditional qw[can_load];
  1         1  
  1         52  
20 1     1   6 use Locale::Maketext::Simple Class => 'CPANPLUS', Style => 'gettext';
  1         8  
  1         9  
21              
22 1     1   605 use CPANPLUS::Internals::Source::MetaCPAN::HTTP;
  1         2  
  1         46  
23 1     1   5 use JSON::PP ();
  1         3  
  1         34  
24              
25             require Tie::Hash;
26 1     1   5 use vars qw[@ISA];
  1         2  
  1         10131  
27             push @ISA, 'Tie::StdHash';
28              
29             sub TIEHASH {
30 2     2   4 my $class = shift;
31 2         11 my %hash = @_;
32              
33 2         17 my $tmpl = {
34             idx => { required => 1 },
35             table => { required => 1 },
36             key => { required => 1 },
37             cb => { required => 1 },
38             offset => { default => 0 },
39             };
40              
41 2 50       8 my $args = check( $tmpl, \%hash ) or return;
42 2         259 my $obj = bless { %$args, store => {} } , $class;
43              
44 2         15 return $obj;
45             }
46              
47             sub FETCH {
48 2     2   129 my $self = shift;
49 2 50       11 my $key = shift or return;
50 2         14 my $idx = $self->{idx};
51 2         6 my $cb = $self->{cb};
52 2         5 my $table = $self->{table};
53              
54             ### did we look this one up before?
55 2 50       9 if( my $obj = $self->{store}->{$key} ) {
56 0         0 return $obj;
57             }
58              
59 2 100       10 $key = uc( $key ) if $table eq 'author';
60              
61 2         9 my $url = $self->{idx} . $table . '/' . $key;
62              
63 2         33 my $http = CPANPLUS::Internals::Source::MetaCPAN::HTTP->new();
64              
65 2         6 my $data = {};
66 2         3 my $href;
67              
68             {
69 2         4 my $str;
  2         3  
70 2         10 $http->reset;
71 2 50       13 my $status = $http->request( $url ) or return;
72 2 50       10 return unless $status eq '200';
73 2 50       13 return unless $str = $http->body;
74 2         7 eval { $href = JSON::PP::decode_json( $str ); };
  2         18  
75 2 50 33     287111 return unless $href and keys %$href;
76             }
77              
78             ### expand author if needed
79             ### XXX no longer generic :(
80 2 100       11 if( $table eq 'module' ) {
81 1 50 33     10 return if $href->{maturity} and $href->{maturity} eq 'developer';
82 1 50       65 return unless $href->{indexed};
83 1         14 $href->{author} = delete $href->{author};
84 1         4 $href->{module} = $key;
85 1         7 $href->{version} = delete $href->{version};
86             {
87 1         2 $http->reset;
  1         8  
88 1         8 my $durl = $self->{idx} . 'release' . '/' . $href->{distribution};
89 1         2 my $str;
90 1         7 my $status = $http->request( $durl );
91 1 50       163 return unless $status eq '200';
92 1 50       8 return unless $str = $http->body;
93 1         8 my $dref;
94 1         3 eval { $dref = JSON::PP::decode_json( $str ); };
  1         8  
95 1 50 33     62097 return unless $dref and keys %$dref;
96 1         74 ( $href->{dist_file} = $dref->{download_url} ) =~ s!^.+?authors/id/!!;
97             }
98 1         14 my ($author, $package) = $href->{dist_file} =~
99             m| (?:[A-Z\d-]/)?
100             (?:[A-Z\d-]{2}/)?
101             ([A-Z\d-]+) (?:/[\S]+)?/
102             ([^/]+)$
103             |xsg;
104             ### remove file name from the path
105 1         9 $href->{dist_file} =~ s|/[^/]+$||;
106 1         6 $href->{path} = join '/', 'authors/id', delete $href->{dist_file};
107 1         3 $href->{package} = $package;
108 1         6 $href->{comment} = $href->{description} = $href->{dslip} = $href->{mtime} = '';
109 1 50       12 $href->{author} = $cb->author_tree( $href->{author} ) or return;
110             $data->{$_} = delete $href->{$_}
111 1         48 for qw(author comment description dslip mtime package module version path);
112             }
113             else {
114 1         5 $data->{author} = delete $href->{name};
115 1         6 $data->{cpanid} = delete $href->{pauseid};
116             }
117              
118 2         10 my $class = {
119             module => 'CPANPLUS::Module',
120             author => 'CPANPLUS::Module::Author',
121             }->{ $table };
122              
123 2         23 my $obj = $self->{store}->{$key} = $class->new( %$data, _id => $cb->_id );
124              
125 2         623 return $obj;
126             }
127              
128             sub STORE {
129 0     0     my $self = shift;
130 0           my $key = shift;
131 0           my $val = shift;
132              
133 0           $self->{store}->{$key} = $val;
134             }
135              
136             sub FIRSTKEY {
137 0     0     my $self = shift;
138 0           my $idx = $self->{'idx'};
139 0           my $table = $self->{table};
140              
141 0 0         my $lkup = $table eq 'module' ? 'mod' : 'auth';
142 0           my $url = $idx . "yaml/${lkup}keys";
143              
144 0           my $str;
145              
146 0           my $http = CPANPLUS::Internals::Source::MetaCPAN::HTTP->new();
147              
148 0 0         my $status = $http->request( $url ) or return;
149 0 0         return unless $status eq '200';
150 0 0         return unless $str = $http->body;
151              
152 0           my $res;
153 0           eval { $res = JSON::PP::decode_json( $str ); };
  0            
154 0 0         return unless $res;
155              
156 0 0         my $ref = $table eq 'module' ? 'mod_name' : 'cpan_id';
157 0           @{ $self->{keys} } =
  0            
158 0           map { $_->{$ref} } @$res;
159              
160 0           $self->{offset} = 0;
161              
162 0           return $self->{keys}->[0];
163             }
164              
165             sub NEXTKEY {
166 0     0     my $self = shift;
167 0           my $idx = $self->{'idx'};
168 0           my $table = $self->{table};
169              
170 0           my $key = $self->{keys}->[ $self->{offset} ];
171              
172 0           $self->{offset} +=1;
173              
174 0 0         if ( wantarray ) {
175             ### use each() semantics
176 0           my $val = $self->FETCH( $key );
177 0           return ( $key, $val );
178             }
179 0           return $key;
180             }
181              
182 0     0     sub EXISTS { !!$_[0]->FETCH( $_[1] ) }
183              
184             ### intentionally left blank
185 0     0     sub DELETE { }
186 0     0     sub CLEAR { }
187              
188             qq[Tie your mother down];
189              
190             __END__