summaryrefslogtreecommitdiffstats
path: root/.checksetup_lib/lib/perl5/CPAN/Meta/Requirements.pm
diff options
context:
space:
mode:
Diffstat (limited to '.checksetup_lib/lib/perl5/CPAN/Meta/Requirements.pm')
-rw-r--r--.checksetup_lib/lib/perl5/CPAN/Meta/Requirements.pm1194
1 files changed, 1194 insertions, 0 deletions
diff --git a/.checksetup_lib/lib/perl5/CPAN/Meta/Requirements.pm b/.checksetup_lib/lib/perl5/CPAN/Meta/Requirements.pm
new file mode 100644
index 000000000..b0e83b0d2
--- /dev/null
+++ b/.checksetup_lib/lib/perl5/CPAN/Meta/Requirements.pm
@@ -0,0 +1,1194 @@
+use 5.006; # keep at v5.6 for CPAN.pm
+use strict;
+use warnings;
+package CPAN::Meta::Requirements;
+# ABSTRACT: a set of version requirements for a CPAN dist
+
+our $VERSION = '2.140';
+
+#pod =head1 SYNOPSIS
+#pod
+#pod use CPAN::Meta::Requirements;
+#pod
+#pod my $build_requires = CPAN::Meta::Requirements->new;
+#pod
+#pod $build_requires->add_minimum('Library::Foo' => 1.208);
+#pod
+#pod $build_requires->add_minimum('Library::Foo' => 2.602);
+#pod
+#pod $build_requires->add_minimum('Module::Bar' => 'v1.2.3');
+#pod
+#pod $METAyml->{build_requires} = $build_requires->as_string_hash;
+#pod
+#pod =head1 DESCRIPTION
+#pod
+#pod A CPAN::Meta::Requirements object models a set of version constraints like
+#pod those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
+#pod and as defined by L<CPAN::Meta::Spec>;
+#pod It can be built up by adding more and more constraints, and it will reduce them
+#pod to the simplest representation.
+#pod
+#pod Logically impossible constraints will be identified immediately by thrown
+#pod exceptions.
+#pod
+#pod =cut
+
+use Carp ();
+
+# To help ExtUtils::MakeMaker bootstrap CPAN::Meta::Requirements on perls
+# before 5.10, we fall back to the EUMM bundled compatibility version module if
+# that's the only thing available. This shouldn't ever happen in a normal CPAN
+# install of CPAN::Meta::Requirements, as version.pm will be picked up from
+# prereqs and be available at runtime.
+
+BEGIN {
+ eval "use version ()"; ## no critic
+ if ( my $err = $@ ) {
+ eval "use ExtUtils::MakeMaker::version" or die $err; ## no critic
+ }
+}
+
+# Perl 5.10.0 didn't have "is_qv" in version.pm
+*_is_qv = version->can('is_qv') ? sub { $_[0]->is_qv } : sub { exists $_[0]->{qv} };
+
+# construct once, reuse many times
+my $V0 = version->new(0);
+
+#pod =method new
+#pod
+#pod my $req = CPAN::Meta::Requirements->new;
+#pod
+#pod This returns a new CPAN::Meta::Requirements object. It takes an optional
+#pod hash reference argument. Currently, only one key is supported:
+#pod
+#pod =for :list
+#pod * C<bad_version_hook> -- if provided, when a version cannot be parsed into
+#pod a version object, this code reference will be called with the invalid
+#pod version string as first argument, and the module name as second
+#pod argument. It must return a valid version object.
+#pod
+#pod All other keys are ignored.
+#pod
+#pod =cut
+
+my @valid_options = qw( bad_version_hook );
+
+sub new {
+ my ($class, $options) = @_;
+ $options ||= {};
+ Carp::croak "Argument to $class\->new() must be a hash reference"
+ unless ref $options eq 'HASH';
+ my %self = map {; $_ => $options->{$_}} @valid_options;
+
+ return bless \%self => $class;
+}
+
+# from version::vpp
+sub _find_magic_vstring {
+ my $value = shift;
+ my $tvalue = '';
+ require B;
+ my $sv = B::svref_2object(\$value);
+ my $magic = ref($sv) eq 'B::PVMG' ? $sv->MAGIC : undef;
+ while ( $magic ) {
+ if ( $magic->TYPE eq 'V' ) {
+ $tvalue = $magic->PTR;
+ $tvalue =~ s/^v?(.+)$/v$1/;
+ last;
+ }
+ else {
+ $magic = $magic->MOREMAGIC;
+ }
+ }
+ return $tvalue;
+}
+
+# safe if given an unblessed reference
+sub _isa_version {
+ UNIVERSAL::isa( $_[0], 'UNIVERSAL' ) && $_[0]->isa('version')
+}
+
+sub _version_object {
+ my ($self, $module, $version) = @_;
+
+ my ($vobj, $err);
+
+ if (not defined $version or (!ref($version) && $version eq '0')) {
+ return $V0;
+ }
+ elsif ( ref($version) eq 'version' || ( ref($version) && _isa_version($version) ) ) {
+ $vobj = $version;
+ }
+ else {
+ # hack around version::vpp not handling <3 character vstring literals
+ if ( $INC{'version/vpp.pm'} || $INC{'ExtUtils/MakeMaker/version/vpp.pm'} ) {
+ my $magic = _find_magic_vstring( $version );
+ $version = $magic if length $magic;
+ }
+ # pad to 3 characters if before 5.8.1 and appears to be a v-string
+ if ( $] < 5.008001 && $version !~ /\A[0-9]/ && substr($version,0,1) ne 'v' && length($version) < 3 ) {
+ $version .= "\0" x (3 - length($version));
+ }
+ eval {
+ local $SIG{__WARN__} = sub { die "Invalid version: $_[0]" };
+ # avoid specific segfault on some older version.pm versions
+ die "Invalid version: $version" if $version eq 'version';
+ $vobj = version->new($version);
+ };
+ if ( my $err = $@ ) {
+ my $hook = $self->{bad_version_hook};
+ $vobj = eval { $hook->($version, $module) }
+ if ref $hook eq 'CODE';
+ unless (eval { $vobj->isa("version") }) {
+ $err =~ s{ at .* line \d+.*$}{};
+ die "Can't convert '$version': $err";
+ }
+ }
+ }
+
+ # ensure no leading '.'
+ if ( $vobj =~ m{\A\.} ) {
+ $vobj = version->new("0$vobj");
+ }
+
+ # ensure normal v-string form
+ if ( _is_qv($vobj) ) {
+ $vobj = version->new($vobj->normal);
+ }
+
+ return $vobj;
+}
+
+#pod =method add_minimum
+#pod
+#pod $req->add_minimum( $module => $version );
+#pod
+#pod This adds a new minimum version requirement. If the new requirement is
+#pod redundant to the existing specification, this has no effect.
+#pod
+#pod Minimum requirements are inclusive. C<$version> is required, along with any
+#pod greater version number.
+#pod
+#pod This method returns the requirements object.
+#pod
+#pod =method add_maximum
+#pod
+#pod $req->add_maximum( $module => $version );
+#pod
+#pod This adds a new maximum version requirement. If the new requirement is
+#pod redundant to the existing specification, this has no effect.
+#pod
+#pod Maximum requirements are inclusive. No version strictly greater than the given
+#pod version is allowed.
+#pod
+#pod This method returns the requirements object.
+#pod
+#pod =method add_exclusion
+#pod
+#pod $req->add_exclusion( $module => $version );
+#pod
+#pod This adds a new excluded version. For example, you might use these three
+#pod method calls:
+#pod
+#pod $req->add_minimum( $module => '1.00' );
+#pod $req->add_maximum( $module => '1.82' );
+#pod
+#pod $req->add_exclusion( $module => '1.75' );
+#pod
+#pod Any version between 1.00 and 1.82 inclusive would be acceptable, except for
+#pod 1.75.
+#pod
+#pod This method returns the requirements object.
+#pod
+#pod =method exact_version
+#pod
+#pod $req->exact_version( $module => $version );
+#pod
+#pod This sets the version required for the given module to I<exactly> the given
+#pod version. No other version would be considered acceptable.
+#pod
+#pod This method returns the requirements object.
+#pod
+#pod =cut
+
+BEGIN {
+ for my $type (qw(maximum exclusion exact_version)) {
+ my $method = "with_$type";
+ my $to_add = $type eq 'exact_version' ? $type : "add_$type";
+
+ my $code = sub {
+ my ($self, $name, $version) = @_;
+
+ $version = $self->_version_object( $name, $version );
+
+ $self->__modify_entry_for($name, $method, $version);
+
+ return $self;
+ };
+
+ no strict 'refs';
+ *$to_add = $code;
+ }
+}
+
+# add_minimum is optimized compared to generated subs above because
+# it is called frequently and with "0" or equivalent input
+sub add_minimum {
+ my ($self, $name, $version) = @_;
+
+ # stringify $version so that version->new("0.00")->stringify ne "0"
+ # which preserves the user's choice of "0.00" as the requirement
+ if (not defined $version or "$version" eq '0') {
+ return $self if $self->__entry_for($name);
+ Carp::confess("can't add new requirements to finalized requirements")
+ if $self->is_finalized;
+
+ $self->{requirements}{ $name } =
+ CPAN::Meta::Requirements::_Range::Range->with_minimum($V0, $name);
+ }
+ else {
+ $version = $self->_version_object( $name, $version );
+
+ $self->__modify_entry_for($name, 'with_minimum', $version);
+ }
+ return $self;
+}
+
+#pod =method add_requirements
+#pod
+#pod $req->add_requirements( $another_req_object );
+#pod
+#pod This method adds all the requirements in the given CPAN::Meta::Requirements
+#pod object to the requirements object on which it was called. If there are any
+#pod conflicts, an exception is thrown.
+#pod
+#pod This method returns the requirements object.
+#pod
+#pod =cut
+
+sub add_requirements {
+ my ($self, $req) = @_;
+
+ for my $module ($req->required_modules) {
+ my $modifiers = $req->__entry_for($module)->as_modifiers;
+ for my $modifier (@$modifiers) {
+ my ($method, @args) = @$modifier;
+ $self->$method($module => @args);
+ };
+ }
+
+ return $self;
+}
+
+#pod =method accepts_module
+#pod
+#pod my $bool = $req->accepts_module($module => $version);
+#pod
+#pod Given an module and version, this method returns true if the version
+#pod specification for the module accepts the provided version. In other words,
+#pod given:
+#pod
+#pod Module => '>= 1.00, < 2.00'
+#pod
+#pod We will accept 1.00 and 1.75 but not 0.50 or 2.00.
+#pod
+#pod For modules that do not appear in the requirements, this method will return
+#pod true.
+#pod
+#pod =cut
+
+sub accepts_module {
+ my ($self, $module, $version) = @_;
+
+ $version = $self->_version_object( $module, $version );
+
+ return 1 unless my $range = $self->__entry_for($module);
+ return $range->_accepts($version);
+}
+
+#pod =method clear_requirement
+#pod
+#pod $req->clear_requirement( $module );
+#pod
+#pod This removes the requirement for a given module from the object.
+#pod
+#pod This method returns the requirements object.
+#pod
+#pod =cut
+
+sub clear_requirement {
+ my ($self, $module) = @_;
+
+ return $self unless $self->__entry_for($module);
+
+ Carp::confess("can't clear requirements on finalized requirements")
+ if $self->is_finalized;
+
+ delete $self->{requirements}{ $module };
+
+ return $self;
+}
+
+#pod =method requirements_for_module
+#pod
+#pod $req->requirements_for_module( $module );
+#pod
+#pod This returns a string containing the version requirements for a given module in
+#pod the format described in L<CPAN::Meta::Spec> or undef if the given module has no
+#pod requirements. This should only be used for informational purposes such as error
+#pod messages and should not be interpreted or used for comparison (see
+#pod L</accepts_module> instead).
+#pod
+#pod =cut
+
+sub requirements_for_module {
+ my ($self, $module) = @_;
+ my $entry = $self->__entry_for($module);
+ return unless $entry;
+ return $entry->as_string;
+}
+
+#pod =method structured_requirements_for_module
+#pod
+#pod $req->structured_requirements_for_module( $module );
+#pod
+#pod This returns a data structure containing the version requirements for a given
+#pod module or undef if the given module has no requirements. This should
+#pod not be used for version checks (see L</accepts_module> instead).
+#pod
+#pod Added in version 2.134.
+#pod
+#pod =cut
+
+sub structured_requirements_for_module {
+ my ($self, $module) = @_;
+ my $entry = $self->__entry_for($module);
+ return unless $entry;
+ return $entry->as_struct;
+}
+
+#pod =method required_modules
+#pod
+#pod This method returns a list of all the modules for which requirements have been
+#pod specified.
+#pod
+#pod =cut
+
+sub required_modules { keys %{ $_[0]{requirements} } }
+
+#pod =method clone
+#pod
+#pod $req->clone;
+#pod
+#pod This method returns a clone of the invocant. The clone and the original object
+#pod can then be changed independent of one another.
+#pod
+#pod =cut
+
+sub clone {
+ my ($self) = @_;
+ my $new = (ref $self)->new;
+
+ return $new->add_requirements($self);
+}
+
+sub __entry_for { $_[0]{requirements}{ $_[1] } }
+
+sub __modify_entry_for {
+ my ($self, $name, $method, $version) = @_;
+
+ my $fin = $self->is_finalized;
+ my $old = $self->__entry_for($name);
+
+ Carp::confess("can't add new requirements to finalized requirements")
+ if $fin and not $old;
+
+ my $new = ($old || 'CPAN::Meta::Requirements::_Range::Range')
+ ->$method($version, $name);
+
+ Carp::confess("can't modify finalized requirements")
+ if $fin and $old->as_string ne $new->as_string;
+
+ $self->{requirements}{ $name } = $new;
+}
+
+#pod =method is_simple
+#pod
+#pod This method returns true if and only if all requirements are inclusive minimums
+#pod -- that is, if their string expression is just the version number.
+#pod
+#pod =cut
+
+sub is_simple {
+ my ($self) = @_;
+ for my $module ($self->required_modules) {
+ # XXX: This is a complete hack, but also entirely correct.
+ return if $self->__entry_for($module)->as_string =~ /\s/;
+ }
+
+ return 1;
+}
+
+#pod =method is_finalized
+#pod
+#pod This method returns true if the requirements have been finalized by having the
+#pod C<finalize> method called on them.
+#pod
+#pod =cut
+
+sub is_finalized { $_[0]{finalized} }
+
+#pod =method finalize
+#pod
+#pod This method marks the requirements finalized. Subsequent attempts to change
+#pod the requirements will be fatal, I<if> they would result in a change. If they
+#pod would not alter the requirements, they have no effect.
+#pod
+#pod If a finalized set of requirements is cloned, the cloned requirements are not
+#pod also finalized.
+#pod
+#pod =cut
+
+sub finalize { $_[0]{finalized} = 1 }
+
+#pod =method as_string_hash
+#pod
+#pod This returns a reference to a hash describing the requirements using the
+#pod strings in the L<CPAN::Meta::Spec> specification.
+#pod
+#pod For example after the following program:
+#pod
+#pod my $req = CPAN::Meta::Requirements->new;
+#pod
+#pod $req->add_minimum('CPAN::Meta::Requirements' => 0.102);
+#pod
+#pod $req->add_minimum('Library::Foo' => 1.208);
+#pod
+#pod $req->add_maximum('Library::Foo' => 2.602);
+#pod
+#pod $req->add_minimum('Module::Bar' => 'v1.2.3');
+#pod
+#pod $req->add_exclusion('Module::Bar' => 'v1.2.8');
+#pod
+#pod $req->exact_version('Xyzzy' => '6.01');
+#pod
+#pod my $hashref = $req->as_string_hash;
+#pod
+#pod C<$hashref> would contain:
+#pod
+#pod {
+#pod 'CPAN::Meta::Requirements' => '0.102',
+#pod 'Library::Foo' => '>= 1.208, <= 2.206',
+#pod 'Module::Bar' => '>= v1.2.3, != v1.2.8',
+#pod 'Xyzzy' => '== 6.01',
+#pod }
+#pod
+#pod =cut
+
+sub as_string_hash {
+ my ($self) = @_;
+
+ my %hash = map {; $_ => $self->{requirements}{$_}->as_string }
+ $self->required_modules;
+
+ return \%hash;
+}
+
+#pod =method add_string_requirement
+#pod
+#pod $req->add_string_requirement('Library::Foo' => '>= 1.208, <= 2.206');
+#pod $req->add_string_requirement('Library::Foo' => v1.208);
+#pod
+#pod This method parses the passed in string and adds the appropriate requirement
+#pod for the given module. A version can be a Perl "v-string". It understands
+#pod version ranges as described in the L<CPAN::Meta::Spec/Version Ranges>. For
+#pod example:
+#pod
+#pod =over 4
+#pod
+#pod =item 1.3
+#pod
+#pod =item >= 1.3
+#pod
+#pod =item <= 1.3
+#pod
+#pod =item == 1.3
+#pod
+#pod =item != 1.3
+#pod
+#pod =item > 1.3
+#pod
+#pod =item < 1.3
+#pod
+#pod =item >= 1.3, != 1.5, <= 2.0
+#pod
+#pod A version number without an operator is equivalent to specifying a minimum
+#pod (C<E<gt>=>). Extra whitespace is allowed.
+#pod
+#pod =back
+#pod
+#pod =cut
+
+my %methods_for_op = (
+ '==' => [ qw(exact_version) ],
+ '!=' => [ qw(add_exclusion) ],
+ '>=' => [ qw(add_minimum) ],
+ '<=' => [ qw(add_maximum) ],
+ '>' => [ qw(add_minimum add_exclusion) ],
+ '<' => [ qw(add_maximum add_exclusion) ],
+);
+
+sub add_string_requirement {
+ my ($self, $module, $req) = @_;
+
+ unless ( defined $req && length $req ) {
+ $req = 0;
+ $self->_blank_carp($module);
+ }
+
+ my $magic = _find_magic_vstring( $req );
+ if (length $magic) {
+ $self->add_minimum($module => $magic);
+ return;
+ }
+
+ my @parts = split qr{\s*,\s*}, $req;
+
+ for my $part (@parts) {
+ my ($op, $ver) = $part =~ m{\A\s*(==|>=|>|<=|<|!=)\s*(.*)\z};
+
+ if (! defined $op) {
+ $self->add_minimum($module => $part);
+ } else {
+ Carp::confess("illegal requirement string: $req")
+ unless my $methods = $methods_for_op{ $op };
+
+ $self->$_($module => $ver) for @$methods;
+ }
+ }
+}
+
+#pod =method from_string_hash
+#pod
+#pod my $req = CPAN::Meta::Requirements->from_string_hash( \%hash );
+#pod my $req = CPAN::Meta::Requirements->from_string_hash( \%hash, \%opts );
+#pod
+#pod This is an alternate constructor for a CPAN::Meta::Requirements
+#pod object. It takes a hash of module names and version requirement
+#pod strings and returns a new CPAN::Meta::Requirements object. As with
+#pod add_string_requirement, a version can be a Perl "v-string". Optionally,
+#pod you can supply a hash-reference of options, exactly as with the L</new>
+#pod method.
+#pod
+#pod =cut
+
+sub _blank_carp {
+ my ($self, $module) = @_;
+ Carp::carp("Undefined requirement for $module treated as '0'");
+}
+
+sub from_string_hash {
+ my ($class, $hash, $options) = @_;
+
+ my $self = $class->new($options);
+
+ for my $module (keys %$hash) {
+ my $req = $hash->{$module};
+ unless ( defined $req && length $req ) {
+ $req = 0;
+ $class->_blank_carp($module);
+ }
+ $self->add_string_requirement($module, $req);
+ }
+
+ return $self;
+}
+
+##############################################################
+
+{
+ package
+ CPAN::Meta::Requirements::_Range::Exact;
+ sub _new { bless { version => $_[1] } => $_[0] }
+
+ sub _accepts { return $_[0]{version} == $_[1] }
+
+ sub as_string { return "== $_[0]{version}" }
+
+ sub as_struct { return [ [ '==', "$_[0]{version}" ] ] }
+
+ sub as_modifiers { return [ [ exact_version => $_[0]{version} ] ] }
+
+ sub _reject_requirements {
+ my ($self, $module, $error) = @_;
+ Carp::confess("illegal requirements for $module: $error")
+ }
+
+ sub _clone {
+ (ref $_[0])->_new( version->new( $_[0]{version} ) )
+ }
+
+ sub with_exact_version {
+ my ($self, $version, $module) = @_;
+ $module = 'module' unless defined $module;
+
+ return $self->_clone if $self->_accepts($version);
+
+ $self->_reject_requirements(
+ $module,
+ "can't be exactly $version when exact requirement is already $self->{version}",
+ );
+ }
+
+ sub with_minimum {
+ my ($self, $minimum, $module) = @_;
+ $module = 'module' unless defined $module;
+
+ return $self->_clone if $self->{version} >= $minimum;
+ $self->_reject_requirements(
+ $module,
+ "minimum $minimum exceeds exact specification $self->{version}",
+ );
+ }
+
+ sub with_maximum {
+ my ($self, $maximum, $module) = @_;
+ $module = 'module' unless defined $module;
+
+ return $self->_clone if $self->{version} <= $maximum;
+ $self->_reject_requirements(
+ $module,
+ "maximum $maximum below exact specification $self->{version}",
+ );
+ }
+
+ sub with_exclusion {
+ my ($self, $exclusion, $module) = @_;
+ $module = 'module' unless defined $module;
+
+ return $self->_clone unless $exclusion == $self->{version};
+ $self->_reject_requirements(
+ $module,
+ "tried to exclude $exclusion, which is already exactly specified",
+ );
+ }
+}
+
+##############################################################
+
+{
+ package
+ CPAN::Meta::Requirements::_Range::Range;
+
+ sub _self { ref($_[0]) ? $_[0] : (bless { } => $_[0]) }
+
+ sub _clone {
+ return (bless { } => $_[0]) unless ref $_[0];
+
+ my ($s) = @_;
+ my %guts = (
+ (exists $s->{minimum} ? (minimum => version->new($s->{minimum})) : ()),
+ (exists $s->{maximum} ? (maximum => version->new($s->{maximum})) : ()),
+
+ (exists $s->{exclusions}
+ ? (exclusions => [ map { version->new($_) } @{ $s->{exclusions} } ])
+ : ()),
+ );
+
+ bless \%guts => ref($s);
+ }
+
+ sub as_modifiers {
+ my ($self) = @_;
+ my @mods;
+ push @mods, [ add_minimum => $self->{minimum} ] if exists $self->{minimum};
+ push @mods, [ add_maximum => $self->{maximum} ] if exists $self->{maximum};
+ push @mods, map {; [ add_exclusion => $_ ] } @{$self->{exclusions} || []};
+ return \@mods;
+ }
+
+ sub as_struct {
+ my ($self) = @_;
+
+ return 0 if ! keys %$self;
+
+ my @exclusions = @{ $self->{exclusions} || [] };
+
+ my @parts;
+
+ for my $tuple (
+ [ qw( >= > minimum ) ],
+ [ qw( <= < maximum ) ],
+ ) {
+ my ($op, $e_op, $k) = @$tuple;
+ if (exists $self->{$k}) {
+ my @new_exclusions = grep { $_ != $self->{ $k } } @exclusions;
+ if (@new_exclusions == @exclusions) {
+ push @parts, [ $op, "$self->{ $k }" ];
+ } else {
+ push @parts, [ $e_op, "$self->{ $k }" ];
+ @exclusions = @new_exclusions;
+ }
+ }
+ }
+
+ push @parts, map {; [ "!=", "$_" ] } @exclusions;
+
+ return \@parts;
+ }
+
+ sub as_string {
+ my ($self) = @_;
+
+ my @parts = @{ $self->as_struct };
+
+ return $parts[0][1] if @parts == 1 and $parts[0][0] eq '>=';
+
+ return join q{, }, map {; join q{ }, @$_ } @parts;
+ }
+
+ sub _reject_requirements {
+ my ($self, $module, $error) = @_;
+ Carp::confess("illegal requirements for $module: $error")
+ }
+
+ sub with_exact_version {
+ my ($self, $version, $module) = @_;
+ $module = 'module' unless defined $module;
+ $self = $self->_clone;
+
+ unless ($self->_accepts($version)) {
+ $self->_reject_requirements(
+ $module,
+ "exact specification $version outside of range " . $self->as_string
+ );
+ }
+
+ return CPAN::Meta::Requirements::_Range::Exact->_new($version);
+ }
+
+ sub _simplify {
+ my ($self, $module) = @_;
+
+ if (defined $self->{minimum} and defined $self->{maximum}) {
+ if ($self->{minimum} == $self->{maximum}) {
+ if (grep { $_ == $self->{minimum} } @{ $self->{exclusions} || [] }) {
+ $self->_reject_requirements(
+ $module,
+ "minimum and maximum are both $self->{minimum}, which is excluded",
+ );
+ }
+
+ return CPAN::Meta::Requirements::_Range::Exact->_new($self->{minimum})
+ }
+
+ if ($self->{minimum} > $self->{maximum}) {
+ $self->_reject_requirements(
+ $module,
+ "minimum $self->{minimum} exceeds maximum $self->{maximum}",
+ );
+ }
+ }
+
+ # eliminate irrelevant exclusions
+ if ($self->{exclusions}) {
+ my %seen;
+ @{ $self->{exclusions} } = grep {
+ (! defined $self->{minimum} or $_ >= $self->{minimum})
+ and
+ (! defined $self->{maximum} or $_ <= $self->{maximum})
+ and
+ ! $seen{$_}++
+ } @{ $self->{exclusions} };
+ }
+
+ return $self;
+ }
+
+ sub with_minimum {
+ my ($self, $minimum, $module) = @_;
+ $module = 'module' unless defined $module;
+ $self = $self->_clone;
+
+ if (defined (my $old_min = $self->{minimum})) {
+ $self->{minimum} = (sort { $b cmp $a } ($minimum, $old_min))[0];
+ } else {
+ $self->{minimum} = $minimum;
+ }
+
+ return $self->_simplify($module);
+ }
+
+ sub with_maximum {
+ my ($self, $maximum, $module) = @_;
+ $module = 'module' unless defined $module;
+ $self = $self->_clone;
+
+ if (defined (my $old_max = $self->{maximum})) {
+ $self->{maximum} = (sort { $a cmp $b } ($maximum, $old_max))[0];
+ } else {
+ $self->{maximum} = $maximum;
+ }
+
+ return $self->_simplify($module);
+ }
+
+ sub with_exclusion {
+ my ($self, $exclusion, $module) = @_;
+ $module = 'module' unless defined $module;
+ $self = $self->_clone;
+
+ push @{ $self->{exclusions} ||= [] }, $exclusion;
+
+ return $self->_simplify($module);
+ }
+
+ sub _accepts {
+ my ($self, $version) = @_;
+
+ return if defined $self->{minimum} and $version < $self->{minimum};
+ return if defined $self->{maximum} and $version > $self->{maximum};
+ return if defined $self->{exclusions}
+ and grep { $version == $_ } @{ $self->{exclusions} };
+
+ return 1;
+ }
+}
+
+1;
+# vim: ts=2 sts=2 sw=2 et:
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+CPAN::Meta::Requirements - a set of version requirements for a CPAN dist
+
+=head1 VERSION
+
+version 2.140
+
+=head1 SYNOPSIS
+
+ use CPAN::Meta::Requirements;
+
+ my $build_requires = CPAN::Meta::Requirements->new;
+
+ $build_requires->add_minimum('Library::Foo' => 1.208);
+
+ $build_requires->add_minimum('Library::Foo' => 2.602);
+
+ $build_requires->add_minimum('Module::Bar' => 'v1.2.3');
+
+ $METAyml->{build_requires} = $build_requires->as_string_hash;
+
+=head1 DESCRIPTION
+
+A CPAN::Meta::Requirements object models a set of version constraints like
+those specified in the F<META.yml> or F<META.json> files in CPAN distributions,
+and as defined by L<CPAN::Meta::Spec>;
+It can be built up by adding more and more constraints, and it will reduce them
+to the simplest representation.
+
+Logically impossible constraints will be identified immediately by thrown
+exceptions.
+
+=head1 METHODS
+
+=head2 new
+
+ my $req = CPAN::Meta::Requirements->new;
+
+This returns a new CPAN::Meta::Requirements object. It takes an optional
+hash reference argument. Currently, only one key is supported:
+
+=over 4
+
+=item *
+
+C<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.
+
+=back
+
+All other keys are ignored.
+
+=head2 add_minimum
+
+ $req->add_minimum( $module => $version );
+
+This adds a new minimum version requirement. If the new requirement is
+redundant to the existing specification, this has no effect.
+
+Minimum requirements are inclusive. C<$version> is required, along with any
+greater version number.
+
+This method returns the requirements object.
+
+=head2 add_maximum
+
+ $req->add_maximum( $module => $version );
+
+This adds a new maximum version requirement. If the new requirement is
+redundant to the existing specification, this has no effect.
+
+Maximum requirements are inclusive. No version strictly greater than the given
+version is allowed.
+
+This method returns the requirements object.
+
+=head2 add_exclusion
+
+ $req->add_exclusion( $module => $version );
+
+This adds a new excluded version. For example, you might use these three
+method calls:
+
+ $req->add_minimum( $module => '1.00' );
+ $req->add_maximum( $module => '1.82' );
+
+ $req->add_exclusion( $module => '1.75' );
+
+Any version between 1.00 and 1.82 inclusive would be acceptable, except for
+1.75.
+
+This method returns the requirements object.
+
+=head2 exact_version
+
+ $req->exact_version( $module => $version );
+
+This sets the version required for the given module to I<exactly> the given
+version. No other version would be considered acceptable.
+
+This method returns the requirements object.
+
+=head2 add_requirements
+
+ $req->add_requirements( $another_req_object );
+
+This method adds all the requirements in the given CPAN::Meta::Requirements
+object to the requirements object on which it was called. If there are any
+conflicts, an exception is thrown.
+
+This method returns the requirements object.
+
+=head2 accepts_module
+
+ my $bool = $req->accepts_module($module => $version);
+
+Given an module and version, this method returns true if the version
+specification for the module accepts the provided version. In other words,
+given:
+
+ Module => '>= 1.00, < 2.00'
+
+We will accept 1.00 and 1.75 but not 0.50 or 2.00.
+
+For modules that do not appear in the requirements, this method will return
+true.
+
+=head2 clear_requirement
+
+ $req->clear_requirement( $module );
+
+This removes the requirement for a given module from the object.
+
+This method returns the requirements object.
+
+=head2 requirements_for_module
+
+ $req->requirements_for_module( $module );
+
+This returns a string containing the version requirements for a given module in
+the format described in L<CPAN::Meta::Spec> or undef if the given module has no
+requirements. This should only be used for informational purposes such as error
+messages and should not be interpreted or used for comparison (see
+L</accepts_module> instead).
+
+=head2 structured_requirements_for_module
+
+ $req->structured_requirements_for_module( $module );
+
+This returns a data structure containing the version requirements for a given
+module or undef if the given module has no requirements. This should
+not be used for version checks (see L</accepts_module> instead).
+
+Added in version 2.134.
+
+=head2 required_modules
+
+This method returns a list of all the modules for which requirements have been
+specified.
+
+=head2 clone
+
+ $req->clone;
+
+This method returns a clone of the invocant. The clone and the original object
+can then be changed independent of one another.
+
+=head2 is_simple
+
+This method returns true if and only if all requirements are inclusive minimums
+-- that is, if their string expression is just the version number.
+
+=head2 is_finalized
+
+This method returns true if the requirements have been finalized by having the
+C<finalize> method called on them.
+
+=head2 finalize
+
+This method marks the requirements finalized. Subsequent attempts to change
+the requirements will be fatal, I<if> they would result in a change. If they
+would not alter the requirements, they have no effect.
+
+If a finalized set of requirements is cloned, the cloned requirements are not
+also finalized.
+
+=head2 as_string_hash
+
+This returns a reference to a hash describing the requirements using the
+strings in the L<CPAN::Meta::Spec> specification.
+
+For example after the following program:
+
+ my $req = CPAN::Meta::Requirements->new;
+
+ $req->add_minimum('CPAN::Meta::Requirements' => 0.102);
+
+ $req->add_minimum('Library::Foo' => 1.208);
+
+ $req->add_maximum('Library::Foo' => 2.602);
+
+ $req->add_minimum('Module::Bar' => 'v1.2.3');
+
+ $req->add_exclusion('Module::Bar' => 'v1.2.8');
+
+ $req->exact_version('Xyzzy' => '6.01');
+
+ my $hashref = $req->as_string_hash;
+
+C<$hashref> would contain:
+
+ {
+ 'CPAN::Meta::Requirements' => '0.102',
+ 'Library::Foo' => '>= 1.208, <= 2.206',
+ 'Module::Bar' => '>= v1.2.3, != v1.2.8',
+ 'Xyzzy' => '== 6.01',
+ }
+
+=head2 add_string_requirement
+
+ $req->add_string_requirement('Library::Foo' => '>= 1.208, <= 2.206');
+ $req->add_string_requirement('Library::Foo' => v1.208);
+
+This method parses the passed in string and adds the appropriate requirement
+for the given module. A version can be a Perl "v-string". It understands
+version ranges as described in the L<CPAN::Meta::Spec/Version Ranges>. For
+example:
+
+=over 4
+
+=item 1.3
+
+=item >= 1.3
+
+=item <= 1.3
+
+=item == 1.3
+
+=item != 1.3
+
+=item > 1.3
+
+=item < 1.3
+
+=item >= 1.3, != 1.5, <= 2.0
+
+A version number without an operator is equivalent to specifying a minimum
+(C<E<gt>=>). Extra whitespace is allowed.
+
+=back
+
+=head2 from_string_hash
+
+ my $req = CPAN::Meta::Requirements->from_string_hash( \%hash );
+ my $req = CPAN::Meta::Requirements->from_string_hash( \%hash, \%opts );
+
+This is an alternate constructor for a CPAN::Meta::Requirements
+object. It takes a hash of module names and version requirement
+strings and returns a new CPAN::Meta::Requirements object. As with
+add_string_requirement, a version can be a Perl "v-string". Optionally,
+you can supply a hash-reference of options, exactly as with the L</new>
+method.
+
+=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
+
+=head1 SUPPORT
+
+=head2 Bugs / Feature Requests
+
+Please report any bugs or feature requests through the issue tracker
+at L<https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements/issues>.
+You will be notified automatically of any progress on your issue.
+
+=head2 Source Code
+
+This is open source software. The code repository is available for
+public review and contribution under the terms of the license.
+
+L<https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements>
+
+ git clone https://github.com/Perl-Toolchain-Gang/CPAN-Meta-Requirements.git
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=back
+
+=head1 CONTRIBUTORS
+
+=for stopwords Ed J Karen Etheridge Leon Timmermans robario
+
+=over 4
+
+=item *
+
+Ed J <mohawk2@users.noreply.github.com>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Leon Timmermans <fawaka@gmail.com>
+
+=item *
+
+robario <webmaster@robario.com>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2010 by David Golden and Ricardo Signes.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut