1use v5.10;
2use strict;
3use warnings;
4package CPAN::Meta::Requirements;
5# ABSTRACT: a set of version requirements for a CPAN dist
6
7our $VERSION = '2.143';
8
9use CPAN::Meta::Requirements::Range;
10
11#pod =head1 SYNOPSIS
12#pod
13#pod   use CPAN::Meta::Requirements;
14#pod
15#pod   my $build_requires = CPAN::Meta::Requirements->new;
16#pod
17#pod   $build_requires->add_minimum('Library::Foo' => 1.208);
18#pod
19#pod   $build_requires->add_minimum('Library::Foo' => 2.602);
20#pod
21#pod   $build_requires->add_minimum('Module::Bar'  => 'v1.2.3');
22#pod
23#pod   $METAyml->{build_requires} = $build_requires->as_string_hash;
24#pod
25#pod =head1 DESCRIPTION
26#pod
27#pod A CPAN::Meta::Requirements object models a set of version constraints like
28#pod those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
29#pod and as defined by L<CPAN::Meta::Spec>.
30#pod It can be built up by adding more and more constraints, and it will reduce them
31#pod to the simplest representation.
32#pod
33#pod Logically impossible constraints will be identified immediately by thrown
34#pod exceptions.
35#pod
36#pod =cut
37
38use Carp ();
39
40#pod =method new
41#pod
42#pod   my $req = CPAN::Meta::Requirements->new;
43#pod
44#pod This returns a new CPAN::Meta::Requirements object.  It takes an optional
45#pod hash reference argument.  Currently, only one key is supported:
46#pod
47#pod =for :list
48#pod * C<bad_version_hook> -- if provided, when a version cannot be parsed into
49#pod   a version object, this code reference will be called with the invalid
50#pod   version string as first argument, and the module name as second
51#pod   argument.  It must return a valid version object.
52#pod
53#pod All other keys are ignored.
54#pod
55#pod =cut
56
57my @valid_options = qw( bad_version_hook );
58
59sub new {
60  my ($class, $options) = @_;
61  $options ||= {};
62  Carp::croak "Argument to $class\->new() must be a hash reference"
63    unless ref $options eq 'HASH';
64  my %self = map {; $_ => $options->{$_}} @valid_options;
65
66  return bless \%self => $class;
67}
68
69#pod =method add_minimum
70#pod
71#pod   $req->add_minimum( $module => $version );
72#pod
73#pod This adds a new minimum version requirement.  If the new requirement is
74#pod redundant to the existing specification, this has no effect.
75#pod
76#pod Minimum requirements are inclusive.  C<$version> is required, along with any
77#pod greater version number.
78#pod
79#pod This method returns the requirements object.
80#pod
81#pod =method add_maximum
82#pod
83#pod   $req->add_maximum( $module => $version );
84#pod
85#pod This adds a new maximum version requirement.  If the new requirement is
86#pod redundant to the existing specification, this has no effect.
87#pod
88#pod Maximum requirements are inclusive.  No version strictly greater than the given
89#pod version is allowed.
90#pod
91#pod This method returns the requirements object.
92#pod
93#pod =method add_exclusion
94#pod
95#pod   $req->add_exclusion( $module => $version );
96#pod
97#pod This adds a new excluded version.  For example, you might use these three
98#pod method calls:
99#pod
100#pod   $req->add_minimum( $module => '1.00' );
101#pod   $req->add_maximum( $module => '1.82' );
102#pod
103#pod   $req->add_exclusion( $module => '1.75' );
104#pod
105#pod Any version between 1.00 and 1.82 inclusive would be acceptable, except for
106#pod 1.75.
107#pod
108#pod This method returns the requirements object.
109#pod
110#pod =method exact_version
111#pod
112#pod   $req->exact_version( $module => $version );
113#pod
114#pod This sets the version required for the given module to I<exactly> the given
115#pod version.  No other version would be considered acceptable.
116#pod
117#pod This method returns the requirements object.
118#pod
119#pod =cut
120
121BEGIN {
122  for my $type (qw(maximum exclusion exact_version)) {
123    my $method = "with_$type";
124    my $to_add = $type eq 'exact_version' ? $type : "add_$type";
125
126    my $code = sub {
127      my ($self, $name, $version) = @_;
128
129      $self->__modify_entry_for($name, $method, $version);
130
131      return $self;
132    };
133
134    no strict 'refs';
135    *$to_add = $code;
136  }
137}
138
139# add_minimum is optimized compared to generated subs above because
140# it is called frequently and with "0" or equivalent input
141sub add_minimum {
142  my ($self, $name, $version) = @_;
143
144  # stringify $version so that version->new("0.00")->stringify ne "0"
145  # which preserves the user's choice of "0.00" as the requirement
146  if (not defined $version or "$version" eq '0') {
147    return $self if $self->__entry_for($name);
148    Carp::croak("can't add new requirements to finalized requirements")
149      if $self->is_finalized;
150
151    $self->{requirements}{ $name } =
152      CPAN::Meta::Requirements::Range->with_minimum('0', $name);
153  }
154  else {
155    $self->__modify_entry_for($name, 'with_minimum', $version);
156  }
157  return $self;
158}
159
160#pod =method version_range_for_module
161#pod
162#pod   $req->version_range_for_module( $another_req_object );
163#pod
164#pod =cut
165
166sub version_range_for_module {
167  my ($self, $module) = @_;
168  return $self->{requirements}{$module};
169}
170
171#pod =method add_requirements
172#pod
173#pod   $req->add_requirements( $another_req_object );
174#pod
175#pod This method adds all the requirements in the given CPAN::Meta::Requirements
176#pod object to the requirements object on which it was called.  If there are any
177#pod conflicts, an exception is thrown.
178#pod
179#pod This method returns the requirements object.
180#pod
181#pod =cut
182
183sub add_requirements {
184  my ($self, $req) = @_;
185
186  for my $module ($req->required_modules) {
187    my $new_range = $req->version_range_for_module($module);
188    $self->__modify_entry_for($module, 'with_range', $new_range);
189  }
190
191  return $self;
192}
193
194#pod =method accepts_module
195#pod
196#pod   my $bool = $req->accepts_module($module => $version);
197#pod
198#pod Given an module and version, this method returns true if the version
199#pod specification for the module accepts the provided version.  In other words,
200#pod given:
201#pod
202#pod   Module => '>= 1.00, < 2.00'
203#pod
204#pod We will accept 1.00 and 1.75 but not 0.50 or 2.00.
205#pod
206#pod For modules that do not appear in the requirements, this method will return
207#pod true.
208#pod
209#pod =cut
210
211sub accepts_module {
212  my ($self, $module, $version) = @_;
213
214  return 1 unless my $range = $self->__entry_for($module);
215  return $range->accepts($version);
216}
217
218#pod =method clear_requirement
219#pod
220#pod   $req->clear_requirement( $module );
221#pod
222#pod This removes the requirement for a given module from the object.
223#pod
224#pod This method returns the requirements object.
225#pod
226#pod =cut
227
228sub clear_requirement {
229  my ($self, $module) = @_;
230
231  return $self unless $self->__entry_for($module);
232
233  Carp::croak("can't clear requirements on finalized requirements")
234    if $self->is_finalized;
235
236  delete $self->{requirements}{ $module };
237
238  return $self;
239}
240
241#pod =method requirements_for_module
242#pod
243#pod   $req->requirements_for_module( $module );
244#pod
245#pod This returns a string containing the version requirements for a given module in
246#pod the format described in L<CPAN::Meta::Spec> or undef if the given module has no
247#pod requirements. This should only be used for informational purposes such as error
248#pod messages and should not be interpreted or used for comparison (see
249#pod L</accepts_module> instead).
250#pod
251#pod =cut
252
253sub requirements_for_module {
254  my ($self, $module) = @_;
255  my $entry = $self->__entry_for($module);
256  return unless $entry;
257  return $entry->as_string;
258}
259
260#pod =method structured_requirements_for_module
261#pod
262#pod   $req->structured_requirements_for_module( $module );
263#pod
264#pod This returns a data structure containing the version requirements for a given
265#pod module or undef if the given module has no requirements.  This should
266#pod not be used for version checks (see L</accepts_module> instead).
267#pod
268#pod Added in version 2.134.
269#pod
270#pod =cut
271
272sub structured_requirements_for_module {
273  my ($self, $module) = @_;
274  my $entry = $self->__entry_for($module);
275  return unless $entry;
276  return $entry->as_struct;
277}
278
279#pod =method required_modules
280#pod
281#pod This method returns a list of all the modules for which requirements have been
282#pod specified.
283#pod
284#pod =cut
285
286sub required_modules { keys %{ $_[0]{requirements} } }
287
288#pod =method clone
289#pod
290#pod   $req->clone;
291#pod
292#pod This method returns a clone of the invocant.  The clone and the original object
293#pod can then be changed independent of one another.
294#pod
295#pod =cut
296
297sub clone {
298  my ($self) = @_;
299  my $new = (ref $self)->new;
300
301  return $new->add_requirements($self);
302}
303
304sub __entry_for     { $_[0]{requirements}{ $_[1] } }
305
306sub __modify_entry_for {
307  my ($self, $name, $method, $version) = @_;
308
309  my $fin = $self->is_finalized;
310  my $old = $self->__entry_for($name);
311
312  Carp::croak("can't add new requirements to finalized requirements")
313    if $fin and not $old;
314
315  my $new = ($old || 'CPAN::Meta::Requirements::Range')
316          ->$method($version, $name, $self->{bad_version_hook});
317
318  Carp::croak("can't modify finalized requirements")
319    if $fin and $old->as_string ne $new->as_string;
320
321  $self->{requirements}{ $name } = $new;
322}
323
324#pod =method is_simple
325#pod
326#pod This method returns true if and only if all requirements are inclusive minimums
327#pod -- that is, if their string expression is just the version number.
328#pod
329#pod =cut
330
331sub is_simple {
332  my ($self) = @_;
333  for my $module ($self->required_modules) {
334    # XXX: This is a complete hack, but also entirely correct.
335    return if not $self->__entry_for($module)->is_simple;
336  }
337
338  return 1;
339}
340
341#pod =method is_finalized
342#pod
343#pod This method returns true if the requirements have been finalized by having the
344#pod C<finalize> method called on them.
345#pod
346#pod =cut
347
348sub is_finalized { $_[0]{finalized} }
349
350#pod =method finalize
351#pod
352#pod This method marks the requirements finalized.  Subsequent attempts to change
353#pod the requirements will be fatal, I<if> they would result in a change.  If they
354#pod would not alter the requirements, they have no effect.
355#pod
356#pod If a finalized set of requirements is cloned, the cloned requirements are not
357#pod also finalized.
358#pod
359#pod =cut
360
361sub finalize { $_[0]{finalized} = 1 }
362
363#pod =method as_string_hash
364#pod
365#pod This returns a reference to a hash describing the requirements using the
366#pod strings in the L<CPAN::Meta::Spec> specification.
367#pod
368#pod For example after the following program:
369#pod
370#pod   my $req = CPAN::Meta::Requirements->new;
371#pod
372#pod   $req->add_minimum('CPAN::Meta::Requirements' => 0.102);
373#pod
374#pod   $req->add_minimum('Library::Foo' => 1.208);
375#pod
376#pod   $req->add_maximum('Library::Foo' => 2.602);
377#pod
378#pod   $req->add_minimum('Module::Bar'  => 'v1.2.3');
379#pod
380#pod   $req->add_exclusion('Module::Bar'  => 'v1.2.8');
381#pod
382#pod   $req->exact_version('Xyzzy'  => '6.01');
383#pod
384#pod   my $hashref = $req->as_string_hash;
385#pod
386#pod C<$hashref> would contain:
387#pod
388#pod   {
389#pod     'CPAN::Meta::Requirements' => '0.102',
390#pod     'Library::Foo' => '>= 1.208, <= 2.206',
391#pod     'Module::Bar'  => '>= v1.2.3, != v1.2.8',
392#pod     'Xyzzy'        => '== 6.01',
393#pod   }
394#pod
395#pod =cut
396
397sub as_string_hash {
398  my ($self) = @_;
399
400  my %hash = map {; $_ => $self->{requirements}{$_}->as_string }
401             $self->required_modules;
402
403  return \%hash;
404}
405
406#pod =method add_string_requirement
407#pod
408#pod   $req->add_string_requirement('Library::Foo' => '>= 1.208, <= 2.206');
409#pod   $req->add_string_requirement('Library::Foo' => v1.208);
410#pod
411#pod This method parses the passed in string and adds the appropriate requirement
412#pod for the given module.  A version can be a Perl "v-string".  It understands
413#pod version ranges as described in the L<CPAN::Meta::Spec/Version Ranges>. For
414#pod example:
415#pod
416#pod =over 4
417#pod
418#pod =item 1.3
419#pod
420#pod =item >= 1.3
421#pod
422#pod =item <= 1.3
423#pod
424#pod =item == 1.3
425#pod
426#pod =item != 1.3
427#pod
428#pod =item > 1.3
429#pod
430#pod =item < 1.3
431#pod
432#pod =item >= 1.3, != 1.5, <= 2.0
433#pod
434#pod A version number without an operator is equivalent to specifying a minimum
435#pod (C<E<gt>=>).  Extra whitespace is allowed.
436#pod
437#pod =back
438#pod
439#pod =cut
440
441sub add_string_requirement {
442  my ($self, $module, $req) = @_;
443
444  $self->__modify_entry_for($module, 'with_string_requirement', $req);
445}
446
447#pod =method from_string_hash
448#pod
449#pod   my $req = CPAN::Meta::Requirements->from_string_hash( \%hash );
450#pod   my $req = CPAN::Meta::Requirements->from_string_hash( \%hash, \%opts );
451#pod
452#pod This is an alternate constructor for a CPAN::Meta::Requirements
453#pod object. It takes a hash of module names and version requirement
454#pod strings and returns a new CPAN::Meta::Requirements object. As with
455#pod add_string_requirement, a version can be a Perl "v-string". Optionally,
456#pod you can supply a hash-reference of options, exactly as with the L</new>
457#pod method.
458#pod
459#pod =cut
460
461sub from_string_hash {
462  my ($class, $hash, $options) = @_;
463
464  my $self = $class->new($options);
465
466  for my $module (keys %$hash) {
467    my $req = $hash->{$module};
468    $self->add_string_requirement($module, $req);
469  }
470
471  return $self;
472}
473
4741;
475# vim: ts=2 sts=2 sw=2 et:
476
477__END__
478
479=pod
480
481=encoding UTF-8
482
483=head1 NAME
484
485CPAN::Meta::Requirements - a set of version requirements for a CPAN dist
486
487=head1 VERSION
488
489version 2.143
490
491=head1 SYNOPSIS
492
493  use CPAN::Meta::Requirements;
494
495  my $build_requires = CPAN::Meta::Requirements->new;
496
497  $build_requires->add_minimum('Library::Foo' => 1.208);
498
499  $build_requires->add_minimum('Library::Foo' => 2.602);
500
501  $build_requires->add_minimum('Module::Bar'  => 'v1.2.3');
502
503  $METAyml->{build_requires} = $build_requires->as_string_hash;
504
505=head1 DESCRIPTION
506
507A CPAN::Meta::Requirements object models a set of version constraints like
508those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
509and as defined by L<CPAN::Meta::Spec>.
510It can be built up by adding more and more constraints, and it will reduce them
511to the simplest representation.
512
513Logically impossible constraints will be identified immediately by thrown
514exceptions.
515
516=head1 METHODS
517
518=head2 new
519
520  my $req = CPAN::Meta::Requirements->new;
521
522This returns a new CPAN::Meta::Requirements object.  It takes an optional
523hash reference argument.  Currently, only one key is supported:
524
525=over 4
526
527=item *
528
529C<bad_version_hook> -- if provided, when a version cannot be parsed into a version object, this code reference will be called with the invalid version string as first argument, and the module name as second argument.  It must return a valid version object.
530
531=back
532
533All other keys are ignored.
534
535=head2 add_minimum
536
537  $req->add_minimum( $module => $version );
538
539This adds a new minimum version requirement.  If the new requirement is
540redundant to the existing specification, this has no effect.
541
542Minimum requirements are inclusive.  C<$version> is required, along with any
543greater version number.
544
545This method returns the requirements object.
546
547=head2 add_maximum
548
549  $req->add_maximum( $module => $version );
550
551This adds a new maximum version requirement.  If the new requirement is
552redundant to the existing specification, this has no effect.
553
554Maximum requirements are inclusive.  No version strictly greater than the given
555version is allowed.
556
557This method returns the requirements object.
558
559=head2 add_exclusion
560
561  $req->add_exclusion( $module => $version );
562
563This adds a new excluded version.  For example, you might use these three
564method calls:
565
566  $req->add_minimum( $module => '1.00' );
567  $req->add_maximum( $module => '1.82' );
568
569  $req->add_exclusion( $module => '1.75' );
570
571Any version between 1.00 and 1.82 inclusive would be acceptable, except for
5721.75.
573
574This method returns the requirements object.
575
576=head2 exact_version
577
578  $req->exact_version( $module => $version );
579
580This sets the version required for the given module to I<exactly> the given
581version.  No other version would be considered acceptable.
582
583This method returns the requirements object.
584
585=head2 version_range_for_module
586
587  $req->version_range_for_module( $another_req_object );
588
589=head2 add_requirements
590
591  $req->add_requirements( $another_req_object );
592
593This method adds all the requirements in the given CPAN::Meta::Requirements
594object to the requirements object on which it was called.  If there are any
595conflicts, an exception is thrown.
596
597This method returns the requirements object.
598
599=head2 accepts_module
600
601  my $bool = $req->accepts_module($module => $version);
602
603Given an module and version, this method returns true if the version
604specification for the module accepts the provided version.  In other words,
605given:
606
607  Module => '>= 1.00, < 2.00'
608
609We will accept 1.00 and 1.75 but not 0.50 or 2.00.
610
611For modules that do not appear in the requirements, this method will return
612true.
613
614=head2 clear_requirement
615
616  $req->clear_requirement( $module );
617
618This removes the requirement for a given module from the object.
619
620This method returns the requirements object.
621
622=head2 requirements_for_module
623
624  $req->requirements_for_module( $module );
625
626This returns a string containing the version requirements for a given module in
627the format described in L<CPAN::Meta::Spec> or undef if the given module has no
628requirements. This should only be used for informational purposes such as error
629messages and should not be interpreted or used for comparison (see
630L</accepts_module> instead).
631
632=head2 structured_requirements_for_module
633
634  $req->structured_requirements_for_module( $module );
635
636This returns a data structure containing the version requirements for a given
637module or undef if the given module has no requirements.  This should
638not be used for version checks (see L</accepts_module> instead).
639
640Added in version 2.134.
641
642=head2 required_modules
643
644This method returns a list of all the modules for which requirements have been
645specified.
646
647=head2 clone
648
649  $req->clone;
650
651This method returns a clone of the invocant.  The clone and the original object
652can then be changed independent of one another.
653
654=head2 is_simple
655
656This method returns true if and only if all requirements are inclusive minimums
657-- that is, if their string expression is just the version number.
658
659=head2 is_finalized
660
661This method returns true if the requirements have been finalized by having the
662C<finalize> method called on them.
663
664=head2 finalize
665
666This method marks the requirements finalized.  Subsequent attempts to change
667the requirements will be fatal, I<if> they would result in a change.  If they
668would not alter the requirements, they have no effect.
669
670If a finalized set of requirements is cloned, the cloned requirements are not
671also finalized.
672
673=head2 as_string_hash
674
675This returns a reference to a hash describing the requirements using the
676strings in the L<CPAN::Meta::Spec> specification.
677
678For example after the following program:
679
680  my $req = CPAN::Meta::Requirements->new;
681
682  $req->add_minimum('CPAN::Meta::Requirements' => 0.102);
683
684  $req->add_minimum('Library::Foo' => 1.208);
685
686  $req->add_maximum('Library::Foo' => 2.602);
687
688  $req->add_minimum('Module::Bar'  => 'v1.2.3');
689
690  $req->add_exclusion('Module::Bar'  => 'v1.2.8');
691
692  $req->exact_version('Xyzzy'  => '6.01');
693
694  my $hashref = $req->as_string_hash;
695
696C<$hashref> would contain:
697
698  {
699    'CPAN::Meta::Requirements' => '0.102',
700    'Library::Foo' => '>= 1.208, <= 2.206',
701    'Module::Bar'  => '>= v1.2.3, != v1.2.8',
702    'Xyzzy'        => '== 6.01',
703  }
704
705=head2 add_string_requirement
706
707  $req->add_string_requirement('Library::Foo' => '>= 1.208, <= 2.206');
708  $req->add_string_requirement('Library::Foo' => v1.208);
709
710This method parses the passed in string and adds the appropriate requirement
711for the given module.  A version can be a Perl "v-string".  It understands
712version ranges as described in the L<CPAN::Meta::Spec/Version Ranges>. For
713example:
714
715=over 4
716
717=item 1.3
718
719=item >= 1.3
720
721=item <= 1.3
722
723=item == 1.3
724
725=item != 1.3
726
727=item > 1.3
728
729=item < 1.3
730
731=item >= 1.3, != 1.5, <= 2.0
732
733A version number without an operator is equivalent to specifying a minimum
734(C<E<gt>=>).  Extra whitespace is allowed.
735
736=back
737
738=head2 from_string_hash
739
740  my $req = CPAN::Meta::Requirements->from_string_hash( \%hash );
741  my $req = CPAN::Meta::Requirements->from_string_hash( \%hash, \%opts );
742
743This is an alternate constructor for a CPAN::Meta::Requirements
744object. It takes a hash of module names and version requirement
745strings and returns a new CPAN::Meta::Requirements object. As with
746add_string_requirement, a version can be a Perl "v-string". Optionally,
747you can supply a hash-reference of options, exactly as with the L</new>
748method.
749
750=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
751
752=head1 SUPPORT
753
754=head2 Bugs / Feature Requests
755
756Please report any bugs or feature requests through the issue tracker
757at L<https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements/issues>.
758You will be notified automatically of any progress on your issue.
759
760=head2 Source Code
761
762This is open source software.  The code repository is available for
763public review and contribution under the terms of the license.
764
765L<https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements>
766
767  git clone https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements.git
768
769=head1 AUTHORS
770
771=over 4
772
773=item *
774
775David Golden <dagolden@cpan.org>
776
777=item *
778
779Ricardo Signes <rjbs@cpan.org>
780
781=back
782
783=head1 CONTRIBUTORS
784
785=for stopwords Ed J Graham Knop Karen Etheridge Leon Timmermans Paul Howarth Ricardo Signes robario Tatsuhiko Miyagawa
786
787=over 4
788
789=item *
790
791Ed J <mohawk2@users.noreply.github.com>
792
793=item *
794
795Graham Knop <haarg@haarg.org>
796
797=item *
798
799Karen Etheridge <ether@cpan.org>
800
801=item *
802
803Leon Timmermans <fawaka@gmail.com>
804
805=item *
806
807Paul Howarth <paul@city-fan.org>
808
809=item *
810
811Ricardo Signes <rjbs@semiotic.systems>
812
813=item *
814
815robario <webmaster@robario.com>
816
817=item *
818
819Tatsuhiko Miyagawa <miyagawa@bulknews.net>
820
821=item *
822
823Tatsuhiko Miyagawa <miyagawa@gmail.com>
824
825=back
826
827=head1 COPYRIGHT AND LICENSE
828
829This software is copyright (c) 2010 by David Golden and Ricardo Signes.
830
831This is free software; you can redistribute it and/or modify it under
832the same terms as the Perl 5 programming language system itself.
833
834=cut
835