File Coverage

blib/lib/CPAN/Meta/Prereqs.pm
Criterion Covered Total %
statement 111 115 96.5
branch 32 48 66.6
condition 16 26 61.5
subroutine 19 19 100.0
pod 10 10 100.0
total 188 218 86.2


line stmt bran cond sub pod time code
1 15     15   39014 use 5.006;
  15         32  
2 15     15   50 use strict;
  15         77  
  15         237  
3 15     15   43 use warnings;
  15         20  
  15         638  
4             package CPAN::Meta::Prereqs;
5              
6             our $VERSION = '2.150009'; # TRIAL
7              
8             #pod =head1 DESCRIPTION
9             #pod
10             #pod A CPAN::Meta::Prereqs object represents the prerequisites for a CPAN
11             #pod distribution or one of its optional features. Each set of prereqs is
12             #pod organized by phase and type, as described in L.
13             #pod
14             #pod =cut
15              
16 15     15   53 use Carp qw(confess);
  15         17  
  15         636  
17 15     15   52 use Scalar::Util qw(blessed);
  15         17  
  15         1057  
18 15     15   7172 use CPAN::Meta::Requirements 2.121;
  15         62903  
  15         14513  
19              
20             #pod =method new
21             #pod
22             #pod my $prereq = CPAN::Meta::Prereqs->new( \%prereq_spec );
23             #pod
24             #pod This method returns a new set of Prereqs. The input should look like the
25             #pod contents of the C field described in L, meaning
26             #pod something more or less like this:
27             #pod
28             #pod my $prereq = CPAN::Meta::Prereqs->new({
29             #pod runtime => {
30             #pod requires => {
31             #pod 'Some::Module' => '1.234',
32             #pod ...,
33             #pod },
34             #pod ...,
35             #pod },
36             #pod ...,
37             #pod });
38             #pod
39             #pod You can also construct an empty set of prereqs with:
40             #pod
41             #pod my $prereqs = CPAN::Meta::Prereqs->new;
42             #pod
43             #pod This empty set of prereqs is useful for accumulating new prereqs before finally
44             #pod dumping the whole set into a structure or string.
45             #pod
46             #pod =cut
47              
48             # note we also accept anything matching /\Ax_/i
49 358     358   534 sub __legal_phases { qw(configure build test runtime develop) }
50 335     335   386 sub __legal_types { qw(requires recommends suggests conflicts) }
51              
52             # expect a prereq spec from META.json -- rjbs, 2010-04-11
53             sub new {
54 28     28 1 1245 my ($class, $prereq_spec) = @_;
55 28   100     62 $prereq_spec ||= {};
56              
57 28         55 my %is_legal_phase = map {; $_ => 1 } $class->__legal_phases;
  140         167  
58 28         67 my %is_legal_type = map {; $_ => 1 } $class->__legal_types;
  112         119  
59              
60 28         32 my %guts;
61 28         68 PHASE: for my $phase (keys %$prereq_spec) {
62 67 50 66     13246 next PHASE unless $phase =~ /\Ax_/i or $is_legal_phase{$phase};
63              
64 67         118 my $phase_spec = $prereq_spec->{ $phase };
65 67 50       122 next PHASE unless keys %$phase_spec;
66              
67 67         89 TYPE: for my $type (keys %$phase_spec) {
68 104 50 66     7630 next TYPE unless $type =~ /\Ax_/i or $is_legal_type{$type};
69              
70 104         95 my $spec = $phase_spec->{ $type };
71              
72 104 50       310 next TYPE unless keys %$spec;
73              
74 104         212 $guts{prereqs}{$phase}{$type} = CPAN::Meta::Requirements->from_string_hash(
75             $spec
76             );
77             }
78             }
79              
80 28         2139 return bless \%guts => $class;
81             }
82              
83             #pod =method requirements_for
84             #pod
85             #pod my $requirements = $prereqs->requirements_for( $phase, $type );
86             #pod
87             #pod This method returns a L object for the given
88             #pod phase/type combination. If no prerequisites are registered for that
89             #pod combination, a new CPAN::Meta::Requirements object will be returned, and it may
90             #pod be added to as needed.
91             #pod
92             #pod If C<$phase> or C<$type> are undefined or otherwise invalid, an exception will
93             #pod be raised.
94             #pod
95             #pod =cut
96              
97             sub requirements_for {
98 217     217 1 14733 my ($self, $phase, $type) = @_;
99              
100 217 50       320 confess "requirements_for called without phase" unless defined $phase;
101 217 50       253 confess "requirements_for called without type" unless defined $type;
102              
103 217 50 66     542 unless ($phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases) {
  1005         1205  
104 0         0 confess "requested requirements for unknown phase: $phase";
105             }
106              
107 217 50 66     484 unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) {
  796         911  
108 0         0 confess "requested requirements for unknown type: $type";
109             }
110              
111 217   66     470 my $req = ($self->{prereqs}{$phase}{$type} ||= CPAN::Meta::Requirements->new);
112              
113 217 100       506 $req->finalize if $self->is_finalized;
114              
115 217         281 return $req;
116             }
117              
118             #pod =method phases
119             #pod
120             #pod my @phases = $prereqs->phases;
121             #pod
122             #pod This method returns the list of all phases currently populated in the prereqs
123             #pod object, suitable for iterating.
124             #pod
125             #pod =cut
126              
127             sub phases {
128 33     33 1 31 my ($self) = @_;
129              
130 33         47 my %is_legal_phase = map {; $_ => 1 } $self->__legal_phases;
  165         182  
131 33 100       43 grep { /\Ax_/i or $is_legal_phase{$_} } keys %{ $self->{prereqs} };
  87         278  
  33         92  
132             }
133              
134             #pod =method types_in
135             #pod
136             #pod my @runtime_types = $prereqs->types_in('runtime');
137             #pod
138             #pod This method returns the list of all types currently populated in the prereqs
139             #pod object for the provided phase, suitable for iterating.
140             #pod
141             #pod =cut
142              
143             sub types_in {
144 99     99 1 87 my ($self, $phase) = @_;
145              
146 99 50 66     263 return unless $phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases;
  450         566  
147              
148 99         138 my %is_legal_type = map {; $_ => 1 } $self->__legal_types;
  396         410  
149 99 100       91 grep { /\Ax_/i or $is_legal_type{$_} } keys %{ $self->{prereqs}{$phase} };
  139         402  
  99         173  
150             }
151              
152             #pod =method with_merged_prereqs
153             #pod
154             #pod my $new_prereqs = $prereqs->with_merged_prereqs( $other_prereqs );
155             #pod
156             #pod my $new_prereqs = $prereqs->with_merged_prereqs( \@other_prereqs );
157             #pod
158             #pod This method returns a new CPAN::Meta::Prereqs objects in which all the
159             #pod other prerequisites given are merged into the current set. This is primarily
160             #pod provided for combining a distribution's core prereqs with the prereqs of one of
161             #pod its optional features.
162             #pod
163             #pod The new prereqs object has no ties to the originals, and altering it further
164             #pod will not alter them.
165             #pod
166             #pod =cut
167              
168             sub with_merged_prereqs {
169 8     8 1 13 my ($self, $other) = @_;
170              
171 8 100       47 my @other = blessed($other) ? $other : @$other;
172              
173 8         15 my @prereq_objs = ($self, @other);
174              
175 8         9 my %new_arg;
176              
177 8         15 for my $phase (__uniq(map { $_->phases } @prereq_objs)) {
  16         29  
178 26         430 for my $type (__uniq(map { $_->types_in($phase) } @prereq_objs)) {
  52         66  
179              
180 45         1048 my $req = CPAN::Meta::Requirements->new;
181              
182 45         319 for my $prereq (@prereq_objs) {
183 90         4652 my $this_req = $prereq->requirements_for($phase, $type);
184 90 100       131 next unless $this_req->required_modules;
185              
186 57         250 $req->add_requirements($this_req);
187             }
188              
189 45 50       8291 next unless $req->required_modules;
190              
191 45         198 $new_arg{ $phase }{ $type } = $req->as_string_hash;
192             }
193             }
194              
195 8         114 return (ref $self)->new(\%new_arg);
196             }
197              
198             #pod =method merged_requirements
199             #pod
200             #pod my $new_reqs = $prereqs->merged_requirements( \@phases, \@types );
201             #pod my $new_reqs = $prereqs->merged_requirements( \@phases );
202             #pod my $new_reqs = $prereqs->merged_requirements();
203             #pod
204             #pod This method joins together all requirements across a number of phases
205             #pod and types into a new L object. If arguments
206             #pod are omitted, it defaults to "runtime", "build" and "test" for phases
207             #pod and "requires" and "recommends" for types.
208             #pod
209             #pod =cut
210              
211             sub merged_requirements {
212 2     2 1 445 my ($self, $phases, $types) = @_;
213 2 100       8 $phases = [qw/runtime build test/] unless defined $phases;
214 2 100       5 $types = [qw/requires recommends/] unless defined $types;
215              
216 2 50       5 confess "merged_requirements phases argument must be an arrayref"
217             unless ref $phases eq 'ARRAY';
218 2 50       4 confess "merged_requirements types argument must be an arrayref"
219             unless ref $types eq 'ARRAY';
220              
221 2         7 my $req = CPAN::Meta::Requirements->new;
222              
223 2         17 for my $phase ( @$phases ) {
224 6 50 33     195 unless ($phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases) {
  30         37  
225 0         0 confess "requested requirements for unknown phase: $phase";
226             }
227 6         7 for my $type ( @$types ) {
228 9 50 33     143 unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) {
  36         44  
229 0         0 confess "requested requirements for unknown type: $type";
230             }
231 9         14 $req->add_requirements( $self->requirements_for($phase, $type) );
232             }
233             }
234              
235 2 50       12 $req->finalize if $self->is_finalized;
236              
237 2         5 return $req;
238             }
239              
240              
241             #pod =method as_string_hash
242             #pod
243             #pod This method returns a hashref containing structures suitable for dumping into a
244             #pod distmeta data structure. It is made up of hashes and strings, only; there will
245             #pod be no Prereqs, CPAN::Meta::Requirements, or C objects inside it.
246             #pod
247             #pod =cut
248              
249             sub as_string_hash {
250 17     17 1 1981 my ($self) = @_;
251              
252 17         22 my %hash;
253              
254 17         35 for my $phase ($self->phases) {
255 47         544 for my $type ($self->types_in($phase)) {
256 74         893 my $req = $self->requirements_for($phase, $type);
257 74 100       120 next unless $req->required_modules;
258              
259 73         297 $hash{ $phase }{ $type } = $req->as_string_hash;
260             }
261             }
262              
263 17         348 return \%hash;
264             }
265              
266             #pod =method is_finalized
267             #pod
268             #pod This method returns true if the set of prereqs has been marked "finalized," and
269             #pod cannot be altered.
270             #pod
271             #pod =cut
272              
273 221     221 1 670 sub is_finalized { $_[0]{finalized} }
274              
275             #pod =method finalize
276             #pod
277             #pod Calling C on a Prereqs object will close it for further modification.
278             #pod Attempting to make any changes that would actually alter the prereqs will
279             #pod result in an exception being thrown.
280             #pod
281             #pod =cut
282              
283             sub finalize {
284 1     1 1 630 my ($self) = @_;
285              
286 1         5 $self->{finalized} = 1;
287              
288 1         1 for my $phase (keys %{ $self->{prereqs} }) {
  1         4  
289 2         6 $_->finalize for values %{ $self->{prereqs}{$phase} };
  2         8  
290             }
291             }
292              
293             #pod =method clone
294             #pod
295             #pod my $cloned_prereqs = $prereqs->clone;
296             #pod
297             #pod This method returns a Prereqs object that is identical to the original object,
298             #pod but can be altered without affecting the original object. Finalization does
299             #pod not survive cloning, meaning that you may clone a finalized set of prereqs and
300             #pod then modify the clone.
301             #pod
302             #pod =cut
303              
304             sub clone {
305 1     1 1 1 my ($self) = @_;
306              
307 1         3 my $clone = (ref $self)->new( $self->as_string_hash );
308             }
309              
310             sub __uniq {
311 34     34   22 my (%s, $u);
312 34 50       31 grep { defined($_) ? !$s{$_}++ : !$u++ } @_;
  105         196  
313             }
314              
315             1;
316              
317             # ABSTRACT: a set of distribution prerequisites by phase and type
318              
319             =pod
320              
321             =encoding UTF-8
322              
323             =head1 NAME
324              
325             CPAN::Meta::Prereqs - a set of distribution prerequisites by phase and type
326              
327             =head1 VERSION
328              
329             version 2.150009
330              
331             =head1 DESCRIPTION
332              
333             A CPAN::Meta::Prereqs object represents the prerequisites for a CPAN
334             distribution or one of its optional features. Each set of prereqs is
335             organized by phase and type, as described in L.
336              
337             =head1 METHODS
338              
339             =head2 new
340              
341             my $prereq = CPAN::Meta::Prereqs->new( \%prereq_spec );
342              
343             This method returns a new set of Prereqs. The input should look like the
344             contents of the C field described in L, meaning
345             something more or less like this:
346              
347             my $prereq = CPAN::Meta::Prereqs->new({
348             runtime => {
349             requires => {
350             'Some::Module' => '1.234',
351             ...,
352             },
353             ...,
354             },
355             ...,
356             });
357              
358             You can also construct an empty set of prereqs with:
359              
360             my $prereqs = CPAN::Meta::Prereqs->new;
361              
362             This empty set of prereqs is useful for accumulating new prereqs before finally
363             dumping the whole set into a structure or string.
364              
365             =head2 requirements_for
366              
367             my $requirements = $prereqs->requirements_for( $phase, $type );
368              
369             This method returns a L object for the given
370             phase/type combination. If no prerequisites are registered for that
371             combination, a new CPAN::Meta::Requirements object will be returned, and it may
372             be added to as needed.
373              
374             If C<$phase> or C<$type> are undefined or otherwise invalid, an exception will
375             be raised.
376              
377             =head2 phases
378              
379             my @phases = $prereqs->phases;
380              
381             This method returns the list of all phases currently populated in the prereqs
382             object, suitable for iterating.
383              
384             =head2 types_in
385              
386             my @runtime_types = $prereqs->types_in('runtime');
387              
388             This method returns the list of all types currently populated in the prereqs
389             object for the provided phase, suitable for iterating.
390              
391             =head2 with_merged_prereqs
392              
393             my $new_prereqs = $prereqs->with_merged_prereqs( $other_prereqs );
394              
395             my $new_prereqs = $prereqs->with_merged_prereqs( \@other_prereqs );
396              
397             This method returns a new CPAN::Meta::Prereqs objects in which all the
398             other prerequisites given are merged into the current set. This is primarily
399             provided for combining a distribution's core prereqs with the prereqs of one of
400             its optional features.
401              
402             The new prereqs object has no ties to the originals, and altering it further
403             will not alter them.
404              
405             =head2 merged_requirements
406              
407             my $new_reqs = $prereqs->merged_requirements( \@phases, \@types );
408             my $new_reqs = $prereqs->merged_requirements( \@phases );
409             my $new_reqs = $prereqs->merged_requirements();
410              
411             This method joins together all requirements across a number of phases
412             and types into a new L object. If arguments
413             are omitted, it defaults to "runtime", "build" and "test" for phases
414             and "requires" and "recommends" for types.
415              
416             =head2 as_string_hash
417              
418             This method returns a hashref containing structures suitable for dumping into a
419             distmeta data structure. It is made up of hashes and strings, only; there will
420             be no Prereqs, CPAN::Meta::Requirements, or C objects inside it.
421              
422             =head2 is_finalized
423              
424             This method returns true if the set of prereqs has been marked "finalized," and
425             cannot be altered.
426              
427             =head2 finalize
428              
429             Calling C on a Prereqs object will close it for further modification.
430             Attempting to make any changes that would actually alter the prereqs will
431             result in an exception being thrown.
432              
433             =head2 clone
434              
435             my $cloned_prereqs = $prereqs->clone;
436              
437             This method returns a Prereqs object that is identical to the original object,
438             but can be altered without affecting the original object. Finalization does
439             not survive cloning, meaning that you may clone a finalized set of prereqs and
440             then modify the clone.
441              
442             =head1 BUGS
443              
444             Please report any bugs or feature using the CPAN Request Tracker.
445             Bugs can be submitted through the web interface at
446             L
447              
448             When submitting a bug or request, please include a test-file or a patch to an
449             existing test-file that illustrates the bug or desired feature.
450              
451             =head1 AUTHORS
452              
453             =over 4
454              
455             =item *
456              
457             David Golden
458              
459             =item *
460              
461             Ricardo Signes
462              
463             =item *
464              
465             Adam Kennedy
466              
467             =back
468              
469             =head1 COPYRIGHT AND LICENSE
470              
471             This software is copyright (c) 2010 by David Golden, Ricardo Signes, Adam Kennedy and Contributors.
472              
473             This is free software; you can redistribute it and/or modify it under
474             the same terms as the Perl 5 programming language system itself.
475              
476             =cut
477              
478             __END__