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   39131 use 5.006;
  15         31  
2 15     15   45 use strict;
  15         63  
  15         209  
3 15     15   37 use warnings;
  15         19  
  15         636  
4             package CPAN::Meta::Prereqs;
5              
6             our $VERSION = '2.150010';
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   51 use Carp qw(confess);
  15         21  
  15         613  
17 15     15   45 use Scalar::Util qw(blessed);
  15         14  
  15         1038  
18 15     15   7068 use CPAN::Meta::Requirements 2.121;
  15         62529  
  15         15027  
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   494 sub __legal_phases { qw(configure build test runtime develop) }
50 335     335   393 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 1273 my ($class, $prereq_spec) = @_;
55 28   100     63 $prereq_spec ||= {};
56              
57 28         55 my %is_legal_phase = map {; $_ => 1 } $class->__legal_phases;
  140         171  
58 28         55 my %is_legal_type = map {; $_ => 1 } $class->__legal_types;
  112         124  
59              
60 28         75 my %guts;
61 28         85 PHASE: for my $phase (keys %$prereq_spec) {
62 67 50 66     10473 next PHASE unless $phase =~ /\Ax_/i or $is_legal_phase{$phase};
63              
64 67         63 my $phase_spec = $prereq_spec->{ $phase };
65 67 50       122 next PHASE unless keys %$phase_spec;
66              
67 67         139 TYPE: for my $type (keys %$phase_spec) {
68 104 50 66     9157 next TYPE unless $type =~ /\Ax_/i or $is_legal_type{$type};
69              
70 104         87 my $spec = $phase_spec->{ $type };
71              
72 104 50       173 next TYPE unless keys %$spec;
73              
74 104         197 $guts{prereqs}{$phase}{$type} = CPAN::Meta::Requirements->from_string_hash(
75             $spec
76             );
77             }
78             }
79              
80 28         2658 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 15094 my ($self, $phase, $type) = @_;
99              
100 217 50       307 confess "requirements_for called without phase" unless defined $phase;
101 217 50       282 confess "requirements_for called without type" unless defined $type;
102              
103 217 50 66     540 unless ($phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases) {
  1005         1184  
104 0         0 confess "requested requirements for unknown phase: $phase";
105             }
106              
107 217 50 66     482 unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) {
  796         956  
108 0         0 confess "requested requirements for unknown type: $type";
109             }
110              
111 217   66     473 my $req = ($self->{prereqs}{$phase}{$type} ||= CPAN::Meta::Requirements->new);
112              
113 217 100       499 $req->finalize if $self->is_finalized;
114              
115 217         293 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 33 my ($self) = @_;
129              
130 33         51 my %is_legal_phase = map {; $_ => 1 } $self->__legal_phases;
  165         191  
131 33 100       43 grep { /\Ax_/i or $is_legal_phase{$_} } keys %{ $self->{prereqs} };
  87         280  
  33         93  
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 88 my ($self, $phase) = @_;
145              
146 99 50 66     276 return unless $phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases;
  450         565  
147              
148 99         129 my %is_legal_type = map {; $_ => 1 } $self->__legal_types;
  396         399  
149 99 100       95 grep { /\Ax_/i or $is_legal_type{$_} } keys %{ $self->{prereqs}{$phase} };
  139         420  
  99         191  
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 12 my ($self, $other) = @_;
170              
171 8 100       52 my @other = blessed($other) ? $other : @$other;
172              
173 8         15 my @prereq_objs = ($self, @other);
174              
175 8         11 my %new_arg;
176              
177 8         12 for my $phase (__uniq(map { $_->phases } @prereq_objs)) {
  16         30  
178 26         1073 for my $type (__uniq(map { $_->types_in($phase) } @prereq_objs)) {
  52         68  
179              
180 45         464 my $req = CPAN::Meta::Requirements->new;
181              
182 45         313 for my $prereq (@prereq_objs) {
183 90         4792 my $this_req = $prereq->requirements_for($phase, $type);
184 90 100       119 next unless $this_req->required_modules;
185              
186 57         245 $req->add_requirements($this_req);
187             }
188              
189 45 50       8470 next unless $req->required_modules;
190              
191 45         195 $new_arg{ $phase }{ $type } = $req->as_string_hash;
192             }
193             }
194              
195 8         112 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 435 my ($self, $phases, $types) = @_;
213 2 100       6 $phases = [qw/runtime build test/] unless defined $phases;
214 2 100       3 $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       3 confess "merged_requirements types argument must be an arrayref"
219             unless ref $types eq 'ARRAY';
220              
221 2         6 my $req = CPAN::Meta::Requirements->new;
222              
223 2         18 for my $phase ( @$phases ) {
224 6 50 33     203 unless ($phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases) {
  30         39  
225 0         0 confess "requested requirements for unknown phase: $phase";
226             }
227 6         6 for my $type ( @$types ) {
228 9 50 33     141 unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) {
  36         42  
229 0         0 confess "requested requirements for unknown type: $type";
230             }
231 9         11 $req->add_requirements( $self->requirements_for($phase, $type) );
232             }
233             }
234              
235 2 50       12 $req->finalize if $self->is_finalized;
236              
237 2         6 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 1587 my ($self) = @_;
251              
252 17         17 my %hash;
253              
254 17         33 for my $phase ($self->phases) {
255 47         541 for my $type ($self->types_in($phase)) {
256 74         930 my $req = $self->requirements_for($phase, $type);
257 74 100       116 next unless $req->required_modules;
258              
259 73         308 $hash{ $phase }{ $type } = $req->as_string_hash;
260             }
261             }
262              
263 17         312 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 660 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 578 my ($self) = @_;
285              
286 1         4 $self->{finalized} = 1;
287              
288 1         1 for my $phase (keys %{ $self->{prereqs} }) {
  1         5  
289 2         7 $_->finalize for values %{ $self->{prereqs}{$phase} };
  2         6  
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 2 my ($self) = @_;
306              
307 1         3 my $clone = (ref $self)->new( $self->as_string_hash );
308             }
309              
310             sub __uniq {
311 34     34   26 my (%s, $u);
312 34 50       33 grep { defined($_) ? !$s{$_}++ : !$u++ } @_;
  105         219  
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.150010
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__