File Coverage

blib/lib/Parse/CPAN/MirroredBy.pm
Criterion Covered Total %
statement 57 88 64.7
branch 15 30 50.0
condition 1 2 50.0
subroutine 12 16 75.0
pod 6 6 100.0
total 91 142 64.0


line stmt bran cond sub pod time code
1             package Parse::CPAN::MirroredBy;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Parse::CPAN::MirroredBy - Parse MIRRORED.BY
8              
9             =head1 DESCRIPTION
10              
11             Like the other members of the Parse::CPAN family B
12             parses and processes the CPAN meta data file F.
13              
14             =head1 METHODS
15              
16             =cut
17              
18 2     2   25721 use 5.006;
  2         8  
  2         78  
19 2     2   11 use strict;
  2         4  
  2         52  
20 2     2   10 use warnings;
  2         11  
  2         63  
21 2     2   11 use Carp 'croak';
  2         4  
  2         126  
22 2     2   1967 use IO::File ();
  2         21925  
  2         56  
23 2     2   1873 use Params::Util qw{ _CODELIKE _HANDLE };
  2         8634  
  2         186  
24              
25 2     2   14 use vars qw{$VERSION};
  2         4  
  2         90  
26             BEGIN {
27 2     2   3491 $VERSION = '0.02';
28             }
29              
30              
31              
32              
33              
34             #####################################################################
35             # Constructor and Accessors
36              
37             =pod
38              
39             =head2 new
40              
41             Creates a new, simple, parser object.
42              
43             =cut
44              
45             sub new {
46 1     1 1 403 my $class = shift;
47 1         6 my $self = bless { filters => [] }, $class;
48 1         2 return $self;
49             }
50              
51             =pod
52              
53             =head2 add_map
54              
55             # Instead of the full hash just read the hostname
56             $parser->add_map( sub { $_[0]->{hostname} } );
57              
58             The C method adds a map stage to the filter pipeline.
59              
60             A single element is passed into the provided function from the previous
61             pipeline phase, and one or more values can be returned which will be
62             passed on to the next pipeline phase.
63              
64             Returns true if added, or throws an exception if a non-CODE reference
65             is provided.
66              
67             =cut
68              
69             sub add_map {
70 0     0 1 0 my $self = shift;
71 0         0 my $code = _CODELIKE(shift);
72 0 0       0 unless ( $code ) {
73 0         0 croak("add_map: Not a CODE reference");
74             }
75 0         0 push @{$self->{filters}}, [ 'map', $code ];
  0         0  
76 0         0 return 1;
77             }
78              
79             =pod
80              
81             =head2 add_grep
82              
83             # We only want the daily mirrors
84             $parser->add_grep( sub { $_[0]->{frequency} eq 'daily' } );
85              
86             The C method adds a grep phase to the filter pipeline.
87              
88             A single value is passed into the provided function, and the function
89             should return true if the value is to be kept, or false if not.
90              
91             Returns true if added, or throws an exception if a non-CODE reference
92             is provided.
93              
94             =cut
95              
96             sub add_grep {
97 0     0 1 0 my $self = shift;
98 0         0 my $code = _CODELIKE(shift);
99 0 0       0 unless ( $code ) {
100 0         0 croak("add_grep: Not a CODE reference");
101             }
102 0         0 push @{$self->{filters}}, [ 'grep', $code ];
  0         0  
103 0         0 return 1;
104             }
105              
106             =pod
107              
108             =head2 add_bless
109              
110             # Bless into whatever objects
111             $parser->add_bless( 'Foo::Whatever' );
112              
113             For situations in which you wish to convert the pipeline values into
114             objects directly, and don't want to do it via a map phase that passes
115             values into a contructor, the C method allows you to provide
116             a class name that the elements of the pipe will be passed to.
117              
118             =cut
119              
120             sub add_bless {
121 0     0 1 0 my $self = shift;
122 0         0 my $class = _DRIVER(shift, 'UNIVERSAL');
123 0 0       0 unless ( $class ) {
124 0         0 croak("add_bless: Not a valid class");
125             }
126 0     0   0 push @{$self->{filters}}, [ 'map', sub { bless $_, $class } ];
  0         0  
  0         0  
127 0         0 return 1;
128             }
129              
130              
131              
132              
133              
134             #####################################################################
135             # Parsing Methods
136              
137             =pod
138              
139             =head2 parse_file
140              
141             my @mirrors = $parser->parse_file( 'MIRRORED.BY' );
142              
143             Once the parser is ready to process the file, the C method
144             can be provided a file name to read. It will read the file, passing the
145             contents through the filter pipeline, and returning the resulting values
146             as a list of results.
147              
148             =cut
149              
150             sub parse_file {
151 1     1 1 294 my $self = shift;
152 1 50       9 my $handle = IO::File->new( $_[0], 'r' ) or croak("open: $!");
153 1         132 return $self->parse( $handle );
154             }
155              
156             =pod
157              
158             =head2 parse
159              
160             my @mirrors = $parser->parse( $file_handle );
161              
162             Once the parser is ready to process the file, the C method
163             can be provided a file handle to read. It will read from the file handle,
164             passing the contents through the filter pipeline, and returning the
165             resulting values as a list of results.
166              
167             =cut
168              
169             sub parse {
170 1     1 1 2 my $self = shift;
171 1 50       35 my $handle = _HANDLE(shift) or croak("Missing or invalid file handle");
172 1         24 my $line = 0;
173 1         2 my $mirror = undef;
174 1         3 my @output = ();
175              
176 1         2 while ( 1 ) {
177             # Next line
178 3677         6552 my $string = <$handle>;
179 3677 100       6293 last if ! defined $string;
180 3676         3689 $line = $line + 1;
181              
182             # Remove the useless lines
183 3676         3654 chomp( $string );
184 3676 100       9302 next if $string =~ /^\s*$/;
185 3188 100       12192 next if $string =~ /^\s*#/;
186              
187             # Hostname or property?
188 2430 100       5536 if ( $string =~ /^\s/ ) {
189             # Property
190 2188 50       7906 unless ( $string =~ /^\s+(\w+)\s+=\s+\"(.*)\"$/ ) {
191 0         0 croak("Invalid property on line $line");
192             }
193 2188   50     3532 $mirror ||= {};
194 2188         6524 $mirror->{"$1"} = "$2";
195              
196             } else {
197             # Hostname
198 242 50       798 unless ( $string =~ /^([\w\.-]+)\:\s*$/ ) {
199 0         0 croak("Invalid host name on line $line");
200             }
201 242         412 my $current = $mirror;
202 242         840 $mirror = { hostname => "$1" };
203 242 100       463 if ( $current ) {
204 241         640 push @output, $self->_process( $current );
205             }
206             }
207             }
208 1 50       9 if ( $mirror ) {
209 1         5 push @output, $self->_process( $mirror );
210             }
211 1         107 return @output;
212             }
213              
214             sub _process {
215 242     242   245 my $self = shift;
216 242         352 my @mirror = shift;
217 242         756 foreach my $op ( @{$self->{filters}} ) {
  242         546  
218 0         0 my $name = $op->[0];
219 0         0 my $code = $op->[1];
220 0 0       0 if ( $name eq 'grep' ) {
    0          
221 0         0 @mirror = grep { $code->($_) } @mirror;
  0         0  
222             } elsif ( $name eq 'map' ) {
223 0         0 @mirror = map { $code->($_) } @mirror;
  0         0  
224             }
225             }
226 242         745 return @mirror;
227             }
228              
229             1;
230              
231             =pod
232              
233             =head1 SUPPORT
234              
235             Bugs should be reported via the CPAN bug tracker at
236              
237             L
238              
239             =head1 AUTHOR
240              
241             Adam Kennedy Eadamk@cpan.orgE
242              
243             =head1 SEE ALSO
244              
245             L, L,
246             L, L
247              
248             =head1 COPYRIGHT
249              
250             Copyright 2008 Adam Kennedy.
251              
252             This program is free software; you can redistribute
253             it and/or modify it under the same terms as Perl itself.
254              
255             The full text of the license can be found in the
256             LICENSE file included with this module.
257              
258             =cut