File Coverage

blib/lib/CPAN/PackageDetails/Header.pm
Criterion Covered Total %
statement 60 65 92.3
branch 11 14 78.5
condition 5 6 83.3
subroutine 15 17 88.2
pod 8 9 88.8
total 99 111 89.1


line stmt bran cond sub pod time code
1             package CPAN::PackageDetails::Header;
2 14     14   1594 use strict;
  14         22  
  14         325  
3 14     14   54 use warnings;
  14         35  
  14         441  
4              
5             our $VERSION = '0.261';
6              
7 14     14   54 use Carp;
  14         20  
  14         9901  
8              
9             =encoding utf8
10              
11             =head1 NAME
12              
13             CPAN::PackageDetails::Header - Handle the header of 02packages.details.txt.gz
14              
15             =head1 SYNOPSIS
16              
17             Used internally by CPAN::PackageDetails
18              
19             =head1 DESCRIPTION
20              
21             The 02packages.details.txt.gz header is a short preamble that give information
22             about the creation of the file, its intended use, and the number of entries in
23             the file. It looks something like:
24              
25             File: 02packages.details.txt
26             URL: http://www.perl.com/CPAN/modules/02packages.details.txt
27             Description: Package names found in directory $CPAN/authors/id/
28             Columns: package name, version, path
29             Intended-For: Automated fetch routines, namespace documentation.
30             Written-By: Id: mldistwatch.pm 1063 2008-09-23 05:23:57Z k
31             Line-Count: 59754
32             Last-Updated: Thu, 23 Oct 2008 02:27:36 GMT
33              
34             Note that there is a Columns field. This module tries to respect the ordering
35             of columns in there. The usual CPAN tools expect only three columns and in the
36             order in this example, but C tries to handle any number
37             of columns in any order.
38              
39             =head2 Methods
40              
41             =over 4
42              
43             =item new( HASH )
44              
45             Create a new Header object. Unless you want a lot of work so you
46             get more control, just let C's C or C
47             handle this for you.
48              
49             In most cases, you'll want to create the Entries object first then
50             pass a reference the the Entries object to C since the header
51             object needs to know how to get the count of the number of entries
52             so it can put it in the "Line-Count" header.
53              
54             CPAN::PackageDetails::Header->new(
55             _entries => $entries_object,
56             )
57              
58             =cut
59              
60             sub new {
61 24     24 1 50 my( $class, %args ) = @_;
62              
63 24         53 my %hash = (
64             _entries => undef,
65             %args
66             );
67              
68 24         80 bless \%hash, $_[0]
69             }
70              
71             =item format_date
72              
73             Write the date in PAUSE format. For example:
74              
75             Thu, 23 Oct 2008 02:27:36 GMT
76              
77             =cut
78              
79             sub format_date {
80 25     25 1 480 my( $second, $minute, $hour, $date, $monnum, $year, $wday ) = gmtime;
81 25         54 $year += 1900;
82              
83 25         45 my $day = ( qw(Sun Mon Tue Wed Thu Fri Sat) )[$wday];
84 25         39 my $month = ( qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) )[$monnum];
85              
86 25         141 sprintf "%s, %02d %s %4d %02d:%02d:%02d GMT",
87             $day, $date, $month, $year, $hour, $minute, $second;
88             }
89              
90             =item default_headers
91              
92             Returns a list of the the headers that should show up in the file. This
93             excludes various fake headers stored in the object.
94              
95             =cut
96              
97             sub default_headers {
98 7         16 map { $_, $_[0]->{$_} }
99 1     1 1 1 grep ! /^_|_class|allow/, keys %{ $_[0] }
  1         25  
100             }
101              
102             sub can {
103 15     15 0 662 my( $self, @methods ) = @_;
104              
105 15   66     53 my $class = ref $self || $self; # class or instance
106              
107 15         37 foreach my $method ( @methods ) {
108             next if
109 15 100 100     22 defined &{"${class}::$method"} ||
  15         84  
110             $self->header_exists( $method );
111 2         37 return 0;
112             }
113              
114 13         33 return 1;
115             }
116              
117             =item set_header
118              
119             Add an entry to the collection. Call this on the C
120             object and it will take care of finding the right handler.
121              
122             =cut
123              
124             sub set_header {
125 283     283 1 358 my( $self, $field, $value ) = @_;
126              
127 283         621 $self->{$field} = $value;
128             }
129              
130             =item header_exists( FIELD )
131              
132             Returns true if the header has a field named FIELD, regardless of
133             its value.
134              
135             =cut
136              
137             sub header_exists {
138 117     117 1 182 my( $self, $field ) = @_;
139              
140 117         397 exists $self->{$field}
141             }
142              
143             =item get_header( FIELD )
144              
145             Returns the value for the named header FIELD. Carps and returns nothing
146             if the named header is not in the object. This method is available from
147             the C or C object:
148              
149             $package_details->get_header( 'url' );
150              
151             $package_details->header->get_header( 'url' );
152              
153             The header names in the Perl code are in a different format than they
154             are in the file. See C for an explanation of the
155             difference.
156              
157             For most headers, you can also use the header name as the method name:
158              
159             $package_details->header->url;
160              
161             =cut
162              
163             sub get_header {
164 71     71 1 125 my( $self, $field ) = @_;
165              
166 71 100       116 if( $self->header_exists( $field ) ) { $self->{$field} }
  69         226  
167 2         208 else { carp "No such header as $field!"; return }
  2         147  
168             }
169              
170             =item columns_as_list
171              
172             Returns the columns name as a list (rather than a comma-joined string). The
173             list is in the order of the columns in the output.
174              
175             =cut
176              
177 5     5 1 35 sub columns_as_list { split /,\s+/, $_[0]->{columns} }
178              
179             =item as_string
180              
181             Return the header formatted as a string.
182              
183             =cut
184              
185 0         0 BEGIN {
186 14     14   60 my %internal_field_name_mapping = (
187             url => 'URL',
188             );
189              
190 14         1327 my %external_field_name_mapping = reverse %internal_field_name_mapping;
191              
192             sub _internal_name_to_external_name {
193 41     41   58 my( $self, $internal ) = @_;
194              
195             return $internal_field_name_mapping{$internal}
196 41 100       74 if exists $internal_field_name_mapping{$internal};
197              
198 37         91 (my $external = $internal) =~ s/_/-/g;
199 37         93 $external =~ s/^(.)/ uc $1 /eg;
  37         103  
200 37         77 $external =~ s/-(.)/ "-" . uc $1 /eg;
  41         97  
201              
202 37         74 return $external;
203             }
204              
205             sub _external_name_to_internal_name {
206 0     0   0 my( $self, $external ) = @_;
207              
208             return $external_field_name_mapping{$external}
209 0 0       0 if exists $external_field_name_mapping{$external};
210              
211 0         0 (my $internal = $external) =~ s/-/_/g;
212              
213 0         0 lc $internal;
214             }
215              
216             sub as_string {
217 4     4 1 12 my( $self, $line_count ) = @_;
218              
219             # XXX: need entry count
220 4         6 my @lines;
221 4         21 foreach my $field ( keys %$self ) {
222 45 100       91 next if substr( $field, 0, 1 ) eq '_';
223 41         65 my $value = $self->get_header( $field );
224              
225 41         79 my $out_field = $self->_internal_name_to_external_name( $field );
226              
227 41         135 push @lines, "$out_field: $value";
228             }
229              
230 4 100       14 push @lines, "Line-Count: " . $self->_entries->as_unique_sorted_list
231             unless $self->header_exists( 'line_count' );
232              
233 4         57 join "\n", sort( @lines ), "\n";
234             }
235             }
236              
237             sub AUTOLOAD {
238 7     7   22 my $self = shift;
239              
240 7         35 ( my $method = $CPAN::PackageDetails::Header::AUTOLOAD ) =~ s/.*:://;
241              
242 7 50       19 carp "No such method as $method!" unless $self->can( $method );
243              
244 7         18 $self->get_header( $method );
245             }
246              
247       0     sub DESTROY { }
248              
249             =back
250              
251             =head1 TO DO
252              
253              
254             =head1 SEE ALSO
255              
256              
257             =head1 SOURCE AVAILABILITY
258              
259             This source is in Github:
260              
261             https://github.com/briandfoy/cpan-packagedetails
262              
263             =head1 AUTHOR
264              
265             brian d foy, C<< >>
266              
267             =head1 COPYRIGHT AND LICENSE
268              
269             Copyright © 2009-2018, brian d foy . All rights reserved.
270              
271             You may redistribute this under the terms of the Artistic License 2.0.
272              
273             =cut
274              
275             1;