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   40414 use 5.006;
  15         34  
2 15     15   49 use strict;
  15         71  
  15         252  
3 15     15   49 use warnings;
  15         17  
  15         700  
4             package CPAN::Meta::Prereqs;
5              
6             our $VERSION = '2.150008'; # 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   52 use Carp qw(confess);
  15         26  
  15         646  
17 15     15   52 use Scalar::Util qw(blessed);
  15         12  
  15         1018  
18 15     15   6928 use CPAN::Meta::Requirements 2.121;
  15         62623  
  15         14707  
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   506 sub __legal_phases { qw(configure build test runtime develop) }
50 335     335   398 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 1270 my ($class, $prereq_spec) = @_;
55 28   100     63 $prereq_spec ||= {};
56              
57 28         54 my %is_legal_phase = map {; $_ => 1 } $class->__legal_phases;
  140         166  
58 28         72 my %is_legal_type = map {; $_ => 1 } $class->__legal_types;
  112         127  
59              
60 28         30 my %guts;
61 28         71 PHASE: for my $phase (keys %$prereq_spec) {
62 67 50 66     9227 next PHASE unless $phase =~ /\Ax_/i or $is_legal_phase{$phase};
63              
64 67         114 my $phase_spec = $prereq_spec->{ $phase };
65 67 50       116 next PHASE unless keys %$phase_spec;
66              
67 67         91 TYPE: for my $type (keys %$phase_spec) {
68 104 50 66     9930 next TYPE unless $type =~ /\Ax_/i or $is_legal_type{$type};
69              
70 104         100 my $spec = $phase_spec->{ $type };
71              
72 104 50       183 next TYPE unless keys %$spec;
73              
74 104         207 $guts{prereqs}{$phase}{$type} = CPAN::Meta::Requirements->from_string_hash(
75             $spec
76             );
77             }
78             }
79              
80 28         3203 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 14840 my ($self, $phase, $type) = @_;
99              
100 217 50       308 confess "requirements_for called without phase" unless defined $phase;
101 217 50       254 confess "requirements_for called without type" unless defined $type;
102              
103 217 50 66     531 unless ($phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases) {
  1005         1197  
104 0         0 confess "requested requirements for unknown phase: $phase";
105             }
106              
107 217 50 66     488 unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) {
  796         953  
108 0         0 confess "requested requirements for unknown type: $type";
109             }
110              
111 217   66     481 my $req = ($self->{prereqs}{$phase}{$type} ||= CPAN::Meta::Requirements->new);
112              
113 217 100       487 $req->finalize if $self->is_finalized;
114              
115 217         306 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 36 my ($self) = @_;
129              
130 33         48 my %is_legal_phase = map {; $_ => 1 } $self->__legal_phases;
  165         188  
131 33 100       41 grep { /\Ax_/i or $is_legal_phase{$_} } keys %{ $self->{prereqs} };
  87         287  
  33         130  
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 93 my ($self, $phase) = @_;
145              
146 99 50 66     266 return unless $phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases;
  450         563  
147              
148 99         124 my %is_legal_type = map {; $_ => 1 } $self->__legal_types;
  396         466  
149 99 100       92 grep { /\Ax_/i or $is_legal_type{$_} } keys %{ $self->{prereqs}{$phase} };
  139         409  
  99         189  
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       50 my @other = blessed($other) ? $other : @$other;
172              
173 8         13 my @prereq_objs = ($self, @other);
174              
175 8         8 my %new_arg;
176              
177 8         14 for my $phase (__uniq(map { $_->phases } @prereq_objs)) {
  16         29  
178 26         940 for my $type (__uniq(map { $_->types_in($phase) } @prereq_objs)) {
  52         71  
179              
180 45         539 my $req = CPAN::Meta::Requirements->new;
181              
182 45         332 for my $prereq (@prereq_objs) {
183 90         4841 my $this_req = $prereq->requirements_for($phase, $type);
184 90 100       131 next unless $this_req->required_modules;
185              
186 57         243 $req->add_requirements($this_req);
187             }
188              
189 45 50       8344 next unless $req->required_modules;
190              
191 45         190 $new_arg{ $phase }{ $type } = $req->as_string_hash;
192             }
193             }
194              
195 8         163 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       7 $phases = [qw/runtime build test/] unless defined $phases;
214 2 100       5 $types = [qw/requires recommends/] unless defined $types;
215              
216 2 50       6 confess "merged_requirements phases argument must be an arrayref"
217             unless ref $phases eq 'ARRAY';
218 2 50       6 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         24 for my $phase ( @$phases ) {
224 6 50 33     213 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         7 for my $type ( @$types ) {
228 9 50 33     165 unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) {
  36         46  
229 0         0 confess "requested requirements for unknown type: $type";
230             }
231 9         12 $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 1752 my ($self) = @_;
251              
252 17         17 my %hash;
253              
254 17         34 for my $phase ($self->phases) {
255 47         889 for my $type ($self->types_in($phase)) {
256 74         563 my $req = $self->requirements_for($phase, $type);
257 74 100       121 next unless $req->required_modules;
258              
259 73         291 $hash{ $phase }{ $type } = $req->as_string_hash;
260             }
261             }
262              
263 17         354 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 686 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 622 my ($self) = @_;
285              
286 1         5 $self->{finalized} = 1;
287              
288 1         1 for my $phase (keys %{ $self->{prereqs} }) {
  1         5  
289 2         5 $_->finalize for values %{ $self->{prereqs}{$phase} };
  2         7  
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         4 my $clone = (ref $self)->new( $self->as_string_hash );
308             }
309              
310             sub __uniq {
311 34     34   30 my (%s, $u);
312 34 50       36 grep { defined($_) ? !$s{$_}++ : !$u++ } @_;
  105         200  
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.150008
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__