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