File Coverage

blib/lib/App/Search/BackPAN.pm
Criterion Covered Total %
statement 11 95 11.5
branch 0 20 0.0
condition n/a
subroutine 4 13 30.7
pod 1 2 50.0
total 16 130 12.3


line stmt bran cond sub pod time code
1             package App::Search::BackPAN;
2              
3             $App::Search::BackPAN::VERSION = '0.06';
4             $App::Search::BackPAN::AUTHORITY = 'cpan:MANWAR';
5              
6             =head1 NAME
7              
8             App::Search::BackPAN - Command Line Interface for backpan.perl.org.
9              
10             =head1 VERSION
11              
12             Version 0.06
13              
14             =cut
15              
16 3     3   63324 use 5.006;
  3         21  
17 3     3   15 use strict;
  3         6  
  3         81  
18 3     3   14 use warnings;
  3         5  
  3         106  
19 3     3   2129 use HTTP::Tiny;
  3         148725  
  3         2918  
20              
21             =head1 DESCRIPTION
22              
23             Happy Birthday CPAN !!!
24             Released on 26th Oct to celebrate the occasion.
25              
26             It provides search functionaliy of L. It
27             comes with search tool C.
28              
29             =head1 SYNOPSIS
30              
31             $ search-backpan --pauseid [PAUSE_ID]
32              
33             For example, if you look for author AAKD.
34              
35             $ search-backpan --pauseid AAKD
36             http://backpan.perl.org/authors/id/A/AA/AAKD/MultiProcFactory-0.01.tar.gz
37             http://backpan.perl.org/authors/id/A/AA/AAKD/MultiProcFactory-0.02.tar.gz
38             http://backpan.perl.org/authors/id/A/AA/AAKD/MultiProcFactory-0.03.tar.gz
39             http://backpan.perl.org/authors/id/A/AA/AAKD/MultiProcFactory-0.04.tar.gz
40             http://backpan.perl.org/authors/id/A/AA/AAKD/XML-Simple-Tree-0.02.tar.gz
41             http://backpan.perl.org/authors/id/A/AA/AAKD/XML-Simple-Tree-0.03.tar.gz
42              
43             =cut
44              
45             sub new {
46 0     0 0   my $self = {};
47              
48 0           $self->{http} = HTTP::Tiny->new;
49 0           $self->{base_url} = 'http://backpan.perl.org/authors/id';
50 0           $self->{pause_id} = undef;
51 0           $self->{first_letter} = undef;
52 0           $self->{first_two_letters} = undef;
53 0           $self->{distributions} = [];
54 0           bless $self;
55              
56 0           return $self;
57             }
58              
59             =head1 METHODS
60              
61             =head2 search($pause_id)
62              
63             As name suggests, it returns the search result for the given C<$pause_id>.
64              
65             use strict; use warnings;
66             use App::Search::BackPAN;
67              
68             my $backpan = App::Search::BackPAN->new;
69             my $result = $backpan->search('AAKD');
70              
71             print join "\n", @$result, "\n";
72              
73             =cut
74              
75             sub search {
76 0     0 1   my ($self, $pause_id) = @_;
77              
78 0           $self->_check_pause_id($pause_id);
79 0           $self->_validate_first_letter;
80 0           $self->_validate_first_two_letters;
81              
82 0           my $authors = $self->_fetch_authors;
83 0 0         if (keys %$authors) {
84 0 0         _die($pause_id) unless (exists $authors->{$pause_id});
85 0           $self->_fetch_distributions;
86 0           return $self->_format_distributions;
87             }
88             else {
89 0           _die($pause_id);
90             }
91             }
92              
93             #
94             #
95             # PRIVATE METHODS
96              
97             sub _check_pause_id {
98 0     0     my ($self, $pause_id) = @_;
99              
100 0 0         die "ERROR: Missing PAUSE ID" unless defined $pause_id;
101 0 0         die "ERROR: PAUSE ID should be 3 or more characters long." unless (length($pause_id) >= 3);
102              
103 0           $self->{pause_id} = $pause_id;
104 0           $self->{first_letter} = substr($pause_id, 0, 1);
105 0           $self->{first_two_letters} = substr($pause_id, 0, 2);
106             }
107              
108             sub _validate_first_letter {
109 0     0     my ($self) = @_;
110              
111 0           my $http = $self->{http};
112 0           my $base_url = $self->{base_url};
113 0           my $response = $http->get($base_url);
114 0           my $content = $response->{content};
115 0           foreach my $line (split /\n/,$content) {
116 0 0         if ($line =~ /href=\"([A-Z])\/\"/) {
117 0 0         return 1 if ($self->{first_letter} eq $1);
118             }
119             }
120              
121 0           _die($self->{pause_id});
122             }
123              
124             sub _validate_first_two_letters {
125 0     0     my ($self) = @_;
126              
127 0           my $http = $self->{http};
128 0           my $base_url = $self->{base_url};
129 0           my $first_letter = $self->{first_letter};
130 0           my $url = sprintf("%s/%s", $base_url, $first_letter);
131              
132 0           my $response = $http->get($url);
133 0           my $content = $response->{content};
134 0           foreach my $line (split /\n/,$content) {
135 0 0         if ($line =~ /href=\"([A-Z][A-Z])\/\"/) {
136 0 0         return 1 if ($self->{first_two_letters} eq $1);
137             }
138             }
139              
140 0           _die($self->{pause_id});
141             }
142              
143             sub _fetch_authors {
144 0     0     my ($self) = @_;
145              
146 0           my $http = $self->{http};
147 0           my $base_url = $self->{base_url};
148 0           my $first_letter = $self->{first_letter};
149 0           my $first_two_letters = $self->{first_two_letters};
150              
151 0           my $url = sprintf("%s/%s/%s", $base_url, $first_letter, $first_two_letters);
152 0           my $response = $http->get($url);
153 0           my $content = $response->{content};
154 0           my $authors = {};
155 0           foreach my $line (split /\n/,$content) {
156 0 0         if ($line =~ /\\/) {
157 0           $authors->{$1} = 1;
158             }
159             }
160              
161 0           return $authors;
162             }
163              
164             sub _fetch_distributions {
165 0     0     my ($self) = @_;
166              
167 0           my $http = $self->{http};
168 0           my $base_url = $self->{base_url};
169 0           my $pause_id = $self->{pause_id};
170 0           my $first_letter = $self->{first_letter};
171 0           my $first_two_letters = $self->{first_two_letters};
172              
173 0           my $url = sprintf("%s/%s/%s/%s", $base_url, $first_letter, $first_two_letters, $pause_id);
174 0           my $response = $http->get($url);
175 0           my $content = $response->{content};
176 0           my $dists = [];
177 0           foreach my $line (split /\n/,$content) {
178 0 0         if ($line =~ /\.*<\/a>/) {
179 0           push @$dists, $1;
180             }
181             }
182              
183 0           $self->{distributions} = $dists;
184             }
185              
186             sub _format_distributions {
187 0     0     my ($self) = @_;
188              
189 0           my $base_url = $self->{base_url};
190 0           my $pause_id = $self->{pause_id};
191 0           my $first_letter = $self->{first_letter};
192 0           my $first_two_letters = $self->{first_two_letters};
193              
194 0           my $result = [];
195 0           foreach my $dist (@{$self->{distributions}}) {
  0            
196 0           push @$result, sprintf("%s/%s/%s/%s/%s", $base_url, $first_letter, $first_two_letters, $pause_id, $dist);
197             }
198              
199 0           return $result;
200             }
201              
202             sub _die {
203 0     0     my ($pause_id) = @_;
204              
205 0           die "ERROR: PAUSE ID [$pause_id] not found.\n";
206             }
207              
208             =head1 AUTHOR
209              
210             Mohammad S Anwar, C<< >>
211              
212             =head1 REPOSITORY
213              
214             L
215              
216             =head1 BUGS
217              
218             Please report any bugs or feature requests to C,
219             or through the web interface at L.
220             I will be notified and then you'll automatically be notified of progress on your
221             bug as I make changes.
222              
223             =head1 SUPPORT
224              
225             You can find documentation for this module with the perldoc command.
226              
227             perldoc App::Search::BackPAN
228              
229             You can also look for information at:
230              
231             =over 4
232              
233             =item * RT: CPAN's request tracker (report bugs here)
234              
235             L
236              
237             =item * AnnoCPAN: Annotated CPAN documentation
238              
239             L
240              
241             =item * CPAN Ratings
242              
243             L
244              
245             =item * Search CPAN
246              
247             L
248              
249             =back
250              
251             =head1 LICENSE AND COPYRIGHT
252              
253             Copyright (C) 2018 Mohammad S Anwar.
254              
255             This program is free software; you can redistribute it and / or modify it under
256             the terms of the the Artistic License (2.0). You may obtain a copy of the full
257             license at:
258              
259             L
260              
261             Any use, modification, and distribution of the Standard or Modified Versions is
262             governed by this Artistic License.By using, modifying or distributing the Package,
263             you accept this license. Do not use, modify, or distribute the Package, if you do
264             not accept this license.
265              
266             If your Modified Version has been derived from a Modified Version made by someone
267             other than you,you are nevertheless required to ensure that your Modified Version
268             complies with the requirements of this license.
269              
270             This license does not grant you the right to use any trademark, service mark,
271             tradename, or logo of the Copyright Holder.
272              
273             This license includes the non-exclusive, worldwide, free-of-charge patent license
274             to make, have made, use, offer to sell, sell, import and otherwise transfer the
275             Package with respect to any patent claims licensable by the Copyright Holder that
276             are necessarily infringed by the Package. If you institute patent litigation
277             (including a cross-claim or counterclaim) against any party alleging that the
278             Package constitutes direct or contributory patent infringement,then this Artistic
279             License to you shall terminate on the date that such litigation is filed.
280              
281             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
282             CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
283             WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
284             NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS
285             REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT,
286             INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE
287             OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288              
289             =cut
290              
291             1; # End of App::Search::BackPAN