File Coverage

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


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