summaryrefslogtreecommitdiff
path: root/cpan
diff options
context:
space:
mode:
authorDavid Golden <dagolden@cpan.org>2011-02-15 22:35:53 -0500
committerDavid Golden <dagolden@cpan.org>2011-02-15 22:50:32 -0500
commitc05760c68edc298aadab73da2781ba0fe1cf24b6 (patch)
tree8fc3142573184b24aadc4c3dea70f1afd6d67f64 /cpan
parent279627b48dfab08c484fbbb6c05d3964fa9529d2 (diff)
downloadperl-c05760c68edc298aadab73da2781ba0fe1cf24b6.tar.gz
Add CPAN::Meta as a dual-life module
CPAN::Meta version 2.110440 has been added as a dual-life module. It provides a standard library to read, interpret and write CPAN distribution metadata files (e.g. META.json and META.yml) which describes a distribution, its contents, and the requirements for building it and installing it. The latest CPAN distribution metadata specification is included as CPAN::Meta::Spec and notes on changes in the specification over time are given in CPAN::Meta::History. CPAN::Meta is required for CPAN.pm and CPANPLUS to read META.json and MYMETA.json files and is required by Module::Build and ExtUtils::MakeMaker to generate META.json and MYMETA.json files
Diffstat (limited to 'cpan')
-rw-r--r--cpan/CPAN-Meta/Changes178
-rw-r--r--cpan/CPAN-Meta/lib/CPAN/Meta.pm696
-rw-r--r--cpan/CPAN-Meta/lib/CPAN/Meta/Converter.pm1365
-rw-r--r--cpan/CPAN-Meta/lib/CPAN/Meta/Feature.pm116
-rw-r--r--cpan/CPAN-Meta/lib/CPAN/Meta/History.pm315
-rw-r--r--cpan/CPAN-Meta/lib/CPAN/Meta/Prereqs.pm277
-rw-r--r--cpan/CPAN-Meta/lib/CPAN/Meta/Spec.pm1145
-rw-r--r--cpan/CPAN-Meta/lib/CPAN/Meta/Validator.pm1002
-rw-r--r--cpan/CPAN-Meta/t/converter-bad.t71
-rw-r--r--cpan/CPAN-Meta/t/converter-fail.t39
-rw-r--r--cpan/CPAN-Meta/t/converter.t139
-rw-r--r--cpan/CPAN-Meta/t/data-bad/107650337-META.yml25
-rw-r--r--cpan/CPAN-Meta/t/data-bad/1122575719-META.yml28
-rw-r--r--cpan/CPAN-Meta/t/data-bad/1206545041-META.yml105
-rw-r--r--cpan/CPAN-Meta/t/data-bad/1598804075-META.yml19
-rw-r--r--cpan/CPAN-Meta/t/data-bad/1927486199-META.yml13
-rw-r--r--cpan/CPAN-Meta/t/data-bad/1985684504-META.yml21
-rw-r--r--cpan/CPAN-Meta/t/data-bad/1985980974-META.yml20
-rw-r--r--cpan/CPAN-Meta/t/data-bad/2031017050-META.yml29
-rw-r--r--cpan/CPAN-Meta/t/data-bad/284247103-META.yml63
-rw-r--r--cpan/CPAN-Meta/t/data-bad/344981821-META.yml26
-rw-r--r--cpan/CPAN-Meta/t/data-bad/35478989-META.yml17
-rw-r--r--cpan/CPAN-Meta/t/data-bad/476602558-META.yml28
-rw-r--r--cpan/CPAN-Meta/t/data-bad/98042513-META.yml16
-rw-r--r--cpan/CPAN-Meta/t/data-bad/META-1_0.yml4
-rw-r--r--cpan/CPAN-Meta/t/data-bad/META-1_1.yml6
-rw-r--r--cpan/CPAN-Meta/t/data-bad/META-1_2.yml34
-rw-r--r--cpan/CPAN-Meta/t/data-bad/META-1_3.yml28
-rw-r--r--cpan/CPAN-Meta/t/data-bad/META-1_4.yml128
-rw-r--r--cpan/CPAN-Meta/t/data-bad/META-2.json76
-rw-r--r--cpan/CPAN-Meta/t/data-bad/restrictive-2.json89
-rw-r--r--cpan/CPAN-Meta/t/data-fail/META-1_0.yml11
-rw-r--r--cpan/CPAN-Meta/t/data-fail/META-1_1.yml15
-rw-r--r--cpan/CPAN-Meta/t/data-fail/META-1_2.yml34
-rw-r--r--cpan/CPAN-Meta/t/data-fail/META-1_3.yml28
-rw-r--r--cpan/CPAN-Meta/t/data-fail/META-1_4.yml129
-rw-r--r--cpan/CPAN-Meta/t/data-fail/META-2.json76
-rw-r--r--cpan/CPAN-Meta/t/data/META-1_0.yml12
-rw-r--r--cpan/CPAN-Meta/t/data/META-1_1.yml16
-rw-r--r--cpan/CPAN-Meta/t/data/META-1_2.yml35
-rw-r--r--cpan/CPAN-Meta/t/data/META-1_3.yml29
-rw-r--r--cpan/CPAN-Meta/t/data/META-1_4.yml132
-rw-r--r--cpan/CPAN-Meta/t/data/META-2.json89
-rw-r--r--cpan/CPAN-Meta/t/data/resources.yml49
-rw-r--r--cpan/CPAN-Meta/t/data/restricted-2.json89
-rw-r--r--cpan/CPAN-Meta/t/data/restrictive-1_4.yml132
-rw-r--r--cpan/CPAN-Meta/t/load-bad.t25
-rw-r--r--cpan/CPAN-Meta/t/meta-obj.t240
-rw-r--r--cpan/CPAN-Meta/t/no-index.t86
-rw-r--r--cpan/CPAN-Meta/t/prereqs-finalize.t91
-rw-r--r--cpan/CPAN-Meta/t/prereqs-merge.t104
-rw-r--r--cpan/CPAN-Meta/t/prereqs.t121
-rw-r--r--cpan/CPAN-Meta/t/repository.t225
-rw-r--r--cpan/CPAN-Meta/t/save-load.t99
-rw-r--r--cpan/CPAN-Meta/t/validator.t35
55 files changed, 8020 insertions, 0 deletions
diff --git a/cpan/CPAN-Meta/Changes b/cpan/CPAN-Meta/Changes
new file mode 100644
index 0000000000..7dabb947e2
--- /dev/null
+++ b/cpan/CPAN-Meta/Changes
@@ -0,0 +1,178 @@
+Revision history for CPAN-Meta
+
+2.110440 2011-02-12 22:55:28 EST5EDT
+
+ [BUGFIX]
+
+ - Bump Parse::CPAN::Meta prereq to 1.44, as 1.43 was never released
+
+2.110420 2011-02-11 15:40:36 EST5EDT
+
+ [BUG FIXES]
+
+ - The as_string() method now always returns a character string;
+ previously, JSON strings were UTF-8 encoded.
+
+ - The save() method now always saves with UTF-8 encoding for
+ Perl 5.8.1 or greater; previously, YAML was not encoded
+
+2.110390 2011-02-07 21:00:47 EST5EDT
+
+ [BUG FIXES]
+
+ - Release 2.110360 had a regression where the save() method would no
+ longer return true on success. That has been fixed.
+
+2.110360 2011-02-04 19:46:21 America/New_York
+
+ [OTHER]
+
+ - Remove autodie dependency so CPAN::Meta can be used on older Perls
+
+ - Remove unused Data::Dumper dependency
+
+2.110350 2011-02-03 19:57:32 America/New_York
+
+ [ENHANCEMENTS]
+
+ - Added "as_string" method similar to "as_struct"
+
+ [OTHER]
+
+ - Bumped Parse::CPAN::Meta prereq to 1.43 and uses that to
+ determine proper YAML/JSON backends
+
+ - Removed unused prereqs
+
+2.110330 2011-02-02 09:42:57 EST5EDT
+
+ [ENHANCEMENTS]
+
+ - Saved META.json files are now sorted by key
+
+ - as_struct() method takes an optional "version" argument to return
+ a down-converted metadata hashref
+
+2.110320 2011-01-31 23:14:30 EST5EDT
+
+ [ENHANCEMENTS]
+
+ - The 'save' method now allows an optional hashref argument, which can be
+ used to set the desired meta spec version. Metadata is automatically
+ converted to the specified output.
+
+2.110240 2011-01-24 16:28:25 EST5EDT
+
+ - Reading JSON/YAML is delegated entirely to Parse::CPAN::Meta (1.4200)
+
+ - JSON.pm is dropped as a prerequisite and JSON::PP is added to prepare
+ for CPAN::Meta to be added to the Perl core
+
+ - JSON writing uses the same JSON backend selection as Parse::CPAN::Meta
+ to allow "upgrading" to a non-core JSON backend module if desired
+
+2.102400 2010-08-28 14:06:34 America/New_York
+
+ - 'as_struct' method now returns unblessed data (reported by Chris Prather)
+
+2.102160 2010-08-04 12:27:10 EST5EDT
+
+ - Fix bugtracker conversion bug (RT#60017)
+
+2.101670 2010-06-15 21:02:42 EST5EDT
+
+ - converting 1.x 'repository' field now puts converted url into the
+ 'url' sub-field of 'repository' instead of the 'web' sub-field
+
+2.101610 2010-06-10 18:51:30 EST5EDT
+
+ - fixed converter bug that output 'artistic2' instead of 'artistic_2'
+ for license in 1.X specs
+
+ - 'artistic2' is now converted to 'artistic_2' if it occurs
+
+ - corrected validation for 'artistic_2' and disallowed 'artistic-2.0'
+
+2.101600 2010-06-09 10:07:31 EST5EDT
+
+ - improve conversion of restricted/restrictive license keys between
+ spec versions 1.4 and 2 [reported by Alexander Hartmaier]
+
+2.101591 2010-06-08 09:56:17 EST5EDT
+
+ - added 'as_struct' method to CPAN::Meta to get a deep copy of
+ the metadata hash_ref
+
+ - won't add an optional_features 'description' field if missing
+
+ - improved documentation of CPAN::Meta::Converter and how it deals
+ with bad/missing data
+
+2.101590 2010-06-07 21:49:36 EST5EDT
+
+ - won't automatically add 'unknown' as repository type when converting;
+ instead, will only add a repository type if a repository 'url' is
+ present and it is of the 'svn:' or 'git:' scheme.
+
+ - squelched some uninitialized value warnings [Graham Barr]
+
+2.101580 2010-06-07 16:44:13 EST5EDT
+
+ - add "lazy_validation" option to constructors
+
+ - add ability to "convert" to same version and clean-up any fixable
+ errors
+
+ - fix validation bugs (adhere closer to the spec)
+
+ - improve lots of heuristics during conversion
+
+2.101461 2010-05-26 16:57:02 America/New_York
+
+ - accessors deep clone list and map keys before returning them
+
+ - add custom_keys() and custom() methods
+
+2.101460 2010-05-25 23:12:27 America/New_York
+
+ - loosen URL validation -- only a scheme and authority are required
+ without restrictions on either
+
+2.101450 2010-05-25 17:59:32 America/New_York
+
+ - when downconverting from 2, leave custom keys unchanged
+ (except in resources, where x_ is changed to X_)
+
+ - when converting to 2, don't prepend x_ to custom keys that already
+ matched qr{\Ax_}i
+
+2.101410 2010-05-21 10:39:18 EST5EDT
+
+ - when downconverting from 2, merge test requirements into build requirements
+
+2.101390 2010-05-19 10:49:50 EST5EDT
+
+ - do not clobber generated_by when converting
+
+2.101380 2010-05-17 23:39:23 EST5EDT
+
+ - added support for down-converting to older versions of the spec
+
+ - improved test coverage for conversion and validation
+
+2.101110 2010-04-21 11:06:52 EST5EDT
+
+ - clarified that .XXXXXX versions of the CPAN-Meta distribution will not
+ change the meaning of the CPAN::Meta::Spec, but may fix typos or
+ clarify prose
+
+ - fixed a typo regarding dotted-integer versions: keeping components
+ in the range 0-999 was corrected to a "should" instead of a "must"
+
+ - fixed validation bugs for certain types of nested data structures
+ (based on a patch provided by Barbie)
+
+2.101091 2010-04-19 06:32:13 EST5EDT
+
+ - keep the old specs from getting indexed so as not to confuse people
+
diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta.pm b/cpan/CPAN-Meta/lib/CPAN/Meta.pm
new file mode 100644
index 0000000000..ef798559fb
--- /dev/null
+++ b/cpan/CPAN-Meta/lib/CPAN/Meta.pm
@@ -0,0 +1,696 @@
+use 5.006;
+use strict;
+use warnings;
+package CPAN::Meta;
+BEGIN {
+ $CPAN::Meta::VERSION = '2.110440';
+}
+# ABSTRACT: the distribution metadata for a CPAN dist
+
+
+use Carp qw(carp croak);
+use CPAN::Meta::Feature;
+use CPAN::Meta::Prereqs;
+use CPAN::Meta::Converter;
+use CPAN::Meta::Validator;
+use Parse::CPAN::Meta 1.44 ();
+
+
+BEGIN {
+ my @STRING_READERS = qw(
+ abstract
+ description
+ dynamic_config
+ generated_by
+ name
+ release_status
+ version
+ );
+
+ no strict 'refs';
+ for my $attr (@STRING_READERS) {
+ *$attr = sub { $_[0]{ $attr } };
+ }
+}
+
+
+BEGIN {
+ my @LIST_READERS = qw(
+ author
+ keywords
+ license
+ );
+
+ no strict 'refs';
+ for my $attr (@LIST_READERS) {
+ *$attr = sub {
+ my $value = $_[0]{ $attr };
+ croak "$attr must be called in list context"
+ unless wantarray;
+ return @{ Storable::dclone($value) } if ref $value;
+ return $value;
+ };
+ }
+}
+
+sub authors { $_[0]->author }
+sub licenses { $_[0]->license }
+
+
+BEGIN {
+ my @MAP_READERS = qw(
+ meta-spec
+ resources
+ provides
+ no_index
+
+ prereqs
+ optional_features
+ );
+
+ no strict 'refs';
+ for my $attr (@MAP_READERS) {
+ (my $subname = $attr) =~ s/-/_/;
+ *$subname = sub {
+ my $value = $_[0]{ $attr };
+ return Storable::dclone($value) if $value;
+ return {};
+ };
+ }
+}
+
+
+sub custom_keys {
+ return grep { /^x_/i } keys %{$_[0]};
+}
+
+sub custom {
+ my ($self, $attr) = @_;
+ my $value = $self->{$attr};
+ return Storable::dclone($value) if ref $value;
+ return $value;
+}
+
+
+sub _new {
+ my ($class, $struct, $options) = @_;
+ my $self;
+
+ if ( $options->{lazy_validation} ) {
+ # try to convert to a valid structure; if succeeds, then return it
+ my $cmc = CPAN::Meta::Converter->new( $struct );
+ $self = $cmc->convert( version => 2 ); # valid or dies
+ return bless $self, $class;
+ }
+ else {
+ # validate original struct
+ my $cmv = CPAN::Meta::Validator->new( $struct );
+ unless ( $cmv->is_valid) {
+ die "Invalid metadata structure. Errors: "
+ . join(", ", $cmv->errors) . "\n";
+ }
+ }
+
+ # up-convert older spec versions
+ my $version = $struct->{'meta-spec'}{version} || '1.0';
+ if ( $version == 2 ) {
+ $self = $struct;
+ }
+ else {
+ my $cmc = CPAN::Meta::Converter->new( $struct );
+ $self = $cmc->convert( version => 2 );
+ }
+
+ return bless $self, $class;
+}
+
+sub new {
+ my ($class, $struct, $options) = @_;
+ my $self = eval { $class->_new($struct, $options) };
+ croak($@) if $@;
+ return $self;
+}
+
+
+sub create {
+ my ($class, $struct, $options) = @_;
+ my $version = __PACKAGE__->VERSION || 2;
+ $struct->{generated_by} ||= __PACKAGE__ . " version $version" ;
+ $struct->{'meta-spec'}{version} ||= int($version);
+ my $self = eval { $class->_new($struct, $options) };
+ croak ($@) if $@;
+ return $self;
+}
+
+
+sub load_file {
+ my ($class, $file, $options) = @_;
+ $options->{lazy_validation} = 1 unless exists $options->{lazy_validation};
+
+ croak "load_file() requires a valid, readable filename"
+ unless -r $file;
+
+ my $self;
+ eval {
+ my $struct = Parse::CPAN::Meta->load_file( $file );
+ $self = $class->_new($struct, $options);
+ };
+ croak($@) if $@;
+ return $self;
+}
+
+
+sub load_yaml_string {
+ my ($class, $yaml, $options) = @_;
+ $options->{lazy_validation} = 1 unless exists $options->{lazy_validation};
+
+ my $self;
+ eval {
+ my ($struct) = Parse::CPAN::Meta->load_yaml_string( $yaml );
+ $self = $class->_new($struct, $options);
+ };
+ croak($@) if $@;
+ return $self;
+}
+
+
+sub load_json_string {
+ my ($class, $json, $options) = @_;
+ $options->{lazy_validation} = 1 unless exists $options->{lazy_validation};
+
+ my $self;
+ eval {
+ my $struct = Parse::CPAN::Meta->load_json_string( $json );
+ $self = $class->_new($struct, $options);
+ };
+ croak($@) if $@;
+ return $self;
+}
+
+
+sub save {
+ my ($self, $file, $options) = @_;
+
+ my $version = $options->{version} || '2';
+ my $layer = $] ge '5.008001' ? ':utf8' : '';
+
+ if ( $version ge '2' ) {
+ carp "'$file' should end in '.json'"
+ unless $file =~ m{\.json$};
+ }
+ else {
+ carp "'$file' should end in '.yml'"
+ unless $file =~ m{\.yml$};
+ }
+
+ my $data = $self->as_string( $options );
+ open my $fh, ">$layer", $file
+ or die "Error opening '$file' for writing: $!\n";
+
+ print {$fh} $data;
+ close $fh
+ or die "Error closing '$file': $!\n";
+
+ return 1;
+}
+
+
+# XXX Do we need this if we always upconvert? -- dagolden, 2010-04-14
+sub meta_spec_version {
+ my ($self) = @_;
+ return $self->meta_spec->{version};
+}
+
+
+sub effective_prereqs {
+ my ($self, $features) = @_;
+ $features ||= [];
+
+ my $prereq = CPAN::Meta::Prereqs->new($self->prereqs);
+
+ return $prereq unless @$features;
+
+ my @other = map {; $self->feature($_)->prereqs } @$features;
+
+ return $prereq->with_merged_prereqs(\@other);
+}
+
+
+sub should_index_file {
+ my ($self, $filename) = @_;
+
+ for my $no_index_file (@{ $self->no_index->{file} || [] }) {
+ return if $filename eq $no_index_file;
+ }
+
+ for my $no_index_dir (@{ $self->no_index->{directory} }) {
+ $no_index_dir =~ s{$}{/} unless $no_index_dir =~ m{/\z};
+ return if index($filename, $no_index_dir) == 0;
+ }
+
+ return 1;
+}
+
+
+sub should_index_package {
+ my ($self, $package) = @_;
+
+ for my $no_index_pkg (@{ $self->no_index->{package} || [] }) {
+ return if $package eq $no_index_pkg;
+ }
+
+ for my $no_index_ns (@{ $self->no_index->{namespace} }) {
+ return if index($package, "${no_index_ns}::") == 0;
+ }
+
+ return 1;
+}
+
+
+sub features {
+ my ($self) = @_;
+
+ my $opt_f = $self->optional_features;
+ my @features = map {; CPAN::Meta::Feature->new($_ => $opt_f->{ $_ }) }
+ keys %$opt_f;
+
+ return @features;
+}
+
+
+sub feature {
+ my ($self, $ident) = @_;
+
+ croak "no feature named $ident"
+ unless my $f = $self->optional_features->{ $ident };
+
+ return CPAN::Meta::Feature->new($ident, $f);
+}
+
+
+sub as_struct {
+ my ($self, $options) = @_;
+ my $backend = Parse::CPAN::Meta->json_backend();
+ my $struct = $backend->new->decode(
+ $backend->new->convert_blessed->encode($self)
+ );
+ if ( $options->{version} ) {
+ my $cmc = CPAN::Meta::Converter->new( $struct );
+ $struct = $cmc->convert( version => $options->{version} );
+ }
+ return $struct;
+}
+
+
+sub as_string {
+ my ($self, $options) = @_;
+
+ my $version = $options->{version} || '2';
+
+ my $struct;
+ if ( $self->version ne $version ) {
+ my $cmc = CPAN::Meta::Converter->new( $self->as_struct );
+ $struct = $cmc->convert( version => $version );
+ }
+ else {
+ $struct = $self->as_struct;
+ }
+
+ my ($data, $backend);
+ if ( $version ge '2' ) {
+ $backend = Parse::CPAN::Meta->json_backend();
+ $data = $backend->new->pretty->canonical->encode($struct);
+ }
+ else {
+ $backend = Parse::CPAN::Meta->yaml_backend();
+ $data = eval { no strict 'refs'; &{"$backend\::Dump"}($struct) };
+ if ( $@ ) {
+ croak $backend->can('errstr') ? $backend->errstr : $@
+ }
+ }
+
+ return $data;
+}
+
+# Used by JSON::PP, etc. for "convert_blessed"
+sub TO_JSON {
+ return { %{ $_[0] } };
+}
+
+1;
+
+
+
+=pod
+
+=head1 NAME
+
+CPAN::Meta - the distribution metadata for a CPAN dist
+
+=head1 VERSION
+
+version 2.110440
+
+=head1 SYNOPSIS
+
+ my $meta = CPAN::Meta->load_file('META.json');
+
+ printf "testing requirements for %s version %s\n",
+ $meta->name,
+ $meta->version;
+
+ my $prereqs = $meta->requirements_for('configure');
+
+ for my $module ($prereqs->required_modules) {
+ my $version = get_local_version($module);
+
+ die "missing required module $module" unless defined $version;
+ die "version for $module not in range"
+ unless $prereqs->accepts_module($module, $version);
+ }
+
+=head1 DESCRIPTION
+
+Software distributions released to the CPAN include a F<META.json> or, for
+older distributions, F<META.yml>, which describes the distribution, its
+contents, and the requirements for building and installing the distribution.
+The data structure stored in the F<META.json> file is described in
+L<CPAN::Meta::Spec>.
+
+CPAN::Meta provides a simple class to represent this distribution metadata (or
+I<distmeta>), along with some helpful methods for interrogating that data.
+
+The documentation below is only for the methods of the CPAN::Meta object. For
+information on the meaning of individual fields, consult the spec.
+
+=head1 METHODS
+
+=head2 new
+
+ my $meta = CPAN::Meta->new($distmeta_struct, \%options);
+
+Returns a valid CPAN::Meta object or dies if the supplied metadata hash
+reference fails to validate. Older-format metadata will be up-converted to
+version 2 if they validate against the original stated specification.
+
+It takes an optional hashref of options. Valid options include:
+
+=over
+
+=item *
+
+lazy_validation -- if true, new will attempt to convert the given metadata
+to version 2 before attempting to validate it. This means than any
+fixable errors will be handled by CPAN::Meta::Converter before validation.
+(Note that this might result in invalid optional data being silently
+dropped.) The default is false.
+
+=back
+
+=head2 create
+
+ my $meta = CPAN::Meta->create($distmeta_struct, \%options);
+
+This is same as C<new()>, except that C<generated_by> and C<meta-spec> fields
+will be generated if not provided. This means the metadata structure is
+assumed to otherwise follow the latest L<CPAN::Meta::Spec>.
+
+=head2 load_file
+
+ my $meta = CPAN::Meta->load_file($distmeta_file, \%options);
+
+Given a pathname to a file containing metadata, this deserializes the file
+according to its file suffix and constructs a new C<CPAN::Meta> object, just
+like C<new()>. It will die if the deserialized version fails to validate
+against its stated specification version.
+
+It takes the same options as C<new()> but C<lazy_validation> defaults to
+true.
+
+=head2 load_yaml_string
+
+ my $meta = CPAN::Meta->load_yaml_string($yaml, \%options);
+
+This method returns a new CPAN::Meta object using the first document in the
+given YAML string. In other respects it is identical to C<load_file()>.
+
+=head2 load_json_string
+
+ my $meta = CPAN::Meta->load_json_string($json, \%options);
+
+This method returns a new CPAN::Meta object using the structure represented by
+the given JSON string. In other respects it is identical to C<load_file()>.
+
+=head2 save
+
+ $meta->save($distmeta_file, \%options);
+
+Serializes the object as JSON and writes it to the given file. The only valid
+option is C<version>, which defaults to '2'. On Perl 5.8.1 or later, the file
+is saved with UTF-8 encoding.
+
+For C<version> 2 (or higher), the filename should end in '.json'. L<JSON::PP>
+is the default JSON backend. Using another JSON backend requires L<JSON> 2.5 or
+later and you must set the C<$ENV{PERL_JSON_BACKEND}> to a supported alternate
+backend like L<JSON::XS>.
+
+For C<version> less than 2, the filename should end in '.yml'.
+L<CPAN::Meta::Converter> is used to generate an older metadata structure, which
+is serialized to YAML. CPAN::Meta::YAML is the default YAML backend. You may
+set the C<$ENV{PERL_YAML_BACKEND}> to a supported alternative backend, though
+this is not recommended due to subtle incompatibilities between YAML parsers on
+CPAN.
+
+=head2 meta_spec_version
+
+This method returns the version part of the C<meta_spec> entry in the distmeta
+structure. It is equivalent to:
+
+ $meta->meta_spec->{version};
+
+=head2 effective_prereqs
+
+ my $prereqs = $meta->effective_prereqs;
+
+ my $prereqs = $meta->effective_prereqs( \@feature_identifiers );
+
+This method returns a L<CPAN::Meta::Prereqs> object describing all the
+prereqs for the distribution. If an arrayref of feature identifiers is given,
+the prereqs for the identified features are merged together with the
+distribution's core prereqs before the CPAN::Meta::Prereqs object is returned.
+
+=head2 should_index_file
+
+ ... if $meta->should_index_file( $filename );
+
+This method returns true if the given file should be indexed. It decides this
+by checking the C<file> and C<directory> keys in the C<no_index> property of
+the distmeta structure.
+
+C<$filename> should be given in unix format.
+
+=head2 should_index_package
+
+ ... if $meta->should_index_package( $package );
+
+This method returns true if the given package should be indexed. It decides
+this by checking the C<package> and C<namespace> keys in the C<no_index>
+property of the distmeta structure.
+
+=head2 features
+
+ my @feature_objects = $meta->features;
+
+This method returns a list of L<CPAN::Meta::Feature> objects, one for each
+optional feature described by the distribution's metadata.
+
+=head2 feature
+
+ my $feature_object = $meta->feature( $identifier );
+
+This method returns a L<CPAN::Meta::Feature> object for the optional feature
+with the given identifier. If no feature with that identifier exists, an
+exception will be raised.
+
+=head2 as_struct
+
+ my $copy = $meta->as_struct( \%options );
+
+This method returns a deep copy of the object's metadata as an unblessed has
+reference. It takes an optional hashref of options. If the hashref contains
+a C<version> argument, the copied metadata will be converted to the version
+of the specification and returned. For example:
+
+ my $old_spec = $meta->as_struct( {version => "1.4"} );
+
+=head2 as_string
+
+ my $string = $meta->as_string( \%options );
+
+This method returns a serialized copy of the object's metadata as a character
+string. (The strings are B<not> UTF-8 encoded.) It takes an optional hashref
+of options. If the hashref contains a C<version> argument, the copied metadata
+will be converted to the version of the specification and returned. For
+example:
+
+ my $string = $meta->as_struct( {version => "1.4"} );
+
+For C<version> greater than or equal to 2, the string will be serialized as
+JSON. For C<version> less than 2, the string will be serialized as YAML. In
+both cases, the same rules are followed as in the C<save()> method for choosing
+a serialization backend.
+
+=head1 STRING DATA
+
+The following methods return a single value, which is the value for the
+corresponding entry in the distmeta structure. Values should be either undef
+or strings.
+
+=over 4
+
+=item *
+
+abstract
+
+=item *
+
+description
+
+=item *
+
+dynamic_config
+
+=item *
+
+generated_by
+
+=item *
+
+name
+
+=item *
+
+release_status
+
+=item *
+
+version
+
+=back
+
+=head1 LIST DATA
+
+These methods return lists of string values, which might be represented in the
+distmeta structure as arrayrefs or scalars:
+
+=over 4
+
+=item *
+
+authors
+
+=item *
+
+keywords
+
+=item *
+
+licenses
+
+=back
+
+The C<authors> and C<licenses> methods may also be called as C<author> and
+C<license>, respectively, to match the field name in the distmeta structure.
+
+=head1 MAP DATA
+
+These readers return hashrefs of arbitrary unblessed data structures, each
+described more fully in the specification:
+
+=over 4
+
+=item *
+
+meta_spec
+
+=item *
+
+resources
+
+=item *
+
+provides
+
+=item *
+
+no_index
+
+=item *
+
+prereqs
+
+=item *
+
+optional_features
+
+=back
+
+=head1 CUSTOM DATA
+
+A list of custom keys are available from the C<custom_keys> method and
+particular keys may be retrieved with the C<custom> method.
+
+ say $meta->custom($_) for $meta->custom_keys;
+
+If a custom key refers to a data structure, a deep clone is returned.
+
+=head1 BUGS
+
+Please report any bugs or feature using the CPAN Request Tracker.
+Bugs can be submitted through the web interface at
+L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta>
+
+When submitting a bug or request, please include a test-file or a patch to an
+existing test-file that illustrates the bug or desired feature.
+
+=head1 SEE ALSO
+
+=over 4
+
+=item *
+
+L<CPAN::Meta::Converter>
+
+=item *
+
+L<CPAN::Meta::Validator>
+
+=back
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=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
+
+
+__END__
+
+
diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Converter.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Converter.pm
new file mode 100644
index 0000000000..2c6ce857d3
--- /dev/null
+++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Converter.pm
@@ -0,0 +1,1365 @@
+use 5.006;
+use strict;
+use warnings;
+package CPAN::Meta::Converter;
+BEGIN {
+ $CPAN::Meta::Converter::VERSION = '2.110440';
+}
+# ABSTRACT: Convert CPAN distribution metadata structures
+
+
+use CPAN::Meta::Validator;
+use Storable qw/dclone/;
+use version 0.82 ();
+
+my %known_specs = (
+ '2' => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
+ '1.4' => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
+ '1.3' => 'http://module-build.sourceforge.net/META-spec-v1.3.html',
+ '1.2' => 'http://module-build.sourceforge.net/META-spec-v1.2.html',
+ '1.1' => 'http://module-build.sourceforge.net/META-spec-v1.1.html',
+ '1.0' => 'http://module-build.sourceforge.net/META-spec-v1.0.html'
+);
+
+my @spec_list = sort { $a <=> $b } keys %known_specs;
+my ($LOWEST, $HIGHEST) = @spec_list[0,-1];
+
+#--------------------------------------------------------------------------#
+# converters
+#
+# called as $converter->($element, $field_name, $full_meta, $to_version)
+#
+# defined return value used for field
+# undef return value means field is skipped
+#--------------------------------------------------------------------------#
+
+sub _keep { $_[0] }
+
+sub _keep_or_one { defined($_[0]) ? $_[0] : 1 }
+
+sub _keep_or_zero { defined($_[0]) ? $_[0] : 0 }
+
+sub _keep_or_unknown { defined($_[0]) && length($_[0]) ? $_[0] : "unknown" }
+
+sub _generated_by {
+ my $gen = shift;
+ my $sig = __PACKAGE__ . " version " . (__PACKAGE__->VERSION || "<dev>");
+
+ return $sig unless defined $gen and length $gen;
+ return $gen if $gen =~ /(, )\Q$sig/;
+ return "$gen, $sig";
+}
+
+sub _listify { ! defined $_[0] ? undef : ref $_[0] eq 'ARRAY' ? $_[0] : [$_[0]] }
+
+sub _prefix_custom {
+ my $key = shift;
+ $key =~ s/^(?!x_) # Unless it already starts with x_
+ (?:x-?)? # Remove leading x- or x (if present)
+ /x_/ix; # and prepend x_
+ return $key;
+}
+
+sub _ucfirst_custom {
+ my $key = shift;
+ $key = ucfirst $key unless $key =~ /[A-Z]/;
+ return $key;
+}
+
+sub _change_meta_spec {
+ my ($element, undef, undef, $version) = @_;
+ $element->{version} = $version;
+ $element->{url} = $known_specs{$version};
+ return $element;
+}
+
+my @valid_licenses_1 = (
+ 'perl',
+ 'gpl',
+ 'apache',
+ 'artistic',
+ 'artistic_2',
+ 'lgpl',
+ 'bsd',
+ 'gpl',
+ 'mit',
+ 'mozilla',
+ 'open_source',
+ 'unrestricted',
+ 'restrictive',
+ 'unknown',
+);
+
+my %license_map_1 = (
+ ( map { $_ => $_ } @valid_licenses_1 ),
+ artistic2 => 'artistic_2',
+);
+
+sub _license_1 {
+ my ($element) = @_;
+ return 'unknown' unless defined $element;
+ if ( $license_map_1{lc $element} ) {
+ return $license_map_1{lc $element};
+ }
+ return 'unknown';
+}
+
+my @valid_licenses_2 = qw(
+ agpl_3
+ apache_1_1
+ apache_2_0
+ artistic_1
+ artistic_2
+ bsd
+ freebsd
+ gfdl_1_2
+ gfdl_1_3
+ gpl_1
+ gpl_2
+ gpl_3
+ lgpl_2_1
+ lgpl_3_0
+ mit
+ mozilla_1_0
+ mozilla_1_1
+ openssl
+ perl_5
+ qpl_1_0
+ ssleay
+ sun
+ zlib
+ open_source
+ restricted
+ unrestricted
+ unknown
+);
+
+my %license_map_2 = (
+ ( map { $_ => $_ } @valid_licenses_2 ),
+ apache => 'apache_2_0',
+ artistic => 'artistic_1',
+ artistic2 => 'artistic_2',
+ gpl => 'gpl_1',
+ lgpl => 'lgpl_2_1',
+ mozilla => 'mozilla_1_0',
+ perl => 'perl_5',
+ restrictive => 'restricted',
+);
+
+sub _license_2 {
+ my ($element) = @_;
+ return [ 'unknown' ] unless defined $element;
+ $element = [ $element ] unless ref $element eq 'ARRAY';
+ my @new_list;
+ for my $lic ( @$element ) {
+ next unless defined $lic;
+ if ( my $new = $license_map_2{lc $lic} ) {
+ push @new_list, $new;
+ }
+ }
+ return @new_list ? \@new_list : [ 'unknown' ];
+}
+
+my %license_downgrade_map = qw(
+ agpl_3 open_source
+ apache_1_1 apache
+ apache_2_0 apache
+ artistic_1 artistic
+ artistic_2 artistic_2
+ bsd bsd
+ freebsd open_source
+ gfdl_1_2 open_source
+ gfdl_1_3 open_source
+ gpl_1 gpl
+ gpl_2 gpl
+ gpl_3 gpl
+ lgpl_2_1 lgpl
+ lgpl_3_0 lgpl
+ mit mit
+ mozilla_1_0 mozilla
+ mozilla_1_1 mozilla
+ openssl open_source
+ perl_5 perl
+ qpl_1_0 open_source
+ ssleay open_source
+ sun open_source
+ zlib open_source
+ open_source open_source
+ restricted restrictive
+ unrestricted unrestricted
+ unknown unknown
+);
+
+sub _downgrade_license {
+ my ($element) = @_;
+ if ( ! defined $element ) {
+ return "unknown";
+ }
+ elsif( ref $element eq 'ARRAY' ) {
+ if ( @$element == 1 ) {
+ return $license_downgrade_map{$element->[0]} || "unknown";
+ }
+ }
+ elsif ( ! ref $element ) {
+ return $license_downgrade_map{$element} || "unknown";
+ }
+ return "unknown";
+}
+
+my $no_index_spec_1_2 = {
+ 'file' => \&_listify,
+ 'dir' => \&_listify,
+ 'package' => \&_listify,
+ 'namespace' => \&_listify,
+};
+
+my $no_index_spec_1_3 = {
+ 'file' => \&_listify,
+ 'directory' => \&_listify,
+ 'package' => \&_listify,
+ 'namespace' => \&_listify,
+};
+
+my $no_index_spec_2 = {
+ 'file' => \&_listify,
+ 'directory' => \&_listify,
+ 'package' => \&_listify,
+ 'namespace' => \&_listify,
+ ':custom' => \&_prefix_custom,
+};
+
+sub _no_index_1_2 {
+ my (undef, undef, $meta) = @_;
+ my $no_index = $meta->{no_index} || $meta->{private};
+ return unless $no_index;
+
+ # cleanup wrong format
+ if ( ! ref $no_index ) {
+ my $item = $no_index;
+ $no_index = { dir => [ $item ], file => [ $item ] };
+ }
+ elsif ( ref $no_index eq 'ARRAY' ) {
+ my $list = $no_index;
+ $no_index = { dir => [ @$list ], file => [ @$list ] };
+ }
+
+ # common mistake: files -> file
+ if ( exists $no_index->{files} ) {
+ $no_index->{file} = delete $no_index->{file};
+ }
+ # common mistake: modules -> module
+ if ( exists $no_index->{modules} ) {
+ $no_index->{module} = delete $no_index->{module};
+ }
+ return _convert($no_index, $no_index_spec_1_2);
+}
+
+sub _no_index_directory {
+ my ($element, $key, $meta, $version) = @_;
+ return unless $element;
+
+ # cleanup wrong format
+ if ( ! ref $element ) {
+ my $item = $element;
+ $element = { directory => [ $item ], file => [ $item ] };
+ }
+ elsif ( ref $element eq 'ARRAY' ) {
+ my $list = $element;
+ $element = { directory => [ @$list ], file => [ @$list ] };
+ }
+
+ if ( exists $element->{dir} ) {
+ $element->{directory} = delete $element->{dir};
+ }
+ # common mistake: files -> file
+ if ( exists $element->{files} ) {
+ $element->{file} = delete $element->{file};
+ }
+ # common mistake: modules -> module
+ if ( exists $element->{modules} ) {
+ $element->{module} = delete $element->{module};
+ }
+ my $spec = $version == 2 ? $no_index_spec_2 : $no_index_spec_1_3;
+ return _convert($element, $spec);
+}
+
+sub _is_module_name {
+ my $mod = shift;
+ return unless defined $mod && length $mod;
+ return $mod =~ m{^[A-Za-z][A-Za-z0-9_]*(?:::[A-Za-z0-9_]+)*$};
+}
+
+sub _clean_version {
+ my ($element, $key, $meta, $to_version) = @_;
+ return 0 if ! defined $element;
+
+ $element =~ s{^\s*}{};
+ $element =~ s{\s*$}{};
+ $element =~ s{^\.}{0.};
+
+ return 0 if ! length $element;
+ return 0 if ( $element eq 'undef' || $element eq '<undef>' );
+
+ if ( my $v = eval { version->new($element) } ) {
+ return $v->is_qv ? $v->normal : $element;
+ }
+ else {
+ return 0;
+ }
+}
+
+sub _version_map {
+ my ($element) = @_;
+ return undef unless defined $element;
+ if ( ref $element eq 'HASH' ) {
+ my $new_map = {};
+ for my $k ( keys %$element ) {
+ next unless _is_module_name($k);
+ my $value = $element->{$k};
+ if ( ! ( defined $value && length $value ) ) {
+ $new_map->{$k} = 0;
+ }
+ elsif ( $value eq 'undef' || $value eq '<undef>' ) {
+ $new_map->{$k} = 0;
+ }
+ elsif ( _is_module_name( $value ) ) { # some weird, old META have this
+ $new_map->{$k} = 0;
+ $new_map->{$value} = 0;
+ }
+ else {
+ $new_map->{$k} = _clean_version($value);
+ }
+ }
+ return $new_map;
+ }
+ elsif ( ref $element eq 'ARRAY' ) {
+ my $hashref = { map { $_ => 0 } @$element };
+ return _version_map($hashref); # cleanup any weird stuff
+ }
+ elsif ( ref $element eq '' && length $element ) {
+ return { $element => 0 }
+ }
+ return;
+}
+
+sub _prereqs_from_1 {
+ my (undef, undef, $meta) = @_;
+ my $prereqs = {};
+ for my $phase ( qw/build configure/ ) {
+ my $key = "${phase}_requires";
+ $prereqs->{$phase}{requires} = _version_map($meta->{$key})
+ if $meta->{$key};
+ }
+ for my $rel ( qw/requires recommends conflicts/ ) {
+ $prereqs->{runtime}{$rel} = _version_map($meta->{$rel})
+ if $meta->{$rel};
+ }
+ return $prereqs;
+}
+
+my $prereqs_spec = {
+ configure => \&_prereqs_rel,
+ build => \&_prereqs_rel,
+ test => \&_prereqs_rel,
+ runtime => \&_prereqs_rel,
+ develop => \&_prereqs_rel,
+ ':custom' => \&_prefix_custom,
+};
+
+my $relation_spec = {
+ requires => \&_version_map,
+ recommends => \&_version_map,
+ suggests => \&_version_map,
+ conflicts => \&_version_map,
+ ':custom' => \&_prefix_custom,
+};
+
+sub _cleanup_prereqs {
+ my ($prereqs, $key, $meta, $to_version) = @_;
+ return unless $prereqs && ref $prereqs eq 'HASH';
+ return _convert( $prereqs, $prereqs_spec, $to_version );
+}
+
+sub _prereqs_rel {
+ my ($relation, $key, $meta, $to_version) = @_;
+ return unless $relation && ref $relation eq 'HASH';
+ return _convert( $relation, $relation_spec, $to_version );
+}
+
+
+BEGIN {
+ my @old_prereqs = qw(
+ requires
+ configure_requires
+ recommends
+ conflicts
+ );
+
+ for ( @old_prereqs ) {
+ my $sub = "_get_$_";
+ my ($phase,$type) = split qr/_/, $_;
+ if ( ! defined $type ) {
+ $type = $phase;
+ $phase = 'runtime';
+ }
+ no strict 'refs';
+ *{$sub} = sub { _extract_prereqs($_[2]->{prereqs},$phase,$type) };
+ }
+}
+
+sub _get_build_requires {
+ my ($data, $key, $meta) = @_;
+
+ my $test_h = _extract_prereqs($_[2]->{prereqs}, qw(test requires)) || {};
+ my $build_h = _extract_prereqs($_[2]->{prereqs}, qw(build requires)) || {};
+
+ require Version::Requirements;
+ my $test_req = Version::Requirements->from_string_hash($test_h);
+ my $build_req = Version::Requirements->from_string_hash($build_h);
+
+ $test_req->add_requirements($build_req)->as_string_hash;
+}
+
+sub _extract_prereqs {
+ my ($prereqs, $phase, $type) = @_;
+ return unless ref $prereqs eq 'HASH';
+ return $prereqs->{$phase}{$type};
+}
+
+sub _downgrade_optional_features {
+ my (undef, undef, $meta) = @_;
+ return undef unless exists $meta->{optional_features};
+ my $origin = $meta->{optional_features};
+ my $features = {};
+ for my $name ( keys %$origin ) {
+ $features->{$name} = {
+ description => $origin->{$name}{description},
+ requires => _extract_prereqs($origin->{$name}{prereqs},'runtime','requires'),
+ configure_requires => _extract_prereqs($origin->{$name}{prereqs},'runtime','configure_requires'),
+ build_requires => _extract_prereqs($origin->{$name}{prereqs},'runtime','build_requires'),
+ recommends => _extract_prereqs($origin->{$name}{prereqs},'runtime','recommends'),
+ conflicts => _extract_prereqs($origin->{$name}{prereqs},'runtime','conflicts'),
+ };
+ for my $k (keys %{$features->{$name}} ) {
+ delete $features->{$name}{$k} unless defined $features->{$name}{$k};
+ }
+ }
+ return $features;
+}
+
+sub _upgrade_optional_features {
+ my (undef, undef, $meta) = @_;
+ return undef unless exists $meta->{optional_features};
+ my $origin = $meta->{optional_features};
+ my $features = {};
+ for my $name ( keys %$origin ) {
+ $features->{$name} = {
+ description => $origin->{$name}{description},
+ prereqs => _prereqs_from_1(undef, undef, $origin->{$name}),
+ };
+ delete $features->{$name}{prereqs}{configure};
+ }
+ return $features;
+}
+
+my $optional_features_2_spec = {
+ description => \&_keep,
+ prereqs => \&_cleanup_prereqs,
+ ':custom' => \&_prefix_custom,
+};
+
+sub _feature_2 {
+ my ($element, $key, $meta, $to_version) = @_;
+ return unless $element && ref $element eq 'HASH';
+ _convert( $element, $optional_features_2_spec, $to_version );
+}
+
+sub _cleanup_optional_features_2 {
+ my ($element, $key, $meta, $to_version) = @_;
+ return unless $element && ref $element eq 'HASH';
+ my $new_data = {};
+ for my $k ( keys %$element ) {
+ $new_data->{$k} = _feature_2( $element->{$k}, $k, $meta, $to_version );
+ }
+ return unless keys %$new_data;
+ return $new_data;
+}
+
+sub _optional_features_1_4 {
+ my ($element) = @_;
+ return unless $element;
+ $element = _optional_features_as_map($element);
+ for my $name ( keys %$element ) {
+ for my $drop ( qw/requires_packages requires_os excluded_os/ ) {
+ delete $element->{$name}{$drop};
+ }
+ }
+ return $element;
+}
+
+sub _optional_features_as_map {
+ my ($element) = @_;
+ return unless $element;
+ if ( ref $element eq 'ARRAY' ) {
+ my %map;
+ for my $feature ( @$element ) {
+ my (@parts) = %$feature;
+ $map{$parts[0]} = $parts[1];
+ }
+ $element = \%map;
+ }
+ return $element;
+}
+
+sub _is_urlish { defined $_[0] && $_[0] =~ m{\A[-+.a-z0-9]+:.+}i }
+
+sub _url_or_drop {
+ my ($element) = @_;
+ return $element if _is_urlish($element);
+ return;
+}
+
+sub _url_list {
+ my ($element) = @_;
+ return unless $element;
+ $element = _listify( $element );
+ $element = [ grep { _is_urlish($_) } @$element ];
+ return unless @$element;
+ return $element;
+}
+
+sub _author_list {
+ my ($element) = @_;
+ return [ 'unknown' ] unless $element;
+ $element = _listify( $element );
+ $element = [ map { defined $_ && length $_ ? $_ : 'unknown' } @$element ];
+ return [ 'unknown' ] unless @$element;
+ return $element;
+}
+
+my $resource2_upgrade = {
+ license => sub { return _is_urlish($_[0]) ? _listify( $_[0] ) : undef },
+ homepage => \&_url_or_drop,
+ bugtracker => sub {
+ my ($item) = @_;
+ return unless $item;
+ if ( $item =~ m{^mailto:(.*)$} ) { return { mailto => $1 } }
+ elsif( _is_urlish($item) ) { return { web => $item } }
+ else { return undef }
+ },
+ repository => sub { return _is_urlish($_[0]) ? { url => $_[0] } : undef },
+ ':custom' => \&_prefix_custom,
+};
+
+sub _upgrade_resources_2 {
+ my (undef, undef, $meta, $version) = @_;
+ return undef unless exists $meta->{resources};
+ return _convert($meta->{resources}, $resource2_upgrade);
+}
+
+my $bugtracker2_spec = {
+ web => \&_url_or_drop,
+ mailto => \&_keep,
+ ':custom' => \&_prefix_custom,
+};
+
+sub _repo_type {
+ my ($element, $key, $meta, $to_version) = @_;
+ return $element if defined $element;
+ return unless exists $meta->{url};
+ my $repo_url = $meta->{url};
+ for my $type ( qw/git svn/ ) {
+ return $type if $repo_url =~ m{\A$type};
+ }
+ return;
+}
+
+my $repository2_spec = {
+ web => \&_url_or_drop,
+ url => \&_url_or_drop,
+ type => \&_repo_type,
+ ':custom' => \&_prefix_custom,
+};
+
+my $resources2_cleanup = {
+ license => \&_url_list,
+ homepage => \&_url_or_drop,
+ bugtracker => sub { ref $_[0] ? _convert( $_[0], $bugtracker2_spec ) : undef },
+ repository => sub { my $data = shift; ref $data ? _convert( $data, $repository2_spec ) : undef },
+ ':custom' => \&_prefix_custom,
+};
+
+sub _cleanup_resources_2 {
+ my ($resources, $key, $meta, $to_version) = @_;
+ return undef unless $resources && ref $resources eq 'HASH';
+ return _convert($resources, $resources2_cleanup, $to_version);
+}
+
+my $resource1_spec = {
+ license => \&_url_or_drop,
+ homepage => \&_url_or_drop,
+ bugtracker => \&_url_or_drop,
+ repository => \&_url_or_drop,
+ ':custom' => \&_keep,
+};
+
+sub _resources_1_3 {
+ my (undef, undef, $meta, $version) = @_;
+ return undef unless exists $meta->{resources};
+ return _convert($meta->{resources}, $resource1_spec);
+}
+
+*_resources_1_4 = *_resources_1_3;
+
+sub _resources_1_2 {
+ my (undef, undef, $meta) = @_;
+ my $resources = $meta->{resources} || {};
+ if ( $meta->{license_url} && ! $resources->{license} ) {
+ $resources->{license} = $meta->license_url
+ if _is_urlish($meta->{license_url});
+ }
+ return undef unless keys %$resources;
+ return _convert($resources, $resource1_spec);
+}
+
+my $resource_downgrade_spec = {
+ license => sub { return ref $_[0] ? $_[0]->[0] : $_[0] },
+ homepage => \&_url_or_drop,
+ bugtracker => sub { return $_[0]->{web} },
+ repository => sub { return $_[0]->{url} || $_[0]->{web} },
+ ':custom' => \&_ucfirst_custom,
+};
+
+sub _downgrade_resources {
+ my (undef, undef, $meta, $version) = @_;
+ return undef unless exists $meta->{resources};
+ return _convert($meta->{resources}, $resource_downgrade_spec);
+}
+
+sub _release_status {
+ my ($element, undef, $meta) = @_;
+ return $element if $element && $element =~ m{\A(?:stable|testing|unstable)\z};
+ return _release_status_from_version(undef, undef, $meta);
+}
+
+sub _release_status_from_version {
+ my (undef, undef, $meta) = @_;
+ my $version = $meta->{version} || '';
+ return ( $version =~ /_/ ) ? 'testing' : 'stable';
+}
+
+my $provides_spec = {
+ file => \&_keep,
+ version => \&_clean_version,
+};
+
+my $provides_spec_2 = {
+ file => \&_keep,
+ version => \&_clean_version,
+ ':custom' => \&_prefix_custom,
+};
+
+sub _provides {
+ my ($element, $key, $meta, $to_version) = @_;
+ return unless defined $element && ref $element eq 'HASH';
+ my $spec = $to_version == 2 ? $provides_spec_2 : $provides_spec;
+ my $new_data = {};
+ for my $k ( keys %$element ) {
+ $new_data->{$k} = _convert($element->{$k}, $spec, $to_version);
+ }
+ return $new_data;
+}
+
+sub _convert {
+ my ($data, $spec, $to_version) = @_;
+
+ my $new_data = {};
+ for my $key ( keys %$spec ) {
+ next if $key eq ':custom' || $key eq ':drop';
+ next unless my $fcn = $spec->{$key};
+ die "spec for '$key' is not a coderef"
+ unless ref $fcn && ref $fcn eq 'CODE';
+ my $new_value = $fcn->($data->{$key}, $key, $data, $to_version);
+ $new_data->{$key} = $new_value if defined $new_value;
+ }
+
+ my $drop_list = $spec->{':drop'};
+ my $customizer = $spec->{':custom'} || \&_keep;
+
+ for my $key ( keys %$data ) {
+ next if $drop_list && grep { $key eq $_ } @$drop_list;
+ next if exists $spec->{$key}; # we handled it
+ $new_data->{ $customizer->($key) } = $data->{$key};
+ }
+
+ return $new_data;
+}
+
+#--------------------------------------------------------------------------#
+# define converters for each conversion
+#--------------------------------------------------------------------------#
+
+# each converts from prior version
+# special ":custom" field is used for keys not recognized in spec
+my %up_convert = (
+ '2-from-1.4' => {
+ # PRIOR MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_2,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # CHANGED TO MANDATORY
+ 'dynamic_config' => \&_keep_or_one,
+ # ADDED MANDATORY
+ 'release_status' => \&_release_status_from_version,
+ # PRIOR OPTIONAL
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_upgrade_optional_features,
+ 'provides' => \&_provides,
+ 'resources' => \&_upgrade_resources_2,
+ # ADDED OPTIONAL
+ 'description' => \&_keep,
+ 'prereqs' => \&_prereqs_from_1,
+
+ # drop these deprecated fields, but only after we convert
+ ':drop' => [ qw(
+ build_requires
+ configure_requires
+ conflicts
+ distribution_type
+ license_url
+ private
+ recommends
+ requires
+ ) ],
+
+ # other random keys need x_ prefixing
+ ':custom' => \&_prefix_custom,
+ },
+ '1.4-from-1.3' => {
+ # PRIOR MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_optional_features_1_4,
+ 'provides' => \&_provides,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ 'resources' => \&_resources_1_4,
+ # ADDED OPTIONAL
+ 'configure_requires' => \&_keep,
+
+ # drop these deprecated fields, but only after we convert
+ ':drop' => [ qw(
+ license_url
+ private
+ )],
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+ '1.3-from-1.2' => {
+ # PRIOR MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_optional_features_as_map,
+ 'provides' => \&_provides,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ 'resources' => \&_resources_1_3,
+
+ # drop these deprecated fields, but only after we convert
+ ':drop' => [ qw(
+ license_url
+ private
+ )],
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+ '1.2-from-1.1' => {
+ # PRIOR MANDATORY
+ 'version' => \&_keep,
+ # CHANGED TO MANDATORY
+ 'license' => \&_license_1,
+ 'name' => \&_keep,
+ 'generated_by' => \&_generated_by,
+ # ADDED MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'meta-spec' => \&_change_meta_spec,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ # ADDED OPTIONAL
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_1_2,
+ 'optional_features' => \&_optional_features_as_map,
+ 'provides' => \&_provides,
+ 'resources' => \&_resources_1_2,
+
+ # drop these deprecated fields, but only after we convert
+ ':drop' => [ qw(
+ license_url
+ private
+ )],
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+ '1.1-from-1.0' => {
+ # CHANGED TO MANDATORY
+ 'version' => \&_keep,
+ # IMPLIED MANDATORY
+ 'name' => \&_keep,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ # ADDED OPTIONAL
+ 'license_url' => \&_url_or_drop,
+ 'private' => \&_keep,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+);
+
+my %down_convert = (
+ '1.4-from-2' => {
+ # MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_downgrade_license,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # OPTIONAL
+ 'build_requires' => \&_get_build_requires,
+ 'configure_requires' => \&_get_configure_requires,
+ 'conflicts' => \&_get_conflicts,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_downgrade_optional_features,
+ 'provides' => \&_provides,
+ 'recommends' => \&_get_recommends,
+ 'requires' => \&_get_requires,
+ 'resources' => \&_downgrade_resources,
+
+ # drop these unsupported fields (after conversion)
+ ':drop' => [ qw(
+ description
+ prereqs
+ release_status
+ )],
+
+ # custom keys will be left unchanged
+ ':custom' => \&_keep
+ },
+ '1.3-from-1.4' => {
+ # MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_optional_features_as_map,
+ 'provides' => \&_provides,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ 'resources' => \&_resources_1_3,
+
+ # drop these unsupported fields, but only after we convert
+ ':drop' => [ qw(
+ configure_requires
+ )],
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep,
+ },
+ '1.2-from-1.3' => {
+ # MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_1_2,
+ 'optional_features' => \&_optional_features_as_map,
+ 'provides' => \&_provides,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ 'resources' => \&_resources_1_3,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep,
+ },
+ '1.1-from-1.2' => {
+ # MANDATORY
+ 'version' => \&_keep,
+ # IMPLIED MANDATORY
+ 'name' => \&_keep,
+ 'meta-spec' => \&_change_meta_spec,
+ # OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'private' => \&_keep,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+
+ # drop unsupported fields
+ ':drop' => [ qw(
+ abstract
+ author
+ provides
+ no_index
+ keywords
+ resources
+ )],
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep,
+ },
+ '1.0-from-1.1' => {
+ # IMPLIED MANDATORY
+ 'name' => \&_keep,
+ 'meta-spec' => \&_change_meta_spec,
+ 'version' => \&_keep,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep,
+ },
+);
+
+my %cleanup = (
+ '2' => {
+ # PRIOR MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_2,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # CHANGED TO MANDATORY
+ 'dynamic_config' => \&_keep_or_one,
+ # ADDED MANDATORY
+ 'release_status' => \&_release_status,
+ # PRIOR OPTIONAL
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_cleanup_optional_features_2,
+ 'provides' => \&_provides,
+ 'resources' => \&_cleanup_resources_2,
+ # ADDED OPTIONAL
+ 'description' => \&_keep,
+ 'prereqs' => \&_cleanup_prereqs,
+
+ # drop these deprecated fields, but only after we convert
+ ':drop' => [ qw(
+ build_requires
+ configure_requires
+ conflicts
+ distribution_type
+ license_url
+ private
+ recommends
+ requires
+ ) ],
+
+ # other random keys need x_ prefixing
+ ':custom' => \&_prefix_custom,
+ },
+ '1.4' => {
+ # PRIOR MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_optional_features_1_4,
+ 'provides' => \&_provides,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ 'resources' => \&_resources_1_4,
+ # ADDED OPTIONAL
+ 'configure_requires' => \&_keep,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+ '1.3' => {
+ # PRIOR MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'meta-spec' => \&_change_meta_spec,
+ 'name' => \&_keep,
+ 'version' => \&_keep,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_directory,
+ 'optional_features' => \&_optional_features_as_map,
+ 'provides' => \&_provides,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ 'resources' => \&_resources_1_3,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+ '1.2' => {
+ # PRIOR MANDATORY
+ 'version' => \&_keep,
+ # CHANGED TO MANDATORY
+ 'license' => \&_license_1,
+ 'name' => \&_keep,
+ 'generated_by' => \&_generated_by,
+ # ADDED MANDATORY
+ 'abstract' => \&_keep_or_unknown,
+ 'author' => \&_author_list,
+ 'meta-spec' => \&_change_meta_spec,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ # ADDED OPTIONAL
+ 'keywords' => \&_keep,
+ 'no_index' => \&_no_index_1_2,
+ 'optional_features' => \&_optional_features_as_map,
+ 'provides' => \&_provides,
+ 'resources' => \&_resources_1_2,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+ '1.1' => {
+ # CHANGED TO MANDATORY
+ 'version' => \&_keep,
+ # IMPLIED MANDATORY
+ 'name' => \&_keep,
+ 'meta-spec' => \&_change_meta_spec,
+ # PRIOR OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+ # ADDED OPTIONAL
+ 'license_url' => \&_url_or_drop,
+ 'private' => \&_keep,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep
+ },
+ '1.0' => {
+ # IMPLIED MANDATORY
+ 'name' => \&_keep,
+ 'meta-spec' => \&_change_meta_spec,
+ 'version' => \&_keep,
+ # IMPLIED OPTIONAL
+ 'build_requires' => \&_version_map,
+ 'conflicts' => \&_version_map,
+ 'distribution_type' => \&_keep,
+ 'dynamic_config' => \&_keep_or_one,
+ 'generated_by' => \&_generated_by,
+ 'license' => \&_license_1,
+ 'recommends' => \&_version_map,
+ 'requires' => \&_version_map,
+
+ # other random keys are OK if already valid
+ ':custom' => \&_keep,
+ },
+);
+
+#--------------------------------------------------------------------------#
+# Code
+#--------------------------------------------------------------------------#
+
+
+sub new {
+ my ($class,$data) = @_;
+
+ # create an attributes hash
+ my $self = {
+ 'data' => $data,
+ 'spec' => $data->{'meta-spec'}{'version'} || "1.0",
+ };
+
+ # create the object
+ return bless $self, $class;
+}
+
+
+sub convert {
+ my ($self, %args) = @_;
+ my $args = { %args };
+
+ my $new_version = $args->{version} || $HIGHEST;
+
+ my ($old_version) = $self->{spec};
+ my $converted = dclone $self->{data};
+
+ if ( $old_version == $new_version ) {
+ $converted = _convert( $converted, $cleanup{$old_version}, $old_version );
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ unless ( $cmv->is_valid ) {
+ my $errs = join("\n", $cmv->errors);
+ die "Failed to clean-up $old_version metadata. Errors:\n$errs\n";
+ }
+ return $converted;
+ }
+ elsif ( $old_version > $new_version ) {
+ my @vers = sort { $b <=> $a } keys %known_specs;
+ for my $i ( 0 .. $#vers-1 ) {
+ next if $vers[$i] > $old_version;
+ last if $vers[$i+1] < $new_version;
+ my $spec_string = "$vers[$i+1]-from-$vers[$i]";
+ $converted = _convert( $converted, $down_convert{$spec_string}, $vers[$i+1] );
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ unless ( $cmv->is_valid ) {
+ my $errs = join("\n", $cmv->errors);
+ die "Failed to downconvert metadata to $vers[$i+1]. Errors:\n$errs\n";
+ }
+ }
+ return $converted;
+ }
+ else {
+ my @vers = sort { $a <=> $b } keys %known_specs;
+ for my $i ( 0 .. $#vers-1 ) {
+ next if $vers[$i] < $old_version;
+ last if $vers[$i+1] > $new_version;
+ my $spec_string = "$vers[$i+1]-from-$vers[$i]";
+ $converted = _convert( $converted, $up_convert{$spec_string}, $vers[$i+1] );
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ unless ( $cmv->is_valid ) {
+ my $errs = join("\n", $cmv->errors);
+ die "Failed to upconvert metadata to $vers[$i+1]. Errors:\n$errs\n";
+ }
+ }
+ return $converted;
+ }
+}
+
+1;
+
+
+
+=pod
+
+=head1 NAME
+
+CPAN::Meta::Converter - Convert CPAN distribution metadata structures
+
+=head1 VERSION
+
+version 2.110440
+
+=head1 SYNOPSIS
+
+ my $struct = decode_json_file('META.json');
+
+ my $cmc = CPAN::Meta::Converter->new( $struct );
+
+ my $new_struct = $cmc->convert( version => "2" );
+
+=head1 DESCRIPTION
+
+This module converts CPAN Meta structures from one form to another. The
+primary use is to convert older structures to the most modern version of
+the specification, but other transformations may be implemented in the
+future as needed. (E.g. stripping all custom fields or stripping all
+optional fields.)
+
+=head1 METHODS
+
+=head2 new
+
+ my $cmc = CPAN::Meta::Converter->new( $struct );
+
+The constructor should be passed a valid metadata structure but invalid
+structures are accepted. If no meta-spec version is provided, version 1.0 will
+be assumed.
+
+=head2 convert
+
+ my $new_struct = $cmc->convert( version => "2" );
+
+Returns a new hash reference with the metadata converted to a different form.
+C<convert> will die if any conversion/standardization still results in an
+invalid structure.
+
+Valid parameters include:
+
+=over
+
+=item *
+
+C<version> -- Indicates the desired specification version (e.g. "1.0", "1.1" ... "1.4", "2").
+Defaults to the latest version of the CPAN Meta Spec.
+
+=back
+
+Conversion proceeds through each version in turn. For example, a version 1.2
+structure might be converted to 1.3 then 1.4 then finally to version 2. The
+conversion process attempts to clean-up simple errors and standardize data.
+For example, if C<author> is given as a scalar, it will converted to an array
+reference containing the item. (Converting a structure to its own version will
+also clean-up and standardize.)
+
+When data are cleaned and standardized, missing or invalid fields will be
+replaced with sensible defaults when possible. This may be lossy or imprecise.
+For example, some badly structured META.yml files on CPAN have prerequisite
+modules listed as both keys and values:
+
+ requires => { 'Foo::Bar' => 'Bam::Baz' }
+
+These would be split and each converted to a prerequisite with a minimum
+version of zero.
+
+When some mandatory fields are missing or invalid, the conversion will attempt
+to provide a sensible default or will fill them with a value of 'unknown'. For
+example a missing or unrecognized C<license> field will result in a C<license>
+field of 'unknown'. Fields that may get an 'unknown' include:
+
+=over 4
+
+=item *
+
+abstract
+
+=item *
+
+author
+
+=item *
+
+license
+
+=back
+
+=head1 BUGS
+
+Please report any bugs or feature using the CPAN Request Tracker.
+Bugs can be submitted through the web interface at
+L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta>
+
+When submitting a bug or request, please include a test-file or a patch to an
+existing test-file that illustrates the bug or desired feature.
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=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
+
+
+__END__
+
+
diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Feature.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Feature.pm
new file mode 100644
index 0000000000..d3575e5e7e
--- /dev/null
+++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Feature.pm
@@ -0,0 +1,116 @@
+use 5.006;
+use strict;
+use warnings;
+package CPAN::Meta::Feature;
+BEGIN {
+ $CPAN::Meta::Feature::VERSION = '2.110440';
+}
+# ABSTRACT: an optional feature provided by a CPAN distribution
+
+use CPAN::Meta::Prereqs;
+
+
+sub new {
+ my ($class, $identifier, $spec) = @_;
+
+ my %guts = (
+ identifier => $identifier,
+ description => $spec->{description},
+ prereqs => CPAN::Meta::Prereqs->new($spec->{prereqs}),
+ );
+
+ bless \%guts => $class;
+}
+
+
+sub identifier { $_[0]{identifier} }
+
+
+sub description { $_[0]{description} }
+
+
+sub prereqs { $_[0]{prereqs} }
+
+1;
+
+
+
+=pod
+
+=head1 NAME
+
+CPAN::Meta::Feature - an optional feature provided by a CPAN distribution
+
+=head1 VERSION
+
+version 2.110440
+
+=head1 DESCRIPTION
+
+A CPAN::Meta::Feature object describes an optional feature offered by a CPAN
+distribution and specified in the distribution's F<META.json> (or F<META.yml>)
+file.
+
+For the most part, this class will only be used when operating on the result of
+the C<feature> or C<features> methods on a L<CPAN::Meta> object.
+
+=head1 METHODS
+
+=head2 new
+
+ my $feature = CPAN::Meta::Feature->new( $identifier => \%spec );
+
+This returns a new Feature object. The C<%spec> argument to the constructor
+should be the same as the value of the C<optional_feature> entry in the
+distmeta. It must contain entries for C<description> and C<prereqs>.
+
+=head2 identifier
+
+This method returns the feature's identifier.
+
+=head2 description
+
+This method returns the feature's long description.
+
+=head2 prereqs
+
+This method returns the feature's prerequisites as a L<CPAN::Meta::Prereqs>
+object.
+
+=head1 BUGS
+
+Please report any bugs or feature using the CPAN Request Tracker.
+Bugs can be submitted through the web interface at
+L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta>
+
+When submitting a bug or request, please include a test-file or a patch to an
+existing test-file that illustrates the bug or desired feature.
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=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
+
+
+__END__
+
+
+
diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/History.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/History.pm
new file mode 100644
index 0000000000..ab036907a4
--- /dev/null
+++ b/cpan/CPAN-Meta/lib/CPAN/Meta/History.pm
@@ -0,0 +1,315 @@
+# vi:tw=72
+use 5.006;
+use strict;
+use warnings;
+package CPAN::Meta::History;
+BEGIN {
+ $CPAN::Meta::History::VERSION = '2.110440';
+}
+# ABSTRACT: history of CPAN Meta Spec changes
+1;
+
+
+
+__END__
+=pod
+
+=head1 NAME
+
+CPAN::Meta::History - history of CPAN Meta Spec changes
+
+=head1 VERSION
+
+version 2.110440
+
+=head1 DESCRIPTION
+
+The CPAN Meta Spec has gone through several iterations. It was
+originally written in HTML and later revised into POD (though published
+in HTML generated from the POD). Fields were added, removed or changed,
+sometimes by design and sometimes to reflect real-world usage after the
+fact.
+
+This document reconstructs the history of the CPAN Meta Spec based on
+change logs, repository commit messages and the published HTML files.
+In some cases, particularly prior to version 1.2, the exact version
+when certain fields were introduced or changed is inconsistent between
+sources. When in doubt, the published HTML files for versions 1.0 to
+1.4 as they existed when version 2 was developed are used as the
+definitive source.
+
+Starting with version 2, the specification document is part of the
+CPAN-Meta distribution and will be published on CPAN as
+L<CPAN::Meta::Spec>.
+
+Going forward, specification version numbers will be integers and
+decimal portions will correspond to a release date for the CPAN::Meta
+library.
+
+=head1 HISTORY
+
+=head2 Version 2
+
+April 2010
+
+=over
+
+=item *
+
+Revised spec examples as perl data structures rather than YAML
+
+=item *
+
+Switched to JSON serialization from YAML
+
+=item *
+
+Specified allowed version number formats
+
+=item *
+
+Replaced 'requires', 'build_requires', 'configure_requires',
+'recommends' and 'conflicts' with new 'prereqs' data structure divided
+by I<phase> (configure, build, test, runtime, etc.) and I<relationship>
+(requires, recommends, suggests, conflicts)
+
+=item *
+
+Added support for 'develop' phase for requirements for maintaining
+a list of authoring tools
+
+=item *
+
+Changed 'license' to a list and revised the set of valid licenses
+
+=item *
+
+Made 'dynamic_config' mandatory to reduce confusion
+
+=item *
+
+Changed 'resources' subkey 'repository' to a hash that clarifies
+repository type, url for browsing and url for checkout
+
+=item *
+
+Changed 'resources' subkey 'bugtracker' to a hash for either web
+or mailto resource
+
+=item *
+
+Changed specification of 'optional_features':
+
+=over
+
+=item *
+
+Added formal specification and usage guide instead of just example
+
+=item *
+
+Changed to use new prereqs data structure instead of individual keys
+
+=back
+
+=item *
+
+Clarified intended use of 'author' as generalized contact list
+
+=item *
+
+Added 'release_status' field to indicate stable, testing or unstable
+status to provide hints to indexers
+
+=item *
+
+Added 'description' field for a longer description of the distribution
+
+=item *
+
+Formalized use of "x_" or "X_" for all custom keys not listed in the
+official spec
+
+=back
+
+=head2 Version 1.4
+
+June 2008
+
+=over
+
+=item *
+
+Noted explicit support for 'perl' in prerequisites
+
+=item *
+
+Added 'configure_requires' prerequisite type
+
+=item *
+
+Changed 'optional_features'
+
+=over
+
+=item *
+
+Example corrected to show map of maps instead of list of maps
+(though descriptive text said 'map' even in v1.3)
+
+=item *
+
+Removed 'requires_packages', 'requires_os' and 'excluded_os'
+as valid subkeys
+
+=back
+
+=back
+
+=head2 Version 1.3
+
+November 2006
+
+=over
+
+=item *
+
+Clarified that all prerequisites take version range specifications
+
+=item *
+
+Added 'no_index' subkey 'directory' and removed 'dir' to match actual
+usage in the wild
+
+=item *
+
+Added a 'repository' subkey to 'resources'
+
+=back
+
+=head2 Version 1.2
+
+August 2005
+
+=over
+
+=item *
+
+Re-wrote and restructured spec in POD syntax
+
+=item *
+
+Changed 'name' to be mandatory
+
+=item *
+
+Changed 'generated_by' to be mandatory
+
+=item *
+
+Changed 'license' to be mandatory
+
+=item *
+
+Added required 'abstract' field
+
+=item *
+
+Added required 'author' field
+
+=item *
+
+Added required 'meta-spec' field to define 'version' (and 'url') of the
+CPAN Meta Spec used for metadata
+
+=item *
+
+Added 'provides' field
+
+=item *
+
+Added 'no_index' field and deprecated 'private' field. 'no_index'
+subkeys include 'file', 'dir', 'package' and 'namespace'
+
+=item *
+
+Added 'keywords' field
+
+=item *
+
+Added 'resources' field with subkeys 'homepage', 'license', and
+'bugtracker'
+
+=item *
+
+Added 'optional_features' field as an alterate under 'recommends'.
+Includes 'description', 'requires', 'build_requires', 'conflicts',
+'requires_packages', 'requires_os' and 'excluded_os' as valid subkeys
+
+=item *
+
+Removed 'license_uri' field
+
+=back
+
+=head2 Version 1.1
+
+May 2003
+
+=over
+
+=item *
+
+Changed 'version' to be mandatory
+
+=item *
+
+Added 'private' field
+
+=item *
+
+Added 'license_uri' field
+
+=back
+
+=head2 Version 1.0
+
+March 2003
+
+=over
+
+=item *
+
+Original release (in HTML format only)
+
+=item *
+
+Included 'name', 'version', 'license', 'distribution_type', 'requires',
+'recommends', 'build_requires', 'conflicts', 'dynamic_config',
+'generated_by'
+
+=back
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=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
+
diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Prereqs.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Prereqs.pm
new file mode 100644
index 0000000000..4fc20939ab
--- /dev/null
+++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Prereqs.pm
@@ -0,0 +1,277 @@
+use 5.006;
+use strict;
+use warnings;
+package CPAN::Meta::Prereqs;
+BEGIN {
+ $CPAN::Meta::Prereqs::VERSION = '2.110440';
+}
+# ABSTRACT: a set of distribution prerequisites by phase and type
+
+
+use Carp qw(confess);
+use Scalar::Util qw(blessed);
+use Version::Requirements 0.101020; # finalize
+
+
+sub __legal_phases { qw(configure build test runtime develop) }
+sub __legal_types { qw(requires recommends suggests conflicts) }
+
+# expect a prereq spec from META.json -- rjbs, 2010-04-11
+sub new {
+ my ($class, $prereq_spec) = @_;
+ $prereq_spec ||= {};
+
+ my %is_legal_phase = map {; $_ => 1 } $class->__legal_phases;
+ my %is_legal_type = map {; $_ => 1 } $class->__legal_types;
+
+ my %guts;
+ PHASE: for my $phase (keys %$prereq_spec) {
+ next PHASE unless $phase =~ /\Ax_/i or $is_legal_phase{$phase};
+
+ my $phase_spec = $prereq_spec->{ $phase };
+ next PHASE unless keys %$phase_spec;
+
+ TYPE: for my $type (keys %$phase_spec) {
+ next TYPE unless $type =~ /\Ax_/i or $is_legal_type{$type};
+
+ my $spec = $phase_spec->{ $type };
+
+ next TYPE unless keys %$spec;
+
+ $guts{prereqs}{$phase}{$type} = Version::Requirements->from_string_hash(
+ $spec
+ );
+ }
+ }
+
+ return bless \%guts => $class;
+}
+
+
+sub requirements_for {
+ my ($self, $phase, $type) = @_;
+
+ confess "requirements_for called without phase" unless defined $phase;
+ confess "requirements_for called without type" unless defined $type;
+
+ unless ($phase =~ /\Ax_/i or grep { $phase eq $_ } $self->__legal_phases) {
+ confess "requested requirements for unknown phase: $phase";
+ }
+
+ unless ($type =~ /\Ax_/i or grep { $type eq $_ } $self->__legal_types) {
+ confess "requested requirements for unknown type: $type";
+ }
+
+ my $req = ($self->{prereqs}{$phase}{$type} ||= Version::Requirements->new);
+
+ $req->finalize if $self->is_finalized;
+
+ return $req;
+}
+
+
+sub with_merged_prereqs {
+ my ($self, $other) = @_;
+
+ my @other = blessed($other) ? $other : @$other;
+
+ my @prereq_objs = ($self, @other);
+
+ my %new_arg;
+
+ for my $phase ($self->__legal_phases) {
+ for my $type ($self->__legal_types) {
+ my $req = Version::Requirements->new;
+
+ for my $prereq (@prereq_objs) {
+ my $this_req = $prereq->requirements_for($phase, $type);
+ next unless $this_req->required_modules;
+
+ $req->add_requirements($this_req);
+ }
+
+ next unless $req->required_modules;
+
+ $new_arg{ $phase }{ $type } = $req->as_string_hash;
+ }
+ }
+
+ return (ref $self)->new(\%new_arg);
+}
+
+
+sub as_string_hash {
+ my ($self) = @_;
+
+ my %hash;
+
+ for my $phase ($self->__legal_phases) {
+ for my $type ($self->__legal_types) {
+ my $req = $self->requirements_for($phase, $type);
+ next unless $req->required_modules;
+
+ $hash{ $phase }{ $type } = $req->as_string_hash;
+ }
+ }
+
+ return \%hash;
+}
+
+
+sub is_finalized { $_[0]{finalized} }
+
+
+sub finalize {
+ my ($self) = @_;
+
+ $self->{finalized} = 1;
+
+ for my $phase (keys %{ $self->{prereqs} }) {
+ $_->finalize for values %{ $self->{prereqs}{$phase} };
+ }
+}
+
+
+sub clone {
+ my ($self) = @_;
+
+ my $clone = (ref $self)->new( $self->as_string_hash );
+}
+
+1;
+
+
+
+=pod
+
+=head1 NAME
+
+CPAN::Meta::Prereqs - a set of distribution prerequisites by phase and type
+
+=head1 VERSION
+
+version 2.110440
+
+=head1 DESCRIPTION
+
+A CPAN::Meta::Prereqs object represents the prerequisites for a CPAN
+distribution or one of its optional features. Each set of prereqs is
+organized by phase and type, as described in L<CPAN::Meta::Prereqs>.
+
+=head1 METHODS
+
+=head2 new
+
+ my $prereq = CPAN::Meta::Prereqs->new( \%prereq_spec );
+
+This method returns a new set of Prereqs. The input should look like the
+contents of the C<prereqs> field described in L<CPAN::Meta::Spec>, meaning
+something more or less like this:
+
+ my $prereq = CPAN::Meta::Prereqs->new({
+ runtime => {
+ requires => {
+ 'Some::Module' => '1.234',
+ ...,
+ },
+ ...,
+ },
+ ...,
+ });
+
+You can also construct an empty set of prereqs with:
+
+ my $prereqs = CPAN::Meta::Prereqs->new;
+
+This empty set of prereqs is useful for accumulating new prereqs before finally
+dumping the whole set into a structure or string.
+
+=head2 requirements_for
+
+ my $requirements = $prereqs->requirements_for( $phase, $type );
+
+This method returns a L<Version::Requirements> object for the given phase/type
+combination. If no prerequisites are registered for that combination, a new
+Version::Requirements object will be returned, and it may be added to as
+needed.
+
+If C<$phase> or C<$type> are undefined or otherwise invalid, an exception will
+be raised.
+
+=head2 with_merged_prereqs
+
+ my $new_prereqs = $prereqs->with_merged_prereqs( $other_prereqs );
+
+ my $new_prereqs = $prereqs->with_merged_prereqs( \@other_prereqs );
+
+This method returns a new CPAN::Meta::Prereqs objects in which all the
+other prerequisites given are merged into the current set. This is primarily
+provided for combining a distribution's core prereqs with the prereqs of one of
+its optional features.
+
+The new prereqs object has no ties to the originals, and altering it further
+will not alter them.
+
+=head2 as_string_hash
+
+This method returns a hashref containing structures suitable for dumping into a
+distmeta data structure. It is made up of hashes and strings, only; there will
+be no Prereqs, Version::Requirements, or C<version> objects inside it.
+
+=head2 is_finalized
+
+This method returns true if the set of prereqs has been marked "finalized," and
+cannot be altered.
+
+=head2 finalize
+
+Calling C<finalize> on a Prereqs object will close it for further modification.
+Attempting to make any changes that would actually alter the prereqs will
+result in an exception being thrown.
+
+=head2 clone
+
+ my $cloned_prereqs = $prereqs->clone;
+
+This method returns a Prereqs object that is identical to the original object,
+but can be altered without affecting the original object. Finalization does
+not survive cloning, meaning that you may clone a finalized set of prereqs and
+then modify the clone.
+
+=head1 BUGS
+
+Please report any bugs or feature using the CPAN Request Tracker.
+Bugs can be submitted through the web interface at
+L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta>
+
+When submitting a bug or request, please include a test-file or a patch to an
+existing test-file that illustrates the bug or desired feature.
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=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
+
+
+__END__
+
+
+
diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Spec.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Spec.pm
new file mode 100644
index 0000000000..8f94c718cb
--- /dev/null
+++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Spec.pm
@@ -0,0 +1,1145 @@
+# vi:tw=72
+use 5.006;
+use strict;
+use warnings;
+package CPAN::Meta::Spec;
+BEGIN {
+ $CPAN::Meta::Spec::VERSION = '2.110440';
+}
+# ABSTRACT: specification for CPAN distribution metadata
+1;
+
+
+
+__END__
+=pod
+
+=head1 NAME
+
+CPAN::Meta::Spec - specification for CPAN distribution metadata
+
+=head1 VERSION
+
+version 2.110440
+
+=head1 SYNOPSIS
+
+ my $distmeta = {
+ name => 'Module-Build',
+ abstract => 'Build and install Perl modules',
+ description => "Module::Build is a system for "
+ . "building, testing, and installing Perl modules. "
+ . "It is meant to ... blah blah blah ...",
+ version => '0.36',
+ author => [
+ 'Ken Williams <kwilliams@cpan.org>',
+ 'Module-Build List <module-build@perl.org>', # additional contact
+ ],
+ license => [ 'perl_5' ],
+ prereqs => {
+ runtime => {
+ requires => {
+ 'perl' => '5.006',
+ 'ExtUtils::Install' => '0',
+ 'File::Basename' => '0',
+ 'File::Compare' => '0',
+ 'IO::File' => '0',
+ },
+ recommends => {
+ 'Archive::Tar' => '1.00',
+ 'ExtUtils::Install' => '0.3',
+ 'ExtUtils::ParseXS' => '2.02',
+ },
+ },
+ build => {
+ requires => {
+ 'Test::More' => '0',
+ },
+ }
+ },
+ resources => {
+ license => ['http://dev.perl.org/licenses/'],
+ },
+ optional_features => {
+ domination => {
+ description => 'Take over the world',
+ prereqs => {
+ develop => { requires => { 'Genius::Evil' => '1.234' } },
+ runtime => { requires => { 'Machine::Weather' => '2.0' } },
+ },
+ },
+ },
+ dynamic_config => 1,
+ keywords => [ qw/ toolchain cpan dual-life / ],
+ 'meta-spec' => {
+ version => '2',
+ url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
+ },
+ generated_by => 'Module::Build version 0.36',
+ };
+
+=head1 DESCRIPTION
+
+This document describes version 2 of the CPAN distribution metadata
+specification, also known as the "CPAN Meta Spec".
+
+Revisions of this specification for typo corrections and prose
+clarifications may be issued as CPAN::Meta::Spec 2.I<x>. These
+revisions will never change semantics or add or remove specified
+behavior.
+
+Distribution metadata describe important properties of Perl
+distributions. Distribution building tools like Module::Build,
+Module::Install, ExtUtils::MakeMaker or Dist::Zilla should create a
+metadata file in accordance with this specification and include it with
+the distribution for use by automated tools that index, examine, package
+or install Perl distributions.
+
+=head1 TERMINOLOGY
+
+=over 4
+
+=item distribution
+
+This is the primary object described by the metadata. In the context of
+this document it usually refers to a collection of modules, scripts,
+and/or documents that are distributed together for other developers to
+use. Examples of distributions are C<Class-Container>, C<libwww-perl>,
+or C<DBI>.
+
+=item module
+
+This refers to a reusable library of code contained in a single file.
+Modules usually contain one or more packages and are often referred
+to by the name of a primary package that can be mapped to the file
+name. For example, one might refer to C<File::Spec> instead of
+F<File/Spec.pm>
+
+=item package
+
+This refers to a namespace declared with the Perl C<package> statement.
+In Perl, packages often have a version number property given by the
+C<$VERSION> variable in the namespace.
+
+=item consumer
+
+This refers to code that reads a metadata file, deserializes it into a
+data structure in memory, or interprets a data structure of metadata
+elements.
+
+=item producer
+
+This refers to code that constructs a metadata data structure,
+serializes into a bytestream and/or writes it to disk.
+
+=item must, should, may, etc.
+
+These terms are interpreted as described in IETF RFC 2119.
+
+=back
+
+=head1 DATA TYPES
+
+Fields in the L</STRUCTURE> section describe data elements, each of
+which has an associated data type as described herein. There are four
+primitive types: Boolean, String, List and Map. Other types are
+subtypes of primitives and define compound data structures or define
+constraints on the values of a data element.
+
+=head2 Boolean
+
+A I<Boolean> is used to provide a true or false value. It B<must> be
+represented as a defined value.
+
+=head2 String
+
+A I<String> is data element containing a non-zero length sequence of
+Unicode characters, such as an ordinary Perl scalar that is not a
+reference.
+
+=head2 List
+
+A I<List> is an ordered collection of zero or more data elements.
+Elements of a List may be of mixed types.
+
+Producers B<must> represent List elements using a data structure which
+unambiguously indicates that multiple values are possible, such as a
+reference to a Perl array (an "arrayref").
+
+Consumers expecting a List B<must> consider a String as equivalent to a
+List of length 1.
+
+=head2 Map
+
+A I<Map> is an unordered collection of zero or more data elements
+("values"), indexed by associated String elements ("keys"). The Map's
+value elements may be of mixed types.
+
+=head2 License String
+
+A I<License String> is a subtype of String with a restricted set of
+values. Valid values are described in detail in the description of
+the L</license> field.
+
+=head2 URL
+
+I<URL> is a subtype of String containing a Uniform Resource Locator or
+Identifier. [ This type is called URL and not URI for historical reasons. ]
+
+=head2 Version
+
+A I<Version> is a subtype of String containing a value that describes
+the version number of packages or distributions. Restrictions on format
+are described in detail in the L</Version Formats> section.
+
+=head2 Version Range
+
+The I<Version Range> type is a subtype of String. It describes a range
+of Versions that may be present or installed to fulfill prerequisites.
+It is specified in detail in the L</Version Ranges> section.
+
+=head1 STRUCTURE
+
+The metadata structure is a data element of type Map. This section
+describes valid keys within the Map.
+
+Any keys not described in this specification document (whether top-level
+or within compound data structures described herein) are considered
+I<custom keys> and B<must> begin with an "x" or "X" and be followed by an
+underscore; i.e. they must match the pattern: C<< qr{\Ax_}i >>. If a
+custom key refers to a compound data structure, subkeys within it do not
+need an "x_" or "X_" prefix.
+
+Consumers of metadata may ignore any or all custom keys. All other keys
+not described herein are invalid and should be ignored by consumers.
+Producers must not generate or output invalid keys.
+
+For each key, an example is provided followed by a description. The
+description begins with the version of spec in which the key was added
+or in which the definition was modified, whether the key is I<required>
+or I<optional> and the data type of the corresponding data element.
+These items are in parentheses, brackets and braces, respectively.
+
+If a data type is a Map or Map subtype, valid subkeys will be described
+as well.
+
+Some fields are marked I<Deprecated>. These are shown for historical
+context and must not be produced in or consumed from any metadata structure
+of version 2 or higher.
+
+=head2 REQUIRED FIELDS
+
+=head3 abstract
+
+Example:
+
+ abstract => 'Build and install Perl modules'
+
+(Spec 1.2) [required] {String}
+
+This is a short description of the purpose of the distribution.
+
+=head3 author
+
+Example:
+
+ author => [ 'Ken Williams <kwilliams@cpan.org>' ]
+
+(Spec 1.2) [required] {List of one or more Strings}
+
+This List indicates the person(s) to contact concerning the
+distribution. The preferred form of the contact string is:
+
+ contact-name <email-address>
+
+This field provides a general contact list independent of other
+structured fields provided within the L</resources> field, such as
+C<bugtracker>. The addressee(s) can be contacted for any purpose
+including but not limited to (security) problems with the distribution,
+questions about the distribution or bugs in the distribution.
+
+A distribution's original author is usually the contact listed within
+this field. Co-maintainers, successor maintainers or mailing lists
+devoted to the distribution may also be listed in addition to or instead
+of the original author.
+
+=head3 dynamic_config
+
+Example:
+
+ dynamic_config => 1
+
+(Spec 2) [required] {Boolean}
+
+A boolean flag indicating whether a F<Build.PL> or F<Makefile.PL> (or
+similar) must be executed to determine prerequisites.
+
+This field should be set to a true value if the distribution performs
+some dynamic configuration (asking questions, sensing the environment,
+etc.) as part of its configuration. This field should be set to a false
+value to indicate that prerequisites included in metadata may be
+considered final and valid for static analysis.
+
+This field explicitly B<does not> indicate whether installation may be
+safely performed without using a Makefile or Build file, as there may be
+special files to install or custom installation targets (e.g. for
+dual-life modules that exist on CPAN as well as in the Perl core). This
+field only defines whether prerequisites are complete as given in the
+metadata.
+
+=head3 generated_by
+
+Example:
+
+ generated_by => 'Module::Build version 0.36'
+
+(Spec 1.0) [required] {String}
+
+This field indicates the tool that was used to create this metadata.
+There are no defined semantics for this field, but it is traditional to
+use a string in the form "Generating::Package version 1.23" or the
+author's name, if the file was generated by hand.
+
+=head3 license
+
+Example:
+
+ license => [ 'perl_5' ]
+
+ license => [ 'apache_2', 'mozilla_1_0' ]
+
+(Spec 2) [required] {List of one or more License Strings}
+
+One or more licenses that apply to some or all of the files in the
+distribution. If multiple licenses are listed, the distribution
+documentation should be consulted to clarify the interpretation of
+multiple licenses.
+
+The following list of license strings are valid:
+
+ string description
+ ------------- -----------------------------------------------
+ agpl_3 GNU Affero General Public License, Version 3
+ apache_1_1 Apache Software License, Version 1.1
+ apache_2_0 Apache License, Version 2.0
+ artistic_1 Artistic License, (Version 1)
+ artistic_2 Artistic License, Version 2.0
+ bsd BSD License (three-clause)
+ freebsd FreeBSD License (two-clause)
+ gfdl_1_2 GNU Free Documentation License, Version 1.2
+ gfdl_1_3 GNU Free Documentation License, Version 1.3
+ gpl_1 GNU General Public License, Version 1
+ gpl_2 GNU General Public License, Version 2
+ gpl_3 GNU General Public License, Version 3
+ lgpl_2_1 GNU Lesser General Public License, Version 2.1
+ lgpl_3_0 GNU Lesser General Public License, Version 3.0
+ mit MIT (aka X11) License
+ mozilla_1_0 Mozilla Public License, Version 1.0
+ mozilla_1_1 Mozilla Public License, Version 1.1
+ openssl OpenSSL License
+ perl_5 The Perl 5 License (Artistic 1 & GPL 1 or later)
+ qpl_1_0 Q Public License, Version 1.0
+ ssleay Original SSLeay License
+ sun Sun Internet Standards Source License (SISSL)
+ zlib zlib License
+
+The following license strings are also valid and indicate other
+licensing not described above:
+
+ string description
+ ------------- -----------------------------------------------
+ open_source Other Open Source Initiative (OSI) approved license
+ restricted Requires special permission from copyright holder
+ unrestricted Not an OSI approved license, but not restricted
+ unknown License not provided in metadata
+
+All other strings are invalid in the license field.
+
+=head3 meta-spec
+
+Example:
+
+ 'meta-spec' => {
+ version => '2',
+ url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
+ }
+
+(Spec 1.2) [required] {Map}
+
+This field indicates the version of the CPAN Meta Spec that should be
+used to interpret the metadata. Consumers must check this key as soon
+as possible and abort further metadata processing if the meta-spec
+version is not supported by the consumer.
+
+The following keys are valid, but only C<version> is required.
+
+=over
+
+=item version
+
+This subkey gives the integer I<Version> of the CPAN Meta Spec against
+which the document was generated.
+
+=item url
+
+This is a I<URL> of the metadata specification document corresponding to
+the given version. This is strictly for human-consumption and should
+not impact the interpretation of the document.
+
+=back
+
+=head3 name
+
+Example:
+
+ name => 'Module-Build'
+
+(Spec 1.0) [required] {String}
+
+This field is the name of the distribution. This is often created by
+taking the "main package" in the distribution and changing C<::> to
+C<->, but the name may be completely unrelated to the packages within
+the distribution. C.f. L<http://search.cpan.org/dist/libwww-perl/>.
+
+=head3 release_status
+
+Example:
+
+ release_status => 'stable'
+
+(Spec 2) [required] {String}
+
+This field provides the release status of this distribution. If the
+C<version> field contains an underscore character, then
+C<release_status> B<must not> be "stable."
+
+The C<release_status> field B<must> have one of the following values:
+
+=over
+
+=item stable
+
+This indicates an ordinary, "final" release that should be indexed by PAUSE
+or other indexers.
+
+=item testing
+
+This indicates a "beta" release that is substantially complete, but has an
+elevated risk of bugs and requires additional testing. The distribution
+should not be installed over a stable release without an explicit request
+or other confirmation from a user. This release status may also be used
+for "release candidate" versions of a distribution.
+
+=item unstable
+
+This indicates an "alpha" release that is under active development, but has
+been released for early feedback or testing and may be missing features or
+may have serious bugs. The distribution should not be installed over a
+stable release without an explicit request or other confirmation from a
+user.
+
+=back
+
+Consumers B<may> use this field to determine how to index the
+distribution for CPAN or other repositories in addition to or in
+replacement of heuristics based on version number or file name.
+
+=head3 version
+
+Example:
+
+ version => '0.36'
+
+(Spec 1.0) [required] {Version}
+
+This field gives the version of the distribution to which the metadata
+structure refers.
+
+=head2 OPTIONAL FIELDS
+
+=head3 description
+
+Example:
+
+ description => "Module::Build is a system for "
+ . "building, testing, and installing Perl modules. "
+ . "It is meant to ... blah blah blah ...",
+
+(Spec 2) [optional] {String}
+
+A longer, more complete description of the purpose or intended use of
+the distribution than the one provided by the C<abstract> key.
+
+=head3 keywords
+
+Example:
+
+ keywords => [ qw/ toolchain cpan dual-life / ]
+
+(Spec 1.1) [optional] {List of zero or more Strings}
+
+A List of keywords that describe this distribution. Keywords
+B<must not> include whitespace.
+
+=head3 no_index
+
+Example:
+
+ no_index => {
+ file => [ 'My/Module.pm' ],
+ directory => [ 'My/Private' ],
+ package => [ 'My::Module::Secret' ],
+ namespace => [ 'My::Module::Sample' ],
+ }
+
+(Spec 1.2) [optional] {Map}
+
+This Map describes any files, directories, packages, and namespaces that
+are private to the packaging or implementation of the distribution and
+should be ignored by indexing or search tools.
+
+Valid subkeys are as follows:
+
+=over
+
+=item file
+
+A I<List> of relative paths to files. Paths B<must be> specified with
+unix convetions.
+
+=item directory
+
+A I<List> of relative paths to directories. Paths B<must be> specified
+with unix convetions.
+
+[ Note: previous editions of the spec had C<dir> instead of C<directory> ]
+
+=item package
+
+A I<List> of package names.
+
+=item namespace
+
+A I<List> of package namespaces, where anything below the namespace
+must be ignored, but I<not> the namespace itself.
+
+In the example above for C<no_index>, C<My::Module::Sample::Foo> would
+be ignored, but C<My::Module::Sample> would not.
+
+=back
+
+=head3 optional_features
+
+Example:
+
+ optional_features => {
+ sqlite => {
+ description => 'Provides SQLite support',
+ prereqs => {
+ runtime => {
+ requires => {
+ 'DBD::SQLite' => '1.25'
+ }
+ }
+ }
+ }
+ }
+
+(Spec 2) [optional] {Map}
+
+This Map describes optional features with incremental prerequisites.
+Each key of the C<optional_features> Map is a String used to identify
+the feature and each value is a Map with additional information about
+the feature. Valid subkeys include:
+
+=over
+
+=item description
+
+This is a String describing the feature. Every optional feature
+should provide a description
+
+=item prereqs
+
+This entry is required and has the same structure as that of the
+C<L</prereqs>> key. It provides a list of package requirements
+that must be satisfied for the feature to be supported or enabled.
+
+There is one crucial restriction: the preqreqs of an optional feature
+B<must not> include C<configure> phase prereqs.
+
+=back
+
+Consumers B<must not> include optional features as prerequisites without
+explict instruction from users (whether via interactive prompting,
+a function parameter or a configuration value, etc. ).
+
+If an optional feature is used by a consumer to add additional
+prerequisites, the consumer should merge the optional feature
+prerequisites into those given by the C<prereqs> key using the same
+semantics. See L</Merging and Resolving Prerequisites> for details on
+merging prerequisites.
+
+I<Suggestion for disuse:> Because there is currently no way for a
+distribution to specify a dependency on an optional feature of another
+dependency, the use of C<optional_feature> is discouraged. Instead,
+create a separate, installable distribution that ensures the desired
+feature is available. For example, if C<Foo::Bar> has a "Baz" feature,
+release a separate C<Foo-Bar-Baz> distribution that satisfies
+requirements for the feature.
+
+=head3 prereqs
+
+Example:
+
+ prereqs => {
+ runtime => {
+ requires => {
+ 'perl' => '5.006',
+ 'File::Spec' => '0.86',
+ 'JSON' => '2.16',
+ },
+ recommends => {
+ 'JSON::XS' => '2.26',
+ },
+ suggests => {
+ 'Archive::Tar' => '0',
+ },
+ },
+ build => {
+ requires => {
+ 'Alien::SDL' => '1.00',
+ },
+ },
+ test => {
+ recommends => {
+ 'Test::Deep' => '0.10',
+ },
+ }
+ }
+
+(Spec 2) [optional] {Map}
+
+This is a Map that describes all the prerequisites of the distribution.
+The keys are phases of activity, such as C<configure>, C<build>, C<test>
+or C<runtime>. Values are Maps in which the keys name the type of
+prerequisite relationship such as C<requires>, C<recommends>, or
+C<suggests> and the value provides a set of prerequisite relations. The
+set of relations B<must> be specified as a Map of package names to
+version ranges.
+
+The full definition for this field is given in the L</Prereq Spec>
+section.
+
+=head3 provides
+
+Example:
+
+ provides => {
+ 'Foo::Bar' => {
+ file => 'lib/Foo/Bar.pm',
+ version => 0.27_02
+ },
+ 'Foo::Bar::Blah' => {
+ file => 'lib/Foo/Bar/Blah.pm',
+ },
+ 'Foo::Bar::Baz' => {
+ file => 'lib/Foo/Bar/Baz.pm',
+ version => 0.3,
+ },
+ }
+
+(Spec 1.2) [optional] {Map}
+
+This describes all packages provided by this distribution. This
+information is used by distribution and automation mechanisms like
+PAUSE, CPAN, and search.cpan.org to build indexes saying in which
+distribution various packages can be found.
+
+The keys of C<provides> are package names that can be found within
+the distribution. The values are Maps with the following valid subkeys:
+
+=over
+
+=item file
+
+This field is required. The value must contain a relative file path
+from the root of the distribution to the module containing the package.
+
+=item version
+
+This field contains a I<Version> String for the package, if one exists.
+
+=back
+
+=head3 resources
+
+Example:
+
+ resources => {
+ license => [ 'http://dev.perl.org/licenses/' ],
+ homepage => 'http://sourceforge.net/projects/module-build',
+ bugtracker => {
+ web => 'http://github.com/dagolden/cpan-meta-spec/issues',
+ mailto => 'meta-bugs@example.com',
+ },
+ repository => {
+ url => 'git://github.com/dagolden/cpan-meta-spec.git',
+ web => 'http://github.com/dagolden/cpan-meta-spec',
+ type => 'git',
+ },
+ x_twitter => 'http://twitter.com/cpan_linked/',
+ }
+
+(Spec 2) [optional] {Map}
+
+This field describes resources related to this distribution.
+
+Valid subkeys include:
+
+=over
+
+=item homepage
+
+The official home of this project on the web.
+
+=item license
+
+A List of I<URL>'s that relate to this distribution's license. As with the
+top-level C<license> field, distribution documentation should be consulted
+to clarify the interpretation of multiple licenses provided here.
+
+=item bugtracker
+
+This entry describes the bug tracking system for this distribution. It
+is a Map with the following valid keys:
+
+ web - a URL pointing to a web front-end for the bug tracker
+ mailto - an email address to which bugs can be sent
+
+=item repository
+
+This entry describes the source control repository for this distribution. It
+is a Map with the following valid keys:
+
+ url - a URL pointing to the repository itself
+ web - a URL pointing to a web front-end for the repository
+ type - a lowercase string indicating the VCS used
+
+Because a url like C<http://myrepo.example.com/> is ambiguous as to
+type, producers should provide a C<type> whenever a C<url> key is given.
+The C<type> field should be the name of the most common program used
+to work with the repository, e.g. git, svn, cvs, darcs, bzr or hg.
+
+=back
+
+=head2 DEPRECATED FIELDS
+
+=head3 build_requires
+
+I<(Deprecated in Spec 2)> [optional] {String}
+
+Replaced by C<prereqs>
+
+=head3 configure_requires
+
+I<(Deprecated in Spec 2)> [optional] {String}
+
+Replaced by C<prereqs>
+
+=head3 conflicts
+
+I<(Deprecated in Spec 2)> [optional] {String}
+
+Replaced by C<prereqs>
+
+=head3 distribution_type
+
+I<(Deprecated in Spec 2)> [optional] {String}
+
+This field indicated 'module' or 'script' but was considered
+meaningless, since many distributions are hybrids of several kinds of
+things.
+
+=head3 license_uri
+
+I<(Deprecated in Spec 1.2)> [optional] {URL}
+
+Replaced by C<license> in C<resources>
+
+=head3 private
+
+I<(Deprecated in Spec 1.2)> [optional] {Map}
+
+This field has been renamed to L</"no_index">.
+
+=head3 recommends
+
+I<(Deprecated in Spec 2)> [optional] {String}
+
+Replaced by C<prereqs>
+
+=head3 requires
+
+I<(Deprecated in Spec 2)> [optional] {String}
+
+Replaced by C<prereqs>
+
+=head1 VERSION NUMBERS
+
+=head2 Version Formats
+
+This section defines the Version type, used by several fields in the
+CPAN Meta Spec.
+
+Version numbers must be treated as strings, not numbers. For
+example, C<1.200> B<must not> be serialized as C<1.2>. Version
+comparison should be delegated to the Perl L<version> module, version
+0.80 or newer.
+
+Unless otherwise specified, version numbers B<must> appear in one of two
+formats:
+
+=over
+
+=item Decimal versions
+
+Decimal versions are regular "decimal numbers", with some limitations.
+They B<must> be non-negative and B<must> begin and end with a digit. A
+single underscore B<may> be included, but B<must> be between two digits.
+They B<must not> use exponential notation ("1.23e-2").
+
+ version => '1.234' # OK
+ version => '1.23_04' # OK
+
+ version => '1.23_04_05' # Illegal
+ version => '1.' # Illegal
+ version => '.1' # Illegal
+
+=item Dotted-integer versions
+
+Dotted-integer (also known as dotted-decimal) versions consist of
+positive integers separated by full stop characters (i.e. "dots",
+"periods" or "decimal points"). This are equivalent in format to Perl
+"v-strings", with some additional restrictions on form. They must be
+given in "normal" form, which has a leading "v" character and at least
+three integer components. To retain a one-to-one mapping with decimal
+versions, all components after the first B<should> be restricted to the
+range 0 to 999. The final component B<may> be separated by an
+underscore character instead of a period.
+
+ version => 'v1.2.3' # OK
+ version => 'v1.2_3' # OK
+ version => 'v1.2.3.4' # OK
+ version => 'v1.2.3_4' # OK
+ version => 'v2009.10.31' # OK
+
+ version => 'v1.2' # Illegal
+ version => '1.2.3' # Illegal
+ version => 'v1.2_3_4' # Illegal
+ version => 'v1.2009.10.31' # Not recommended
+
+=back
+
+=head2 Version Ranges
+
+Some fields (prereq, optional_features) indicate the particular
+version(s) of some other module that may be required as a prerequisite.
+This section details the Version Range type used to provide this
+information.
+
+The simplest format for a Version Range is just the version
+number itself, e.g. C<2.4>. This means that B<at least> version 2.4
+must be present. To indicate that B<any> version of a prerequisite is
+okay, even if the prerequisite doesn't define a version at all, use
+the version C<0>.
+
+Alternatively, a version range B<may> use the operators E<lt> (less than),
+E<lt>= (less than or equal), E<gt> (greater than), E<gt>= (greater than
+or equal), == (equal), and != (not equal). For example, the
+specification C<E<lt> 2.0> means that any version of the prerequisite
+less than 2.0 is suitable.
+
+For more complicated situations, version specifications B<may> be AND-ed
+together using commas. The specification C<E<gt>= 1.2, != 1.5, E<lt>
+2.0> indicates a version that must be B<at least> 1.2, B<less than> 2.0,
+and B<not equal to> 1.5.
+
+=head1 PREREQUISITES
+
+=head2 Prereq Spec
+
+The C<prereqs> key in the top-level metadata and within
+C<optional_features> define the relationship between a distribution and
+other packages. The prereq spec structure is a hierarchical data
+structure which divides prerequisites into I<Phases> of activity in the
+installation process and I<Relationships> that indicate how
+prerequisites should be resolved.
+
+For example, to specify that C<Data::Dumper> is C<required> during the
+C<test> phase, this entry would appear in the distribution metadata:
+
+ prereqs => {
+ test => {
+ requires => {
+ 'Data::Dumper' => '2.00'
+ }
+ }
+ }
+
+=head3 Phases
+
+Requirements for regular use must be listed in the C<runtime> phase.
+Other requirements should be listed in the earliest stage in which they
+are required and consumers must accumulate and satisfy requirements
+across phases before executing the activity. For example, C<build>
+requirements must also be available during the C<test> phase.
+
+ before action requirements that must be met
+ ---------------- --------------------------------
+ perl Build.PL configure
+ perl Makefile.PL
+
+ make configure, runtime, build
+ Build
+
+ make test configure, runtime, build, test
+ Build test
+
+Consumers that install the distribution must ensure that
+I<runtime> requirements are also installed and may install
+dependencies from other phases.
+
+ after action requirements that must be met
+ ---------------- --------------------------------
+ make install runtime
+ Build install
+
+=over
+
+=item configure
+
+The configure phase occurs before any dynamic configuration has been
+attempted. Libraries required by the configure phase B<must> be
+available for use before the distribution building tool has been
+executed.
+
+=item build
+
+The build phase is when the distribution's source code is compiled (if
+necessary) and otherwise made ready for installation.
+
+=item test
+
+The test phase is when the distribution's automated test suite is run.
+Any library that is needed only for testing and not for subsequent use
+should be listed here.
+
+=item runtime
+
+The runtime phase refers not only to when the distribution's contents
+are installed, but also to its continued use. Any library that is a
+prerequisite for regular use of this distribution should be indicated
+here.
+
+=item develop
+
+The develop phase's prereqs are libraries needed to work on the
+distribution's source code as its author does. These tools might be
+needed to build a release tarball, to run author-only tests, or to
+perform other tasks related to developing new versions of the
+distribution.
+
+=back
+
+=head3 Relationships
+
+=over
+
+=item requires
+
+These dependencies B<must> be installed for proper completion of the
+phase.
+
+=item recommends
+
+Recommended dependencies are I<strongly> encouraged and should be
+satisfied except in resource constrained environments.
+
+=item suggests
+
+These dependencies are optional, but are suggested for enhanced operation
+of the described distribution.
+
+=item conflicts
+
+These libraries cannot be installed when the phase is in operation.
+This is a very rare situation, and the C<conflicts> relationship should
+be used with great caution, or not at all.
+
+=back
+
+=head2 Merging and Resolving Prerequisites
+
+Whenever metadata consumers merge prerequisites, either from different
+phases or from C<optional_features>, they should merged in a way which
+preserves the intended semantics of the prerequisite structure. Generally,
+this means concatenating the version specifications using commas, as
+described in the L<Version Ranges> section.
+
+Another subtle error that can occur in resolving prerequisites comes from
+the way that modules in prerequisites are indexed to distribution files on
+CPAN. When a module is deleted from a distribution, prerequisites calling
+for that module could indicate an older distribution should installed,
+potentially overwriting files from a newer distribution.
+
+For example, as of Oct 31, 2009, the CPAN index file contained these
+module-distribution mappings:
+
+ Class::MOP 0.94 D/DR/DROLSKY/Class-MOP-0.94.tar.gz
+ Class::MOP::Class 0.94 D/DR/DROLSKY/Class-MOP-0.94.tar.gz
+ Class::MOP::Class::Immutable 0.04 S/ST/STEVAN/Class-MOP-0.36.tar.gz
+
+Consider the case where "Class::MOP" 0.94 is installed. If a
+distribution specified "Class::MOP::Class::Immutable" as a prerequisite,
+it could result in Class-MOP-0.36.tar.gz being installed, overwriting
+any files from Class-MOP-0.94.tar.gz.
+
+Consumers of metadata B<should> test whether prerequisites would result
+in installed module files being "downgraded" to an older version and
+B<may> warn users or ignore the prerequisite that would cause such a
+result.
+
+=head1 SERIALIZATION
+
+Distribution metadata should be serialized (as a hashref) as
+JSON-encoded data and packaged with distributions as the file
+F<META.json>.
+
+In the past, the distribution metadata structure had been packed with
+distributions as F<META.yml>, a file in the YAML Tiny format (for which,
+see L<YAML::Tiny>). Tools that consume distribution metadata from disk
+should be capable of loading F<META.yml>, but should prefer F<META.json>
+if both are found.
+
+=head1 NOTES FOR IMPLEMENTORS
+
+=head2 Extracting Version Numbers from Perl Modules
+
+To get the version number from a Perl module, consumers should use the
+C<< MM->parse_version($file) >> method provided by L<ExtUtils::MakeMaker> or
+the L<Module::Build::ModuleInfo> module provided with L<Module::Build>. For
+example, for the module given by C<$mod>, the version may be retrieved in one
+of the following ways:
+
+ # via ExtUtils::MakeMaker
+ my $file = MM->_installed_file_for_module($mod);
+ my $version = MM->parse_version($file)
+
+The private C<_installed_file_for_module> method may be replaced with
+other methods for locating a module in C<@INC>.
+
+ # via Module::Build
+ my $info = Module::Build::ModuleInfo->new_from_module($mod);
+ my $version = $info->version;
+
+If only a filename is available, the following approach may be used:
+
+ # via Module::Build
+ my $info = Module::Build::ModuleInfo->new_from_file($file);
+ my $version = $info->version;
+
+=head2 Comparing Version Numbers
+
+The L<version> module provides the most reliable way to compare version
+numbers in all the various ways they might be provided or might exist
+within modules. Given two strings containing version numbers, C<$v1> and
+C<$v2>, they should be converted to C<version> objects before using
+ordinary comparison operators. For example:
+
+ use version;
+ if ( version->new($v1) <=> version->new($v2) ) {
+ print "Versions are not equal\n";
+ }
+
+If the only comparison needed is whether an installed module is of a
+sufficiently high version, a direct test may be done using the string
+form of C<eval> and the C<use> function. For example, for module C<$mod>
+and version prerequisite C<$prereq>:
+
+ if ( eval "use $mod $prereq (); 1" ) {
+ print "Module $mod version is OK.\n";
+ }
+
+If the values of C<$mod> and C<$prereq> have not been scrubbed, however,
+this presents security implications.
+
+=head1 SEE ALSO
+
+CPAN, L<http://www.cpan.org/>
+
+CPAN.pm, L<http://search.cpan.org/dist/CPAN/>
+
+CPANPLUS, L<http://search.cpan.org/dist/CPANPLUS/>
+
+ExtUtils::MakeMaker, L<http://search.cpan.org/dist/ExtUtils-MakeMaker/>
+
+Module::Build, L<http://search.cpan.org/dist/Module-Build/>
+
+Module::Install, L<http://search.cpan.org/dist/Module-Install/>
+
+JSON, L<http://json.org/>
+
+YAML, L<http://www.yaml.org/>
+
+=head1 CONTRIBUTORS
+
+Ken Williams wrote the original CPAN Meta Spec (also known as the
+"META.yml spec") in 2003 and maintained it through several revisions
+with input from various members of the community. In 2005, Randy
+Sims redrafted it from HTML to POD for the version 1.2 release. Ken
+continued to maintain the spec through version 1.4.
+
+In late 2009, David Golden organized the version 2 proposal review
+process. David and Ricardo Signes drafted the final version 2 spec
+in April 2010 based on the version 1.4 spec and patches contributed
+during the proposal process.
+
+Several others have contributed patches over the years. The full list
+of contributors in the repository history currently includes:
+
+ 2shortplanks
+ Avar Arnfjord Bjarmason
+ Christopher J. Madsen
+ Damyan Ivanov
+ David Golden
+ Eric Wilhelm
+ Ken Williams
+ Lars DIECKOW
+ Michael G. Schwern
+ Randy Sims
+ Ricardo Signes
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=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
+
diff --git a/cpan/CPAN-Meta/lib/CPAN/Meta/Validator.pm b/cpan/CPAN-Meta/lib/CPAN/Meta/Validator.pm
new file mode 100644
index 0000000000..a203621ab8
--- /dev/null
+++ b/cpan/CPAN-Meta/lib/CPAN/Meta/Validator.pm
@@ -0,0 +1,1002 @@
+use 5.006;
+use strict;
+use warnings;
+package CPAN::Meta::Validator;
+BEGIN {
+ $CPAN::Meta::Validator::VERSION = '2.110440';
+}
+# ABSTRACT: validate CPAN distribution metadata structures
+
+
+#--------------------------------------------------------------------------#
+# This code copied and adapted from Test::CPAN::Meta
+# by Barbie, <barbie@cpan.org> for Miss Barbell Productions,
+# L<http://www.missbarbell.co.uk>
+#--------------------------------------------------------------------------#
+
+#--------------------------------------------------------------------------#
+# Specification Definitions
+#--------------------------------------------------------------------------#
+
+my %known_specs = (
+ '1.4' => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
+ '1.3' => 'http://module-build.sourceforge.net/META-spec-v1.3.html',
+ '1.2' => 'http://module-build.sourceforge.net/META-spec-v1.2.html',
+ '1.1' => 'http://module-build.sourceforge.net/META-spec-v1.1.html',
+ '1.0' => 'http://module-build.sourceforge.net/META-spec-v1.0.html'
+);
+my %known_urls = map {$known_specs{$_} => $_} keys %known_specs;
+
+my $module_map1 = { 'map' => { ':key' => { name => \&module, value => \&exversion } } };
+
+my $module_map2 = { 'map' => { ':key' => { name => \&module, value => \&version } } };
+
+my $no_index_2 = {
+ 'map' => { file => { list => { value => \&string } },
+ directory => { list => { value => \&string } },
+ 'package' => { list => { value => \&string } },
+ namespace => { list => { value => \&string } },
+ ':key' => { name => \&custom_2, value => \&anything },
+ }
+};
+
+my $no_index_1_3 = {
+ 'map' => { file => { list => { value => \&string } },
+ directory => { list => { value => \&string } },
+ 'package' => { list => { value => \&string } },
+ namespace => { list => { value => \&string } },
+ ':key' => { name => \&string, value => \&anything },
+ }
+};
+
+my $no_index_1_2 = {
+ 'map' => { file => { list => { value => \&string } },
+ dir => { list => { value => \&string } },
+ 'package' => { list => { value => \&string } },
+ namespace => { list => { value => \&string } },
+ ':key' => { name => \&string, value => \&anything },
+ }
+};
+
+my $no_index_1_1 = {
+ 'map' => { ':key' => { name => \&string, list => { value => \&string } },
+ }
+};
+
+my $prereq_map = {
+ map => {
+ ':key' => {
+ name => \&phase,
+ 'map' => {
+ ':key' => {
+ name => \&relation,
+ %$module_map1,
+ },
+ },
+ }
+ },
+};
+
+my %definitions = (
+ '2' => {
+ # REQUIRED
+ 'abstract' => { mandatory => 1, value => \&string },
+ 'author' => { mandatory => 1, lazylist => { value => \&string } },
+ 'dynamic_config' => { mandatory => 1, value => \&boolean },
+ 'generated_by' => { mandatory => 1, value => \&string },
+ 'license' => { mandatory => 1, lazylist => { value => \&license } },
+ 'meta-spec' => {
+ mandatory => 1,
+ 'map' => {
+ version => { mandatory => 1, value => \&version},
+ url => { value => \&url },
+ ':key' => { name => \&custom_2, value => \&anything },
+ }
+ },
+ 'name' => { mandatory => 1, value => \&string },
+ 'release_status' => { mandatory => 1, value => \&release_status },
+ 'version' => { mandatory => 1, value => \&version },
+
+ # OPTIONAL
+ 'description' => { value => \&string },
+ 'keywords' => { lazylist => { value => \&string } },
+ 'no_index' => $no_index_2,
+ 'optional_features' => {
+ 'map' => {
+ ':key' => {
+ name => \&string,
+ 'map' => {
+ description => { value => \&string },
+ prereqs => $prereq_map,
+ ':key' => { name => \&custom_2, value => \&anything },
+ }
+ }
+ }
+ },
+ 'prereqs' => $prereq_map,
+ 'provides' => {
+ 'map' => {
+ ':key' => {
+ name => \&module,
+ 'map' => {
+ file => { mandatory => 1, value => \&file },
+ version => { value => \&version },
+ ':key' => { name => \&custom_2, value => \&anything },
+ }
+ }
+ }
+ },
+ 'resources' => {
+ 'map' => {
+ license => { lazylist => { value => \&url } },
+ homepage => { value => \&url },
+ bugtracker => {
+ 'map' => {
+ web => { value => \&url },
+ mailto => { value => \&string},
+ ':key' => { name => \&custom_2, value => \&anything },
+ }
+ },
+ repository => {
+ 'map' => {
+ web => { value => \&url },
+ url => { value => \&url },
+ type => { value => \&string },
+ ':key' => { name => \&custom_2, value => \&anything },
+ }
+ },
+ ':key' => { value => \&string, name => \&custom_2 },
+ }
+ },
+
+ # CUSTOM -- additional user defined key/value pairs
+ # note we can only validate the key name, as the structure is user defined
+ ':key' => { name => \&custom_2, value => \&anything },
+ },
+
+'1.4' => {
+ 'meta-spec' => {
+ mandatory => 1,
+ 'map' => {
+ version => { mandatory => 1, value => \&version},
+ url => { mandatory => 1, value => \&urlspec },
+ ':key' => { name => \&string, value => \&anything },
+ },
+ },
+
+ 'name' => { mandatory => 1, value => \&string },
+ 'version' => { mandatory => 1, value => \&version },
+ 'abstract' => { mandatory => 1, value => \&string },
+ 'author' => { mandatory => 1, list => { value => \&string } },
+ 'license' => { mandatory => 1, value => \&license },
+ 'generated_by' => { mandatory => 1, value => \&string },
+
+ 'distribution_type' => { value => \&string },
+ 'dynamic_config' => { value => \&boolean },
+
+ 'requires' => $module_map1,
+ 'recommends' => $module_map1,
+ 'build_requires' => $module_map1,
+ 'configure_requires' => $module_map1,
+ 'conflicts' => $module_map2,
+
+ 'optional_features' => {
+ 'map' => {
+ ':key' => { name => \&string,
+ 'map' => { description => { value => \&string },
+ requires => $module_map1,
+ recommends => $module_map1,
+ build_requires => $module_map1,
+ conflicts => $module_map2,
+ ':key' => { name => \&string, value => \&anything },
+ }
+ }
+ }
+ },
+
+ 'provides' => {
+ 'map' => {
+ ':key' => { name => \&module,
+ 'map' => {
+ file => { mandatory => 1, value => \&file },
+ version => { value => \&version },
+ ':key' => { name => \&string, value => \&anything },
+ }
+ }
+ }
+ },
+
+ 'no_index' => $no_index_1_3,
+ 'private' => $no_index_1_3,
+
+ 'keywords' => { list => { value => \&string } },
+
+ 'resources' => {
+ 'map' => { license => { value => \&url },
+ homepage => { value => \&url },
+ bugtracker => { value => \&url },
+ repository => { value => \&url },
+ ':key' => { value => \&string, name => \&custom_1 },
+ }
+ },
+
+ # additional user defined key/value pairs
+ # note we can only validate the key name, as the structure is user defined
+ ':key' => { name => \&string, value => \&anything },
+},
+
+'1.3' => {
+ 'meta-spec' => {
+ mandatory => 1,
+ 'map' => {
+ version => { mandatory => 1, value => \&version},
+ url => { mandatory => 1, value => \&urlspec },
+ ':key' => { name => \&string, value => \&anything },
+ },
+ },
+
+ 'name' => { mandatory => 1, value => \&string },
+ 'version' => { mandatory => 1, value => \&version },
+ 'abstract' => { mandatory => 1, value => \&string },
+ 'author' => { mandatory => 1, list => { value => \&string } },
+ 'license' => { mandatory => 1, value => \&license },
+ 'generated_by' => { mandatory => 1, value => \&string },
+
+ 'distribution_type' => { value => \&string },
+ 'dynamic_config' => { value => \&boolean },
+
+ 'requires' => $module_map1,
+ 'recommends' => $module_map1,
+ 'build_requires' => $module_map1,
+ 'conflicts' => $module_map2,
+
+ 'optional_features' => {
+ 'map' => {
+ ':key' => { name => \&string,
+ 'map' => { description => { value => \&string },
+ requires => $module_map1,
+ recommends => $module_map1,
+ build_requires => $module_map1,
+ conflicts => $module_map2,
+ ':key' => { name => \&string, value => \&anything },
+ }
+ }
+ }
+ },
+
+ 'provides' => {
+ 'map' => {
+ ':key' => { name => \&module,
+ 'map' => {
+ file => { mandatory => 1, value => \&file },
+ version => { value => \&version },
+ ':key' => { name => \&string, value => \&anything },
+ }
+ }
+ }
+ },
+
+
+ 'no_index' => $no_index_1_3,
+ 'private' => $no_index_1_3,
+
+ 'keywords' => { list => { value => \&string } },
+
+ 'resources' => {
+ 'map' => { license => { value => \&url },
+ homepage => { value => \&url },
+ bugtracker => { value => \&url },
+ repository => { value => \&url },
+ ':key' => { value => \&string, name => \&custom_1 },
+ }
+ },
+
+ # additional user defined key/value pairs
+ # note we can only validate the key name, as the structure is user defined
+ ':key' => { name => \&string, value => \&anything },
+},
+
+# v1.2 is misleading, it seems to assume that a number of fields where created
+# within v1.1, when they were created within v1.2. This may have been an
+# original mistake, and that a v1.1 was retro fitted into the timeline, when
+# v1.2 was originally slated as v1.1. But I could be wrong ;)
+'1.2' => {
+ 'meta-spec' => {
+ mandatory => 1,
+ 'map' => {
+ version => { mandatory => 1, value => \&version},
+ url => { mandatory => 1, value => \&urlspec },
+ ':key' => { name => \&string, value => \&anything },
+ },
+ },
+
+
+ 'name' => { mandatory => 1, value => \&string },
+ 'version' => { mandatory => 1, value => \&version },
+ 'license' => { mandatory => 1, value => \&license },
+ 'generated_by' => { mandatory => 1, value => \&string },
+ 'author' => { mandatory => 1, list => { value => \&string } },
+ 'abstract' => { mandatory => 1, value => \&string },
+
+ 'distribution_type' => { value => \&string },
+ 'dynamic_config' => { value => \&boolean },
+
+ 'keywords' => { list => { value => \&string } },
+
+ 'private' => $no_index_1_2,
+ '$no_index' => $no_index_1_2,
+
+ 'requires' => $module_map1,
+ 'recommends' => $module_map1,
+ 'build_requires' => $module_map1,
+ 'conflicts' => $module_map2,
+
+ 'optional_features' => {
+ 'map' => {
+ ':key' => { name => \&string,
+ 'map' => { description => { value => \&string },
+ requires => $module_map1,
+ recommends => $module_map1,
+ build_requires => $module_map1,
+ conflicts => $module_map2,
+ ':key' => { name => \&string, value => \&anything },
+ }
+ }
+ }
+ },
+
+ 'provides' => {
+ 'map' => {
+ ':key' => { name => \&module,
+ 'map' => {
+ file => { mandatory => 1, value => \&file },
+ version => { value => \&version },
+ ':key' => { name => \&string, value => \&anything },
+ }
+ }
+ }
+ },
+
+ 'resources' => {
+ 'map' => { license => { value => \&url },
+ homepage => { value => \&url },
+ bugtracker => { value => \&url },
+ repository => { value => \&url },
+ ':key' => { value => \&string, name => \&custom_1 },
+ }
+ },
+
+ # additional user defined key/value pairs
+ # note we can only validate the key name, as the structure is user defined
+ ':key' => { name => \&string, value => \&anything },
+},
+
+# note that the 1.1 spec only specifies 'version' as mandatory
+'1.1' => {
+ 'name' => { value => \&string },
+ 'version' => { mandatory => 1, value => \&version },
+ 'license' => { value => \&license },
+ 'generated_by' => { value => \&string },
+
+ 'license_uri' => { value => \&url },
+ 'distribution_type' => { value => \&string },
+ 'dynamic_config' => { value => \&boolean },
+
+ 'private' => $no_index_1_1,
+
+ 'requires' => $module_map1,
+ 'recommends' => $module_map1,
+ 'build_requires' => $module_map1,
+ 'conflicts' => $module_map2,
+
+ # additional user defined key/value pairs
+ # note we can only validate the key name, as the structure is user defined
+ ':key' => { name => \&string, value => \&anything },
+},
+
+# note that the 1.0 spec doesn't specify optional or mandatory fields
+# but we will treat version as mandatory since otherwise META 1.0 is
+# completely arbitrary and pointless
+'1.0' => {
+ 'name' => { value => \&string },
+ 'version' => { mandatory => 1, value => \&version },
+ 'license' => { value => \&license },
+ 'generated_by' => { value => \&string },
+
+ 'license_uri' => { value => \&url },
+ 'distribution_type' => { value => \&string },
+ 'dynamic_config' => { value => \&boolean },
+
+ 'requires' => $module_map1,
+ 'recommends' => $module_map1,
+ 'build_requires' => $module_map1,
+ 'conflicts' => $module_map2,
+
+ # additional user defined key/value pairs
+ # note we can only validate the key name, as the structure is user defined
+ ':key' => { name => \&string, value => \&anything },
+},
+);
+
+#--------------------------------------------------------------------------#
+# Code
+#--------------------------------------------------------------------------#
+
+
+sub new {
+ my ($class,$data) = @_;
+
+ # create an attributes hash
+ my $self = {
+ 'data' => $data,
+ 'spec' => $data->{'meta-spec'}{'version'} || "1.0",
+ 'errors' => undef,
+ };
+
+ # create the object
+ return bless $self, $class;
+}
+
+
+sub is_valid {
+ my $self = shift;
+ my $data = $self->{data};
+ my $spec_version = $self->{spec};
+ $self->check_map($definitions{$spec_version},$data);
+ return ! $self->errors;
+}
+
+
+sub errors {
+ my $self = shift;
+ return () unless(defined $self->{errors});
+ return @{$self->{errors}};
+}
+
+
+my $spec_error = "Missing validation action in specification. "
+ . "Must be one of 'map', 'list', 'lazylist', or 'value'";
+
+sub check_map {
+ my ($self,$spec,$data) = @_;
+
+ if(ref($spec) ne 'HASH') {
+ $self->_error( "Unknown META specification, cannot validate." );
+ return;
+ }
+
+ if(ref($data) ne 'HASH') {
+ $self->_error( "Expected a map structure from string or file." );
+ return;
+ }
+
+ for my $key (keys %$spec) {
+ next unless($spec->{$key}->{mandatory});
+ next if(defined $data->{$key});
+ push @{$self->{stack}}, $key;
+ $self->_error( "Missing mandatory field, '$key'" );
+ pop @{$self->{stack}};
+ }
+
+ for my $key (keys %$data) {
+ push @{$self->{stack}}, $key;
+ if($spec->{$key}) {
+ if($spec->{$key}{value}) {
+ $spec->{$key}{value}->($self,$key,$data->{$key});
+ } elsif($spec->{$key}{'map'}) {
+ $self->check_map($spec->{$key}{'map'},$data->{$key});
+ } elsif($spec->{$key}{'list'}) {
+ $self->check_list($spec->{$key}{'list'},$data->{$key});
+ } elsif($spec->{$key}{'lazylist'}) {
+ $self->check_lazylist($spec->{$key}{'lazylist'},$data->{$key});
+ } else {
+ $self->_error( "$spec_error for '$key'" );
+ }
+
+ } elsif ($spec->{':key'}) {
+ $spec->{':key'}{name}->($self,$key,$key);
+ if($spec->{':key'}{value}) {
+ $spec->{':key'}{value}->($self,$key,$data->{$key});
+ } elsif($spec->{':key'}{'map'}) {
+ $self->check_map($spec->{':key'}{'map'},$data->{$key});
+ } elsif($spec->{':key'}{'list'}) {
+ $self->check_list($spec->{':key'}{'list'},$data->{$key});
+ } elsif($spec->{':key'}{'lazylist'}) {
+ $self->check_lazylist($spec->{':key'}{'lazylist'},$data->{$key});
+ } else {
+ $self->_error( "$spec_error for ':key'" );
+ }
+
+
+ } else {
+ $self->_error( "Unknown key, '$key', found in map structure" );
+ }
+ pop @{$self->{stack}};
+ }
+}
+
+# if it's a string, make it into a list and check the list
+sub check_lazylist {
+ my ($self,$spec,$data) = @_;
+
+ if ( defined $data && ! ref($data) ) {
+ $data = [ $data ];
+ }
+
+ $self->check_list($spec,$data);
+}
+
+sub check_list {
+ my ($self,$spec,$data) = @_;
+
+ if(ref($data) ne 'ARRAY') {
+ $self->_error( "Expected a list structure" );
+ return;
+ }
+
+ if(defined $spec->{mandatory}) {
+ if(!defined $data->[0]) {
+ $self->_error( "Missing entries from mandatory list" );
+ }
+ }
+
+ for my $value (@$data) {
+ push @{$self->{stack}}, $value || "<undef>";
+ if(defined $spec->{value}) {
+ $spec->{value}->($self,'list',$value);
+ } elsif(defined $spec->{'map'}) {
+ $self->check_map($spec->{'map'},$value);
+ } elsif(defined $spec->{'list'}) {
+ $self->check_list($spec->{'list'},$value);
+ } elsif(defined $spec->{'lazylist'}) {
+ $self->check_lazylist($spec->{'lazylist'},$value);
+ } elsif ($spec->{':key'}) {
+ $self->check_map($spec,$value);
+ } else {
+ $self->_error( "$spec_error associated with '$self->{stack}[-2]'" );
+ }
+ pop @{$self->{stack}};
+ }
+}
+
+
+sub header {
+ my ($self,$key,$value) = @_;
+ if(defined $value) {
+ return 1 if($value && $value =~ /^--- #YAML:1.0/);
+ }
+ $self->_error( "file does not have a valid YAML header." );
+ return 0;
+}
+
+sub release_status {
+ my ($self,$key,$value) = @_;
+ if(defined $value) {
+ my $version = $self->{data}{version} || '';
+ if ( $version =~ /_/ ) {
+ return 1 if ( $value =~ /\A(?:testing|unstable)\z/ );
+ $self->_error( "'$value' for '$key' is invalid for version '$version'" );
+ }
+ else {
+ return 1 if ( $value =~ /\A(?:stable|testing|unstable)\z/ );
+ $self->_error( "'$value' for '$key' is invalid" );
+ }
+ }
+ else {
+ $self->_error( "'$key' is not defined" );
+ }
+ return 0;
+}
+
+# _uri_split taken from URI::Split by Gisle Aas, Copyright 2003
+sub _uri_split {
+ return $_[0] =~ m,(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?,;
+}
+
+sub url {
+ my ($self,$key,$value) = @_;
+ if(defined $value) {
+ my ($scheme, $auth, $path, $query, $frag) = _uri_split($value);
+ unless ( defined $scheme && length $scheme ) {
+ $self->_error( "'$value' for '$key' does not have a URL scheme" );
+ return 0;
+ }
+ unless ( defined $auth && length $auth ) {
+ $self->_error( "'$value' for '$key' does not have a URL authority" );
+ return 0;
+ }
+ return 1;
+ }
+ $value ||= '';
+ $self->_error( "'$value' for '$key' is not a valid URL." );
+ return 0;
+}
+
+sub urlspec {
+ my ($self,$key,$value) = @_;
+ if(defined $value) {
+ return 1 if($value && $known_specs{$self->{spec}} eq $value);
+ if($value && $known_urls{$value}) {
+ $self->_error( 'META specification URL does not match version' );
+ return 0;
+ }
+ }
+ $self->_error( 'Unknown META specification' );
+ return 0;
+}
+
+sub anything { return 1 }
+
+sub string {
+ my ($self,$key,$value) = @_;
+ if(defined $value) {
+ return 1 if($value || $value =~ /^0$/);
+ }
+ $self->_error( "value is an undefined string" );
+ return 0;
+}
+
+sub string_or_undef {
+ my ($self,$key,$value) = @_;
+ return 1 unless(defined $value);
+ return 1 if($value || $value =~ /^0$/);
+ $self->_error( "No string defined for '$key'" );
+ return 0;
+}
+
+sub file {
+ my ($self,$key,$value) = @_;
+ return 1 if(defined $value);
+ $self->_error( "No file defined for '$key'" );
+ return 0;
+}
+
+sub exversion {
+ my ($self,$key,$value) = @_;
+ if(defined $value && ($value || $value =~ /0/)) {
+ my $pass = 1;
+ for(split(",",$value)) { $self->version($key,$_) or ($pass = 0); }
+ return $pass;
+ }
+ $value = '<undef>' unless(defined $value);
+ $self->_error( "'$value' for '$key' is not a valid version." );
+ return 0;
+}
+
+sub version {
+ my ($self,$key,$value) = @_;
+ if(defined $value) {
+ return 0 unless($value || $value =~ /0/);
+ return 1 if($value =~ /^\s*((<|<=|>=|>|!=|==)\s*)?v?\d+((\.\d+((_|\.)\d+)?)?)/);
+ } else {
+ $value = '<undef>';
+ }
+ $self->_error( "'$value' for '$key' is not a valid version." );
+ return 0;
+}
+
+sub boolean {
+ my ($self,$key,$value) = @_;
+ if(defined $value) {
+ return 1 if($value =~ /^(0|1|true|false)$/);
+ } else {
+ $value = '<undef>';
+ }
+ $self->_error( "'$value' for '$key' is not a boolean value." );
+ return 0;
+}
+
+my %v1_licenses = (
+ 'perl' => 'http://dev.perl.org/licenses/',
+ 'gpl' => 'http://www.opensource.org/licenses/gpl-license.php',
+ 'apache' => 'http://apache.org/licenses/LICENSE-2.0',
+ 'artistic' => 'http://opensource.org/licenses/artistic-license.php',
+ 'artistic_2' => 'http://opensource.org/licenses/artistic-license-2.0.php',
+ 'lgpl' => 'http://www.opensource.org/licenses/lgpl-license.phpt',
+ 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
+ 'gpl' => 'http://www.opensource.org/licenses/gpl-license.php',
+ 'mit' => 'http://opensource.org/licenses/mit-license.php',
+ 'mozilla' => 'http://opensource.org/licenses/mozilla1.1.php',
+ 'open_source' => undef,
+ 'unrestricted' => undef,
+ 'restrictive' => undef,
+ 'unknown' => undef,
+);
+
+my %v2_licenses = map { $_ => 1 } qw(
+ agpl_3
+ apache_1_1
+ apache_2_0
+ artistic_1
+ artistic_2
+ bsd
+ freebsd
+ gfdl_1_2
+ gfdl_1_3
+ gpl_1
+ gpl_2
+ gpl_3
+ lgpl_2_1
+ lgpl_3_0
+ mit
+ mozilla_1_0
+ mozilla_1_1
+ openssl
+ perl_5
+ qpl_1_0
+ ssleay
+ sun
+ zlib
+ open_source
+ restricted
+ unrestricted
+ unknown
+);
+
+sub license {
+ my ($self,$key,$value) = @_;
+ my $licenses = $self->{spec} < 2 ? \%v1_licenses : \%v2_licenses;
+ if(defined $value) {
+ return 1 if($value && exists $licenses->{$value});
+ } else {
+ $value = '<undef>';
+ }
+ $self->_error( "License '$value' is invalid" );
+ return 0;
+}
+
+sub custom_1 {
+ my ($self,$key) = @_;
+ if(defined $key) {
+ # a valid user defined key should be alphabetic
+ # and contain at least one capital case letter.
+ return 1 if($key && $key =~ /^[_a-z]+$/i && $key =~ /[A-Z]/);
+ } else {
+ $key = '<undef>';
+ }
+ $self->_error( "Custom resource '$key' must be in CamelCase." );
+ return 0;
+}
+
+sub custom_2 {
+ my ($self,$key) = @_;
+ if(defined $key) {
+ return 1 if($key && $key =~ /^x_/i); # user defined
+ } else {
+ $key = '<undef>';
+ }
+ $self->_error( "Custom key '$key' must begin with 'x_' or 'X_'." );
+ return 0;
+}
+
+sub identifier {
+ my ($self,$key) = @_;
+ if(defined $key) {
+ return 1 if($key && $key =~ /^([a-z][_a-z]+)$/i); # spec 2.0 defined
+ } else {
+ $key = '<undef>';
+ }
+ $self->_error( "Key '$key' is not a legal identifier." );
+ return 0;
+}
+
+sub module {
+ my ($self,$key) = @_;
+ if(defined $key) {
+ return 1 if($key && $key =~ /^[A-Za-z0-9_]+(::[A-Za-z0-9_]+)*$/);
+ } else {
+ $key = '<undef>';
+ }
+ $self->_error( "Key '$key' is not a legal module name." );
+ return 0;
+}
+
+my @valid_phases = qw/ configure build test runtime develop /;
+sub phase {
+ my ($self,$key) = @_;
+ if(defined $key) {
+ return 1 if( length $key && grep { $key eq $_ } @valid_phases );
+ return 1 if $key =~ /x_/i;
+ } else {
+ $key = '<undef>';
+ }
+ $self->_error( "Key '$key' is not a legal phase." );
+ return 0;
+}
+
+my @valid_relations = qw/ requires recommends suggests conflicts /;
+sub relation {
+ my ($self,$key) = @_;
+ if(defined $key) {
+ return 1 if( length $key && grep { $key eq $_ } @valid_relations );
+ return 1 if $key =~ /x_/i;
+ } else {
+ $key = '<undef>';
+ }
+ $self->_error( "Key '$key' is not a legal prereq relationship." );
+ return 0;
+}
+
+sub _error {
+ my $self = shift;
+ my $mess = shift;
+
+ $mess .= ' ('.join(' -> ',@{$self->{stack}}).')' if($self->{stack});
+ $mess .= " [Validation: $self->{spec}]";
+
+ push @{$self->{errors}}, $mess;
+}
+
+1;
+
+
+
+=pod
+
+=head1 NAME
+
+CPAN::Meta::Validator - validate CPAN distribution metadata structures
+
+=head1 VERSION
+
+version 2.110440
+
+=head1 SYNOPSIS
+
+ my $struct = decode_json_file('META.json');
+
+ my $cmv = CPAN::Meta::Validator->new( $struct );
+
+ unless ( $cmv->is_valid ) {
+ my $msg = "Invalid META structure. Errors found:\n";
+ $msg .= join( "\n", $cmv->errors );
+ die $msg;
+ }
+
+=head1 DESCRIPTION
+
+This module validates a CPAN Meta structure against the version of the
+the specification claimed in the C<meta-spec> field of the structure.
+
+=head1 METHODS
+
+=head2 new
+
+ my $cmv = CPAN::Meta::Validator->new( $struct )
+
+The constructor must be passed a metadata structure.
+
+=head2 is_valid
+
+ if ( $cmv->is_valid ) {
+ ...
+ }
+
+Returns a boolean value indicating whether the metadata provided
+is valid.
+
+=head2 errors
+
+ warn( join "\n", $cmv->errors );
+
+Returns a list of errors seen during validation.
+
+=begin internals
+
+=head2 Check Methods
+
+=over
+
+=item * check_map($spec,$data)
+
+Checks whether a map (or hash) part of the data structure conforms to the
+appropriate specification definition.
+=item * check_list($spec,$data)
+
+Checks whether a list (or array) part of the data structure conforms to
+the appropriate specification definition.
+=item * check_lazylist($spec,$data)
+
+Checks whether a list conforms, but converts strings to a single-element list
+=back
+
+=head2 Validator Methods
+
+=over
+
+=item * header($self,$key,$value)
+
+Validates that the header is valid.
+
+Note: No longer used as we now read the data structure, not the file.=item * url($self,$key,$value)
+
+Validates that a given value is in an acceptable URL format
+=item * urlspec($self,$key,$value)
+
+Validates that the URL to a META specification is a known one.
+=item * string_or_undef($self,$key,$value)
+
+Validates that the value is either a string or an undef value. Bit of a
+catchall function for parts of the data structure that are completely user
+defined.
+=item * string($self,$key,$value)
+
+Validates that a string exists for the given key.
+=item * file($self,$key,$value)
+
+Validate that a file is passed for the given key. This may be made more
+thorough in the future. For now it acts like \&string.
+=item * exversion($self,$key,$value)
+
+Validates a list of versions, e.g. '<= 5, >=2, ==3, !=4, >1, <6, 0'.
+=item * version($self,$key,$value)
+
+Validates a single version string. Versions of the type '5.8.8' and '0.00_00'
+are both valid. A leading 'v' like 'v1.2.3' is also valid.
+=item * boolean($self,$key,$value)
+
+Validates for a boolean value. Currently these values are '1', '0', 'true',
+'false', however the latter 2 may be removed.
+=item * license($self,$key,$value)
+
+Validates that a value is given for the license. Returns 1 if an known license
+type, or 2 if a value is given but the license type is not a recommended one.
+=item * custom_1($self,$key,$value)
+
+Validates that the given key is in CamelCase, to indicate a user defined
+keyword and only has characters in the class [-_a-zA-Z]. In version 1.X
+of the spec, this was only explicitly stated for 'resources'.
+=item * custom_2($self,$key,$value)
+
+Validates that the given key begins with 'x_' or 'X_', to indicate a user
+defined keyword and only has characters in the class [-_a-zA-Z]
+=item * identifier($self,$key,$value)
+
+Validates that key is in an acceptable format for the META specification,
+for an identifier, i.e. any that matches the regular expression
+qr/[a-z][a-z_]/i.
+=item * module($self,$key,$value)
+
+Validates that a given key is in an acceptable module name format, e.g.
+'Test::CPAN::Meta::Version'.
+=back
+
+=end internals
+
+=head1 BUGS
+
+Please report any bugs or feature using the CPAN Request Tracker.
+Bugs can be submitted through the web interface at
+L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta>
+
+When submitting a bug or request, please include a test-file or a patch to an
+existing test-file that illustrates the bug or desired feature.
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Ricardo Signes <rjbs@cpan.org>
+
+=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
+
+
+__END__
+
+
+
diff --git a/cpan/CPAN-Meta/t/converter-bad.t b/cpan/CPAN-Meta/t/converter-bad.t
new file mode 100644
index 0000000000..1225e42184
--- /dev/null
+++ b/cpan/CPAN-Meta/t/converter-bad.t
@@ -0,0 +1,71 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+use CPAN::Meta::Validator;
+use CPAN::Meta::Converter;
+use File::Spec;
+use IO::Dir;
+use Parse::CPAN::Meta 1.4400;
+
+my $data_dir = IO::Dir->new( 't/data-bad' );
+my @files = sort grep { /^\w/ } $data_dir->read;
+
+sub _spec_version { return $_[0]->{'meta-spec'}{version} || "1.0" }
+
+#use Data::Dumper;
+
+for my $f ( reverse sort @files ) {
+ my $path = File::Spec->catfile('t','data-bad',$f);
+ my $original = Parse::CPAN::Meta->load_file( $path );
+ ok( $original, "loaded $f" );
+ my $original_v = _spec_version($original);
+ # UPCONVERSION
+ if ( _spec_version( $original ) lt '2' ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => 2 );
+ is ( _spec_version($converted), 2, "up converted spec version $original_v to spec version 2");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "up converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+ }
+ # UPCONVERSION - partial
+ if ( _spec_version( $original ) lt '1.4' ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => '1.4' );
+ is ( _spec_version($converted), 1.4, "up converted spec version $original_v to spec version 1.4");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "up converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+ }
+ # DOWNCONVERSION - partial
+ if ( _spec_version( $original ) gt '1.2' ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => '1.2' );
+ is ( _spec_version($converted), '1.2', "down converted spec version $original_v to spec version 1.2");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "down converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+ }
+ # DOWNCONVERSION
+ if ( _spec_version( $original ) gt '1.0' ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => '1.0' );
+ is ( _spec_version($converted), '1.0', "down converted spec version $original_v to spec version 1.0");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "down converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+ }
+}
+
+done_testing;
+
diff --git a/cpan/CPAN-Meta/t/converter-fail.t b/cpan/CPAN-Meta/t/converter-fail.t
new file mode 100644
index 0000000000..3a82f2d5af
--- /dev/null
+++ b/cpan/CPAN-Meta/t/converter-fail.t
@@ -0,0 +1,39 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+use CPAN::Meta::Validator;
+use CPAN::Meta::Converter;
+use File::Spec;
+use IO::Dir;
+use Parse::CPAN::Meta 1.4400;
+
+my $data_dir = IO::Dir->new( 't/data-fail' );
+my @files = sort grep { /^\w/ } $data_dir->read;
+
+sub _spec_version { return $_[0]->{'meta-spec'}{version} || "1.0" }
+
+use Data::Dumper;
+
+for my $f ( reverse sort @files ) {
+ my $path = File::Spec->catfile('t','data-fail',$f);
+ my $original = Parse::CPAN::Meta->load_file( $path );
+ ok( $original, "loaded invalid $f" );
+ my $original_v = _spec_version($original);
+ # UPCONVERSION
+ if ( _spec_version( $original ) lt '2' ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ eval { $cmc->convert( version => 2 ) };
+ ok ( $@, "error thrown up converting" );
+ }
+ # DOWNCONVERSION
+ if ( _spec_version( $original ) gt '1.0' ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ eval { $cmc->convert( version => '1.0' ) };
+ ok ( $@, "error thrown down converting" );
+ }
+}
+
+done_testing;
+
diff --git a/cpan/CPAN-Meta/t/converter.t b/cpan/CPAN-Meta/t/converter.t
new file mode 100644
index 0000000000..53ea5ee6d6
--- /dev/null
+++ b/cpan/CPAN-Meta/t/converter.t
@@ -0,0 +1,139 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+use CPAN::Meta::Validator;
+use CPAN::Meta::Converter;
+use File::Spec;
+use IO::Dir;
+use Parse::CPAN::Meta 1.4400;
+
+my $data_dir = IO::Dir->new( 't/data' );
+my @files = sort grep { /^\w/ } $data_dir->read;
+
+sub _spec_version { return $_[0]->{'meta-spec'}{version} || "1.0" }
+
+#use Data::Dumper;
+
+for my $f ( reverse sort @files ) {
+ my $path = File::Spec->catfile('t','data',$f);
+ my $original = Parse::CPAN::Meta->load_file( $path );
+ ok( $original, "loaded $f" );
+ my $original_v = _spec_version($original);
+ # UPCONVERSION
+ {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => 2 );
+ is ( _spec_version($converted), 2, "up converted spec version $original_v to spec version 2");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "up converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+ }
+ # UPCONVERSION - partial
+ if ( _spec_version( $original ) < 2 ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => '1.4' );
+ is ( _spec_version($converted), 1.4, "up converted spec version $original_v to spec version 1.4");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "up converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+ }
+ # DOWNCONVERSION - partial
+ if ( _spec_version( $original ) >= 1.2 ) {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => '1.2' );
+ is ( _spec_version($converted), '1.2', "down converted spec version $original_v to spec version 1.2");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "down converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+
+ if (_spec_version( $original ) == 2) {
+ is_deeply(
+ $converted->{build_requires},
+ {
+ 'Test::More' => '0.88',
+ 'Build::Requires' => '1.1',
+ 'Test::Requires' => '1.2',
+ },
+ "downconversion from 2 merge test and build requirements",
+ );
+ }
+ }
+ # DOWNCONVERSION
+ {
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => '1.0' );
+ is ( _spec_version($converted), '1.0', "down converted spec version $original_v to spec version 1.0");
+ my $cmv = CPAN::Meta::Validator->new( $converted );
+ ok ( $cmv->is_valid, "down converted META is valid" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors )
+# . "\nMETA:\n" . Dumper($converted)
+ );
+
+ unless ($original_v eq '1.0') {
+ like ( $converted->{generated_by},
+ qr(\Q$original->{generated_by}\E, CPAN::Meta::Converter version \S+$),
+ "added converter mark to generated_by",
+ );
+ }
+ }
+}
+
+# specific test for custom key handling
+{
+ my $path = File::Spec->catfile('t','data','META-1_4.yml');
+ my $original = Parse::CPAN::Meta->load_file( $path );
+ ok( $original, "loaded META-1_4.yml" );
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $up_converted = $cmc->convert( version => 2 );
+ ok ( $up_converted->{x_whatever} && ! $up_converted->{'x-whatever'},
+ "up converted 'x-' to 'x_'"
+ );
+ ok ( $up_converted->{x_whatelse},
+ "up converted 'x_' as 'x_'"
+ );
+ ok ( $up_converted->{x_WhatNow} && ! $up_converted->{XWhatNow},
+ "up converted 'XFoo' to 'x_Foo'"
+ ) or diag join("\n", keys %$up_converted);
+}
+
+# specific test for custom key handling
+{
+ my $path = File::Spec->catfile('t','data','META-2.json');
+ my $original = Parse::CPAN::Meta->load_file( $path );
+ ok( $original, "loaded META-2.json" );
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $up_converted = $cmc->convert( version => 1.4 );
+ ok ( $up_converted->{x_whatever},
+ "down converted 'x_' as 'x_'"
+ );
+}
+
+# specific test for upconverting resources
+{
+ my $path = File::Spec->catfile('t','data','resources.yml');
+ my $original = Parse::CPAN::Meta->load_file( $path );
+ ok( $original, "loaded resources.yml" );
+ my $cmc = CPAN::Meta::Converter->new( $original );
+ my $converted = $cmc->convert( version => 2 );
+ is_deeply(
+ $converted->{resources},
+ { x_MailingList => 'http://groups.google.com/group/www-mechanize-users',
+ x_Repository => 'http://code.google.com/p/www-mechanize/source',
+ homepage => 'http://code.google.com/p/www-mechanize/',
+ bugtracker => {web => 'http://code.google.com/p/www-mechanize/issues/list',},
+ license => ['http://dev.perl.org/licenses/'],
+ },
+ "upconversion of resources"
+ );
+}
+
+done_testing;
+
diff --git a/cpan/CPAN-Meta/t/data-bad/107650337-META.yml b/cpan/CPAN-Meta/t/data-bad/107650337-META.yml
new file mode 100644
index 0000000000..84080ef657
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/107650337-META.yml
@@ -0,0 +1,25 @@
+---
+name: FabForce-DBDesigner4-DBIC
+version: 0.0802
+author:
+ - 'Renee Baecker <module@renee-baecker.de>'
+abstract: create DBIC scheme for DBDesigner4 xml file
+license: artistic2
+requires:
+ FabForce::DBDesigner4: 0.3
+ File::Spec: 3.12
+build_requires:
+ Carp: 0
+ Test::CheckManifest: 1
+ Test::More: 0
+generated_by: Module::Build version 0.2808
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
+provides:
+ FabForce::DBDesigner4::DBIC:
+ file: lib/FabForce/DBDesigner4/DBIC.pm
+ version: 0.0802
+resources:
+ license: http://dev.perl.org/licenses/
+
diff --git a/cpan/CPAN-Meta/t/data-bad/1122575719-META.yml b/cpan/CPAN-Meta/t/data-bad/1122575719-META.yml
new file mode 100644
index 0000000000..f37cb284a7
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/1122575719-META.yml
@@ -0,0 +1,28 @@
+---
+abstract: 'Generate Catalyst application menus'
+author:
+ - 'David P.C. Wollmann <converter42@gmail.com>'
+build_requires:
+ ExtUtils::MakeMaker: 6.42
+ Test::More: 0
+configure_requires:
+ ExtUtils::MakeMaker: 6.42
+distribution_type: module
+generated_by: 'Module::Install version 0.87'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: CatalystX-Menu-Tree
+no_index:
+ directory:
+ - inc
+ - t
+ inc: []
+requires:
+ Catalyst::Runtime: 0
+ MRO::Compat: 0
+ perl: 5.8.0
+resources:
+ license: http://dev.perl.org/licenses/
+version: 0.02
diff --git a/cpan/CPAN-Meta/t/data-bad/1206545041-META.yml b/cpan/CPAN-Meta/t/data-bad/1206545041-META.yml
new file mode 100644
index 0000000000..a8be520dd5
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/1206545041-META.yml
@@ -0,0 +1,105 @@
+---
+name: PDF-Template
+version: 0.29_02
+author: ~
+abstract: PDF::Template
+license: perl
+requires:
+ Encode: 0.01
+ PDF::Writer: 0.05
+ perl: 5.6.0
+build_requires:
+ IO::Scalar: 0.01
+ Test::More: 0.47
+provides:
+ PDF::Template:
+ file: lib/PDF/Template.pm
+ version: 0.29_02
+ PDF::Template::Base:
+ file: lib/PDF/Template/Base.pm
+ version: ~
+ PDF::Template::Constants:
+ file: lib/PDF/Template/Constants.pm
+ version: ~
+ PDF::Template::Container:
+ file: lib/PDF/Template/Container.pm
+ version: ~
+ PDF::Template::Container::Always:
+ file: lib/PDF/Template/Container/Always.pm
+ version: ~
+ PDF::Template::Container::Conditional:
+ file: lib/PDF/Template/Container/Conditional.pm
+ version: ~
+ PDF::Template::Container::Font:
+ file: lib/PDF/Template/Container/Font.pm
+ version: ~
+ PDF::Template::Container::Footer:
+ file: lib/PDF/Template/Container/Footer.pm
+ version: ~
+ PDF::Template::Container::Header:
+ file: lib/PDF/Template/Container/Header.pm
+ version: ~
+ PDF::Template::Container::Loop:
+ file: lib/PDF/Template/Container/Loop.pm
+ version: ~
+ PDF::Template::Container::Margin:
+ file: lib/PDF/Template/Container/Margin.pm
+ version: ~
+ PDF::Template::Container::PageDef:
+ file: lib/PDF/Template/Container/PageDef.pm
+ version: ~
+ PDF::Template::Container::PdfTemplate:
+ file: lib/PDF/Template/Container/PdfTemplate.pm
+ version: ~
+ PDF::Template::Container::Row:
+ file: lib/PDF/Template/Container/Row.pm
+ version: ~
+ PDF::Template::Container::Scope:
+ file: lib/PDF/Template/Container/Scope.pm
+ version: ~
+ PDF::Template::Container::Section:
+ file: lib/PDF/Template/Container/Section.pm
+ version: ~
+ PDF::Template::Context:
+ file: lib/PDF/Template/Context.pm
+ version: ~
+ PDF::Template::Element:
+ file: lib/PDF/Template/Element.pm
+ version: ~
+ PDF::Template::Element::Bookmark:
+ file: lib/PDF/Template/Element/Bookmark.pm
+ version: ~
+ PDF::Template::Element::Circle:
+ file: lib/PDF/Template/Element/Circle.pm
+ version: ~
+ PDF::Template::Element::HorizontalRule:
+ file: lib/PDF/Template/Element/HorizontalRule.pm
+ version: ~
+ PDF::Template::Element::Image:
+ file: lib/PDF/Template/Element/Image.pm
+ version: ~
+ PDF::Template::Element::Line:
+ file: lib/PDF/Template/Element/Line.pm
+ version: ~
+ PDF::Template::Element::PageBreak:
+ file: lib/PDF/Template/Element/PageBreak.pm
+ version: ~
+ PDF::Template::Element::TextBox:
+ file: lib/PDF/Template/Element/TextBox.pm
+ version: ~
+ PDF::Template::Element::Var:
+ file: lib/PDF/Template/Element/Var.pm
+ version: ~
+ PDF::Template::Element::Weblink:
+ file: lib/PDF/Template/Element/Weblink.pm
+ version: ~
+ PDF::Template::Factory:
+ file: lib/PDF/Template/Factory.pm
+ version: ~
+ PDF::Template::Iterator:
+ file: lib/PDF/Template/Iterator.pm
+ version: ~
+ PDF::Template::TextObject:
+ file: lib/PDF/Template/TextObject.pm
+ version: ~
+generated_by: Module::Build version 0.2701
diff --git a/cpan/CPAN-Meta/t/data-bad/1598804075-META.yml b/cpan/CPAN-Meta/t/data-bad/1598804075-META.yml
new file mode 100644
index 0000000000..868c8cd587
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/1598804075-META.yml
@@ -0,0 +1,19 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: XML-RDB
+version: 1.3
+version_from: RDB.pm
+installdirs: site
+requires:
+ Data::Dumper: 0
+ DBI: 1.35
+ DBIx::DBSchema: .16
+ DBIx::Recordset: .23
+ DBIx::Sequence: .04
+ Getopt::Std: 0
+ IO::File: 1.08
+ URI::Escape: 3.16
+ XML::DOM: 1.29
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.30
diff --git a/cpan/CPAN-Meta/t/data-bad/1927486199-META.yml b/cpan/CPAN-Meta/t/data-bad/1927486199-META.yml
new file mode 100644
index 0000000000..9b5d8bd3b1
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/1927486199-META.yml
@@ -0,0 +1,13 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: WWW-phpBB-Mod-Installer
+version: 0.03
+version_from: lib/WWW/phpBB/Mod/Installer.pm
+installdirs: site
+requires:
+ DBD::mysql: 3.0002
+ DBI: 1.5
+ XML::Xerces: -4
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.30
diff --git a/cpan/CPAN-Meta/t/data-bad/1985684504-META.yml b/cpan/CPAN-Meta/t/data-bad/1985684504-META.yml
new file mode 100644
index 0000000000..4d79f42be1
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/1985684504-META.yml
@@ -0,0 +1,21 @@
+--- #YAML:1.0
+name: Squatting
+version: 0.30
+abstract: A Camping-inspired Web Microframework for Perl
+license: mit
+generated_by: ExtUtils::MakeMaker version 6.36
+distribution_type: module
+requires:
+ Continuity: 0.991
+ Data::Dump: 0
+ HTTP::Daemon: 0
+ JSON::XS: 0
+ Shell::Perl: 0
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
+author:
+ - John BEPPU <beppu@cpan.org>
+no_index:
+ - eg
+ - t
diff --git a/cpan/CPAN-Meta/t/data-bad/1985980974-META.yml b/cpan/CPAN-Meta/t/data-bad/1985980974-META.yml
new file mode 100644
index 0000000000..7814f05ce3
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/1985980974-META.yml
@@ -0,0 +1,20 @@
+---
+abstract: 'A Form::Sensible::Form::Reflector subclass to reflect off of DBIC schema classes'
+author:
+ - 'Devin Austin <dhoss@cpan.org>'
+generated_by: 'Dist::Zilla version 1.100160'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: Form-Sensible-Reflector-DBIC
+requires:
+ DBIx::Class: "\"\""
+ Data::Dumper: "\"\""
+ DateTime: "\"\""
+ ExtUtils::MakeMaker: 6.11
+ Form::Sensible: "\"\""
+ Moose: 0.93
+ SQL::Translator: 0.11002
+ Test::Simple: 0.88
+version: 0.0341
diff --git a/cpan/CPAN-Meta/t/data-bad/2031017050-META.yml b/cpan/CPAN-Meta/t/data-bad/2031017050-META.yml
new file mode 100644
index 0000000000..c7b3930720
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/2031017050-META.yml
@@ -0,0 +1,29 @@
+--- #YAML:1.0
+name: Forks-Super
+version: 0.16
+abstract: extensions and convenience methods for managing background processes.
+author:
+ - Marty O'Brien <mob@cpan.org>
+license: perl
+distribution_type: module
+configure_requires:
+ ExtUtils::MakeMaker: 0
+build_requires:
+ ExtUtils::MakeMaker: 0
+requires:
+ Test::More: 0
+no_index:
+ directory:
+ - t
+ - inc
+generated_by: ExtUtils::MakeMaker version 6.55_02
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+recommends:
+ - Time::HiRes
+ - 0
+ - YAML
+ - 0
+ - Win32::Process
+ - 0
diff --git a/cpan/CPAN-Meta/t/data-bad/284247103-META.yml b/cpan/CPAN-Meta/t/data-bad/284247103-META.yml
new file mode 100644
index 0000000000..e7390a2bff
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/284247103-META.yml
@@ -0,0 +1,63 @@
+--- #YAML:1.0
+
+meta-spec:
+ version: 1.2
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+
+name: Daizu
+version: 0.3
+abstract: Web publishing system built on Subversion
+license: gpl
+
+resources:
+ homepage: http://www.daizucms.org/
+ license: http://www.gnu.org/licenses/gpl.html
+
+author:
+ - 'Geoff Richards <geoff@laxan.com>'
+
+requires:
+ Carp::Assert: 0
+ Compress::Zlib: 0
+ DBD::Pg: 0
+ DateTime: 0
+ DateTime::Format::Pg: 0.08
+ Digest::SHA1: 0
+ File::MMagic: 0
+ HTML::Entities: 1.32
+ HTML::Parser: 0
+ HTML::Tagset: 0
+ Image::Size: 0
+ Math::Round: 0.03
+ Path::Class: 0.02
+ SVN::Ra: 0
+ Template: 2.15
+ URI: 0
+ XML::LibXML: 1.59
+
+build_requires:
+ Module::Build: 0
+
+optional_features:
+ - syntax-highlight:
+ description: Automatically syntax-highlight example code in articles
+ requires:
+ Text::VimColor: 0.09
+ - picture-article:
+ description: Publish pictures as articles, with automatic thumbnails
+ requires:
+ Image::Magick: 0
+ - related-links:
+ description: Add a Related Links box to pages for articles
+ requires:
+ Template::Plugin::Class: 0
+
+no_index:
+ file:
+ - test-repos.dump
+
+dynamic_config: 0
+
+generated_by: Geoff Richards
+
+# vi:ts=4 sw=4 expandtab
diff --git a/cpan/CPAN-Meta/t/data-bad/344981821-META.yml b/cpan/CPAN-Meta/t/data-bad/344981821-META.yml
new file mode 100644
index 0000000000..7a51e87ebc
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/344981821-META.yml
@@ -0,0 +1,26 @@
+---
+abstract: ''
+author:
+ - 'Tokuhiro Matsuno C<< <tokuhiro __at__ mobilefactory.jp> >>'
+build_requires:
+ Class::DBI: 0
+ Class::DBI::Pager: 0
+ Sledge::TestPages: 0
+ Test::Base: 0
+ Test::More: 0
+ YAML: 0
+distribution_type: module
+generated_by: 'Module::Install version 0.75'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.3.html
+ version: 1.3
+name: Sledge-Plugin-Pager
+no_index:
+ directory:
+ - inc
+ - t
+requires:
+ Lingua::EN::Inflect: 0
+ String::CamelCase: 0
+version: 0.02
diff --git a/cpan/CPAN-Meta/t/data-bad/35478989-META.yml b/cpan/CPAN-Meta/t/data-bad/35478989-META.yml
new file mode 100644
index 0000000000..42e0c1081a
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/35478989-META.yml
@@ -0,0 +1,17 @@
+--- #YAML:1.0
+name: oEdtk
+version: 0.42
+abstract: ~
+license: ~
+author: ~
+generated_by: ExtUtils::MakeMaker version 6.44
+distribution_type: module
+requires:
+ Config::IniFiles: 2.3
+ DBI: 1.6
+ Spreadsheet::WriteExcel: 1
+ Sys::Hostname: Digest::MD5
+ Term::ReadKey: POSIX
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.3.html
+ version: 1.3
diff --git a/cpan/CPAN-Meta/t/data-bad/476602558-META.yml b/cpan/CPAN-Meta/t/data-bad/476602558-META.yml
new file mode 100644
index 0000000000..ee78dc4085
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/476602558-META.yml
@@ -0,0 +1,28 @@
+---
+abstract: 'Benchmarking with statistical confidence'
+author:
+ - '-2001 Andrew Ho.'
+build_requires:
+ ExtUtils::MakeMaker: 6.42
+ Test::More: 0
+configure_requires:
+ ExtUtils::MakeMaker: 6.42
+distribution_type: module
+generated_by: 'Module::Install version 0.91'
+license: gpl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+module_name: Benchmark::Timer
+name: Benchmark-Timer
+no_index:
+ delta.pl: []
+ directory:
+ - inc
+ - t
+requires:
+ Time::HiRes: 0
+ perl: 5.005
+resources:
+ license: http://opensource.org/licenses/gpl-license.php
+version: 0.7102
diff --git a/cpan/CPAN-Meta/t/data-bad/98042513-META.yml b/cpan/CPAN-Meta/t/data-bad/98042513-META.yml
new file mode 100644
index 0000000000..9a1b25f5dd
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/98042513-META.yml
@@ -0,0 +1,16 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: Apache-ErrorControl
+version: 1.026
+version_from: ErrorControl.pm
+installdirs: site
+requires:
+ Apache::Constants: 1.09
+ Apache::File: 1.01
+ Apache::Request: 1.1
+ Class::Date: 
+ HTML::Template::Set: 1.01
+ MIME::Entity: 5.404
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.17
diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_0.yml b/cpan/CPAN-Meta/t/data-bad/META-1_0.yml
new file mode 100644
index 0000000000..9aaaa119c0
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/META-1_0.yml
@@ -0,0 +1,4 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: Template-DBI
+version: 1.23
diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_1.yml b/cpan/CPAN-Meta/t/data-bad/META-1_1.yml
new file mode 100644
index 0000000000..d90b133324
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/META-1_1.yml
@@ -0,0 +1,6 @@
+--- #YAML:1.0
+name: Class-Virtual
+version: 1.23
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.1.html
+ version: 1.1
diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_2.yml b/cpan/CPAN-Meta/t/data-bad/META-1_2.yml
new file mode 100644
index 0000000000..ef58965f9a
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/META-1_2.yml
@@ -0,0 +1,34 @@
+---
+name: Test-Harness-Straps
+version: 0.30
+author:
+ - 'Michael G Schwern <schwern@pobox.com>'
+license: perl
+resources:
+ license: http://dev.perl.org/licenses/
+requires:
+ File::Spec: 0.6
+provides:
+ Test::Harness::Assert:
+ file: lib/Test/Harness/Assert.pm
+ version: 0.02
+ Test::Harness::Iterator:
+ file: lib/Test/Harness/Iterator.pm
+ version: 0.02
+ Test::Harness::Iterator::ARRAY:
+ file: lib/Test/Harness/Iterator.pm
+ Test::Harness::Iterator::FH:
+ file: lib/Test/Harness/Iterator.pm
+ Test::Harness::Point:
+ file: lib/Test/Harness/Point.pm
+ version: 0.01
+ Test::Harness::Results:
+ file: lib/Test/Harness/Results.pm
+ version: 0.01
+ Test::Harness::Straps:
+ file: lib/Test/Harness/Straps.pm
+ version: 0.30
+generated_by: Module::Build version 0.280801
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_3.yml b/cpan/CPAN-Meta/t/data-bad/META-1_3.yml
new file mode 100644
index 0000000000..ad215ad92c
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/META-1_3.yml
@@ -0,0 +1,28 @@
+---
+abstract: a modern perl interactive shell
+author: Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>)
+build_requires:
+ Test::More: 0
+distribution_type: module
+generated_by: Module::Install version 0.67
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.3.html
+ version: 1.3
+name: Devel-REPL
+no_index:
+ directory:
+ - inc
+ - t
+requires:
+ Data::Dump::Streamer: 0
+ File::HomeDir: 0
+ File::Spec: 0
+ Lexical::Persistence: 0
+ Moose: 0
+ MooseX::Getopt: 0
+ MooseX::Object::Pluggable: 0
+ Term::ReadLine: 0
+ namespace::clean: 0
+ perl: 5.8.1
+version: 1.001000
diff --git a/cpan/CPAN-Meta/t/data-bad/META-1_4.yml b/cpan/CPAN-Meta/t/data-bad/META-1_4.yml
new file mode 100644
index 0000000000..1336f10a48
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/META-1_4.yml
@@ -0,0 +1,128 @@
+---
+author:
+ - 'Ken Williams <kwilliams@cpan.org>'
+ - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>."
+build_requires:
+ File::Temp: 0.15
+ Test::Harness: 3.16
+ Test::More: 0.49
+generated_by: 'Module::Build version 0.3608'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: Module-Build
+provides:
+ Module::Build:
+ file: lib/Module/Build.pm
+ version: 0.36_08
+ Module::Build::Base:
+ file: lib/Module/Build/Base.pm
+ version: 0.36_08
+ Module::Build::Compat:
+ file: lib/Module/Build/Compat.pm
+ version: 0.36_08
+ Module::Build::Config:
+ file: lib/Module/Build/Config.pm
+ version: 0.36_08
+ Module::Build::Cookbook:
+ file: lib/Module/Build/Cookbook.pm
+ version: 0.36_08
+ Module::Build::Dumper:
+ file: lib/Module/Build/Dumper.pm
+ version: 0.36_08
+ Module::Build::ModuleInfo:
+ file: lib/Module/Build/ModuleInfo.pm
+ version: 0.36_08
+ Module::Build::Notes:
+ file: lib/Module/Build/Notes.pm
+ version: 0.36_08
+ Module::Build::PPMMaker:
+ file: lib/Module/Build/PPMMaker.pm
+ version: 0.36_08
+ Module::Build::Platform::Amiga:
+ file: lib/Module/Build/Platform/Amiga.pm
+ version: 0.36_08
+ Module::Build::Platform::Default:
+ file: lib/Module/Build/Platform/Default.pm
+ version: 0.36_08
+ Module::Build::Platform::EBCDIC:
+ file: lib/Module/Build/Platform/EBCDIC.pm
+ version: 0.36_08
+ Module::Build::Platform::MPEiX:
+ file: lib/Module/Build/Platform/MPEiX.pm
+ version: 0.36_08
+ Module::Build::Platform::MacOS:
+ file: lib/Module/Build/Platform/MacOS.pm
+ version: 0.36_08
+ Module::Build::Platform::RiscOS:
+ file: lib/Module/Build/Platform/RiscOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Unix:
+ file: lib/Module/Build/Platform/Unix.pm
+ version: 0.36_08
+ Module::Build::Platform::VMS:
+ file: lib/Module/Build/Platform/VMS.pm
+ version: 0.36_08
+ Module::Build::Platform::VOS:
+ file: lib/Module/Build/Platform/VOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Windows:
+ file: lib/Module/Build/Platform/Windows.pm
+ version: 0.36_08
+ Module::Build::Platform::aix:
+ file: lib/Module/Build/Platform/aix.pm
+ version: 0.36_08
+ Module::Build::Platform::cygwin:
+ file: lib/Module/Build/Platform/cygwin.pm
+ version: 0.36_08
+ Module::Build::Platform::darwin:
+ file: lib/Module/Build/Platform/darwin.pm
+ version: 0.36_08
+ Module::Build::Platform::os2:
+ file: lib/Module/Build/Platform/os2.pm
+ version: 0.36_08
+ Module::Build::PodParser:
+ file: lib/Module/Build/PodParser.pm
+ version: 0.36_08
+ Module::Build::Version:
+ file: lib/Module/Build/Version.pm
+ version: 0.77
+ Module::Build::YAML:
+ file: lib/Module/Build/YAML.pm
+ version: 1.40
+ inc::latest:
+ file: lib/inc/latest.pm
+ version: 0.36_08
+ inc::latest::private:
+ file: lib/inc/latest/private.pm
+ version: 0.36_08
+recommends:
+ ExtUtils::Install: 0.3
+ ExtUtils::Manifest: 1.54
+ version: 0.74
+requires:
+ Cwd: 0
+ Data::Dumper: 0
+ ExtUtils::CBuilder: 0.27
+ ExtUtils::Install: 0
+ ExtUtils::Manifest: 0
+ ExtUtils::Mkbootstrap: 0
+ ExtUtils::ParseXS: 2.21
+ File::Basename: 0
+ File::Compare: 0
+ File::Copy: 0
+ File::Find: 0
+ File::Path: 0
+ File::Spec: 0.82
+ Getopt::Long: 0
+ IO::File: 0
+ Test::Harness: 0
+ Text::Abbrev: 0
+ Text::ParseWords: 0
+ perl: 5.006001
+resources:
+ MailingList: mailto:module-build@perl.org
+ license: http://dev.perl.org/licenses/
+ repository: http://github.com/dagolden/module-build/
+version: 0.36_08
diff --git a/cpan/CPAN-Meta/t/data-bad/META-2.json b/cpan/CPAN-Meta/t/data-bad/META-2.json
new file mode 100644
index 0000000000..6734399e22
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/META-2.json
@@ -0,0 +1,76 @@
+{
+ "resources" : {
+ "license" : [
+ "http://dev.perl.org/licenses/"
+ ]
+ },
+ "generated_by" : "Module::Build version 0.36",
+ "meta-spec" : {
+ "version" : "2",
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec"
+ },
+ "version" : "0.36",
+ "name" : "Module-Build",
+ "author" : [
+ "Ken Williams <kwilliams@cpan.org>",
+ "Module-Build List <module-build@perl.org>"
+ ],
+ "release_status" : "stable",
+ "license" : [
+ "perl_5"
+ ],
+ "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah",
+ "keywords" : [
+ "toolchain",
+ "cpan",
+ "dual-life"
+ ],
+ "prereqs" : {
+ "runtime" : {
+ "requires" : {
+ "File::Copy" : "0",
+ "IO::File" : "0",
+ "Data::Dumper" : "0",
+ "File::Spec" : "0",
+ "Config" : "0",
+ "ExtUtils::Install" : "0",
+ "perl" : "5.006",
+ "File::Compare" : "0",
+ "File::Find" : "0",
+ "File::Path" : "0",
+ "File::Basename" : "0",
+ "Cwd" : "0"
+ },
+ "recommends" : {
+ "YAML" : "0.35",
+ "ExtUtils::ParseXS" : "2.02",
+ "Pod::Text" : "0",
+ "ExtUtils::Install" : "0.3",
+ "Archive::Tar" : "1.00"
+ }
+ },
+ "build" : {
+ "requires" : {
+ "Test::More" : "0"
+ }
+ }
+ },
+ "optional_features" : {
+ "domination" : {
+ "prereqs" : {
+ "develop" : {
+ "requires" : {
+ "Genius::Evil" : "1.234"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Machine::Weather" : "2.0"
+ }
+ }
+ },
+ "description" : "Take over the world"
+ }
+ },
+ "abstract" : "Build and install Perl modules"
+}
diff --git a/cpan/CPAN-Meta/t/data-bad/restrictive-2.json b/cpan/CPAN-Meta/t/data-bad/restrictive-2.json
new file mode 100644
index 0000000000..2fdd9fb39a
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-bad/restrictive-2.json
@@ -0,0 +1,89 @@
+{
+ "resources" : {
+ "license" : [
+ "http://dev.perl.org/licenses/"
+ ],
+ "repository" : {
+ "url" : "svn://repo.example.com/foo-bar#fakeanchor",
+ "web" : "http://www.example.com"
+ }
+ },
+ "generated_by" : "Module::Build version 0.36",
+ "meta-spec" : {
+ "version" : "2",
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec"
+ },
+ "version" : "0.36",
+ "name" : "Module-Build",
+ "dynamic_config" : 1,
+ "author" : [
+ "Ken Williams <kwilliams@cpan.org>",
+ "Module-Build List <module-build@perl.org>"
+ ],
+ "release_status" : "stable",
+ "license" : [
+ "restrictive"
+ ],
+ "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah",
+ "keywords" : [
+ "toolchain",
+ "cpan",
+ "dual-life"
+ ],
+ "prereqs" : {
+ "runtime" : {
+ "requires" : {
+ "File::Copy" : "0",
+ "IO::File" : "0",
+ "Data::Dumper" : "0",
+ "File::Spec" : "0",
+ "Config" : "0",
+ "ExtUtils::Install" : "0",
+ "perl" : "5.006",
+ "File::Compare" : "0",
+ "File::Find" : "0",
+ "File::Path" : "0",
+ "File::Basename" : "0",
+ "Cwd" : "0"
+ },
+ "recommends" : {
+ "YAML" : "0.35",
+ "ExtUtils::ParseXS" : "2.02",
+ "Pod::Text" : "0",
+ "ExtUtils::Install" : "0.3",
+ "Archive::Tar" : "1.00"
+ }
+ },
+ "build" : {
+ "requires" : {
+ "Build::Requires": "1.1",
+ "Test::More" : "0"
+ }
+ },
+ "test" : {
+ "requires" : {
+ "Test::More" : "0.88",
+ "Test::Requires" : "1.2"
+ }
+ }
+ },
+ "optional_features" : {
+ "domination" : {
+ "prereqs" : {
+ "develop" : {
+ "requires" : {
+ "Genius::Evil" : "1.234"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Machine::Weather" : "2.0"
+ }
+ }
+ },
+ "description" : "Take over the world"
+ }
+ },
+ "abstract" : "Build and install Perl modules",
+ "x_whatever" : "Custom key"
+}
diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_0.yml b/cpan/CPAN-Meta/t/data-fail/META-1_0.yml
new file mode 100644
index 0000000000..44b0bbf6fd
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-fail/META-1_0.yml
@@ -0,0 +1,11 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: Template-DBI
+version_from: lib/Template/Plugin/DBI.pm
+installdirs: site
+license: perl
+requires:
+ DBI: 1
+ Template: 2.15
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.17
diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_1.yml b/cpan/CPAN-Meta/t/data-fail/META-1_1.yml
new file mode 100644
index 0000000000..e96665f0d3
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-fail/META-1_1.yml
@@ -0,0 +1,15 @@
+--- #YAML:1.0
+name: Class-Virtual
+abstract: ~
+license: unknown
+generated_by: ExtUtils::MakeMaker version 6.30_03
+author: ~
+distribution_type: module
+requires:
+ Carp::Assert: 0.1
+ Class::Data::Inheritable: 0.02
+ Class::ISA: 0.31
+ Test::More: 0.5
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.1.html
+ version: 1.1
diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_2.yml b/cpan/CPAN-Meta/t/data-fail/META-1_2.yml
new file mode 100644
index 0000000000..4829149914
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-fail/META-1_2.yml
@@ -0,0 +1,34 @@
+---
+name: Test-Harness-Straps
+author:
+ - 'Michael G Schwern <schwern@pobox.com>'
+abstract: detailed analysis of test results
+license: perl
+resources:
+ license: http://dev.perl.org/licenses/
+requires:
+ File::Spec: 0.6
+provides:
+ Test::Harness::Assert:
+ file: lib/Test/Harness/Assert.pm
+ version: 0.02
+ Test::Harness::Iterator:
+ file: lib/Test/Harness/Iterator.pm
+ version: 0.02
+ Test::Harness::Iterator::ARRAY:
+ file: lib/Test/Harness/Iterator.pm
+ Test::Harness::Iterator::FH:
+ file: lib/Test/Harness/Iterator.pm
+ Test::Harness::Point:
+ file: lib/Test/Harness/Point.pm
+ version: 0.01
+ Test::Harness::Results:
+ file: lib/Test/Harness/Results.pm
+ version: 0.01
+ Test::Harness::Straps:
+ file: lib/Test/Harness/Straps.pm
+ version: 0.30
+generated_by: Module::Build version 0.280801
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_3.yml b/cpan/CPAN-Meta/t/data-fail/META-1_3.yml
new file mode 100644
index 0000000000..3bbe0718c6
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-fail/META-1_3.yml
@@ -0,0 +1,28 @@
+---
+abstract: a modern perl interactive shell
+author:
+ - Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>)
+build_requires:
+ Test::More: 0
+distribution_type: module
+generated_by: Module::Install version 0.67
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.3.html
+ version: 1.3
+name: Devel-REPL
+no_index:
+ directory:
+ - inc
+ - t
+requires:
+ Data::Dump::Streamer: 0
+ File::HomeDir: 0
+ File::Spec: 0
+ Lexical::Persistence: 0
+ Moose: 0
+ MooseX::Getopt: 0
+ MooseX::Object::Pluggable: 0
+ Term::ReadLine: 0
+ namespace::clean: 0
+ perl: 5.8.1
diff --git a/cpan/CPAN-Meta/t/data-fail/META-1_4.yml b/cpan/CPAN-Meta/t/data-fail/META-1_4.yml
new file mode 100644
index 0000000000..cec4d11ca4
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-fail/META-1_4.yml
@@ -0,0 +1,129 @@
+---
+abstract: 'Build and install Perl modules'
+author:
+ - 'Ken Williams <kwilliams@cpan.org>'
+ - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>."
+build_requires:
+ File::Temp: 0.15
+ Test::Harness: 3.16
+ Test::More: 0.49
+generated_by: 'Module::Build version 0.3608'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: Module-Build
+provides:
+ Module::Build:
+ file: lib/Module/Build.pm
+ version: 0.36_08
+ Module::Build::Base:
+ file: lib/Module/Build/Base.pm
+ version: 0.36_08
+ Module::Build::Compat:
+ file: lib/Module/Build/Compat.pm
+ version: 0.36_08
+ Module::Build::Config:
+ file: lib/Module/Build/Config.pm
+ version: 0.36_08
+ Module::Build::Cookbook:
+ file: lib/Module/Build/Cookbook.pm
+ version: 0.36_08
+ Module::Build::Dumper:
+ file: lib/Module/Build/Dumper.pm
+ version: 0.36_08
+ Module::Build::ModuleInfo:
+ file: lib/Module/Build/ModuleInfo.pm
+ version: 0.36_08
+ Module::Build::Notes:
+ file: lib/Module/Build/Notes.pm
+ version: 0.36_08
+ Module::Build::PPMMaker:
+ file: lib/Module/Build/PPMMaker.pm
+ version: 0.36_08
+ Module::Build::Platform::Amiga:
+ file: lib/Module/Build/Platform/Amiga.pm
+ version: 0.36_08
+ Module::Build::Platform::Default:
+ file: lib/Module/Build/Platform/Default.pm
+ version: 0.36_08
+ Module::Build::Platform::EBCDIC:
+ file: lib/Module/Build/Platform/EBCDIC.pm
+ version: 0.36_08
+ Module::Build::Platform::MPEiX:
+ file: lib/Module/Build/Platform/MPEiX.pm
+ version: 0.36_08
+ Module::Build::Platform::MacOS:
+ file: lib/Module/Build/Platform/MacOS.pm
+ version: 0.36_08
+ Module::Build::Platform::RiscOS:
+ file: lib/Module/Build/Platform/RiscOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Unix:
+ file: lib/Module/Build/Platform/Unix.pm
+ version: 0.36_08
+ Module::Build::Platform::VMS:
+ file: lib/Module/Build/Platform/VMS.pm
+ version: 0.36_08
+ Module::Build::Platform::VOS:
+ file: lib/Module/Build/Platform/VOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Windows:
+ file: lib/Module/Build/Platform/Windows.pm
+ version: 0.36_08
+ Module::Build::Platform::aix:
+ file: lib/Module/Build/Platform/aix.pm
+ version: 0.36_08
+ Module::Build::Platform::cygwin:
+ file: lib/Module/Build/Platform/cygwin.pm
+ version: 0.36_08
+ Module::Build::Platform::darwin:
+ file: lib/Module/Build/Platform/darwin.pm
+ version: 0.36_08
+ Module::Build::Platform::os2:
+ file: lib/Module/Build/Platform/os2.pm
+ version: 0.36_08
+ Module::Build::PodParser:
+ file: lib/Module/Build/PodParser.pm
+ version: 0.36_08
+ Module::Build::Version:
+ file: lib/Module/Build/Version.pm
+ version: 0.77
+ Module::Build::YAML:
+ file: lib/Module/Build/YAML.pm
+ version: 1.40
+ inc::latest:
+ file: lib/inc/latest.pm
+ version: 0.36_08
+ inc::latest::private:
+ file: lib/inc/latest/private.pm
+ version: 0.36_08
+recommends:
+ ExtUtils::Install: 0.3
+ ExtUtils::Manifest: 1.54
+ version: 0.74
+requires:
+ Cwd: 0
+ Data::Dumper: 0
+ ExtUtils::CBuilder: 0.27
+ ExtUtils::Install: 0
+ ExtUtils::Manifest: 0
+ ExtUtils::Mkbootstrap: 0
+ ExtUtils::ParseXS: 2.21
+ File::Basename: 0
+ File::Compare: 0
+ File::Copy: 0
+ File::Find: 0
+ File::Path: 0
+ File::Spec: 0.82
+ Getopt::Long: 0
+ IO::File: 0
+ Test::Harness: 0
+ Text::Abbrev: 0
+ Text::ParseWords: 0
+ perl: 5.006001
+resources:
+ MailingList: mailto:module-build@perl.org
+ license: http://dev.perl.org/licenses/
+ repository: http://github.com/dagolden/module-build/
+
diff --git a/cpan/CPAN-Meta/t/data-fail/META-2.json b/cpan/CPAN-Meta/t/data-fail/META-2.json
new file mode 100644
index 0000000000..4cad8f3a24
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data-fail/META-2.json
@@ -0,0 +1,76 @@
+{
+ "resources" : {
+ "license" : [
+ "http://dev.perl.org/licenses/"
+ ]
+ },
+ "generated_by" : "Module::Build version 0.36",
+ "meta-spec" : {
+ "version" : "2",
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec"
+ },
+ "name" : "Module-Build",
+ "dynamic_config" : 1,
+ "author" : [
+ "Ken Williams <kwilliams@cpan.org>",
+ "Module-Build List <module-build@perl.org>"
+ ],
+ "release_status" : "stable",
+ "license" : [
+ "perl_5"
+ ],
+ "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah",
+ "keywords" : [
+ "toolchain",
+ "cpan",
+ "dual-life"
+ ],
+ "prereqs" : {
+ "runtime" : {
+ "requires" : {
+ "File::Copy" : "0",
+ "IO::File" : "0",
+ "Data::Dumper" : "0",
+ "File::Spec" : "0",
+ "Config" : "0",
+ "ExtUtils::Install" : "0",
+ "perl" : "5.006",
+ "File::Compare" : "0",
+ "File::Find" : "0",
+ "File::Path" : "0",
+ "File::Basename" : "0",
+ "Cwd" : "0"
+ },
+ "recommends" : {
+ "YAML" : "0.35",
+ "ExtUtils::ParseXS" : "2.02",
+ "Pod::Text" : "0",
+ "ExtUtils::Install" : "0.3",
+ "Archive::Tar" : "1.00"
+ }
+ },
+ "build" : {
+ "requires" : {
+ "Test::More" : "0"
+ }
+ }
+ },
+ "optional_features" : {
+ "domination" : {
+ "prereqs" : {
+ "develop" : {
+ "requires" : {
+ "Genius::Evil" : "1.234"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Machine::Weather" : "2.0"
+ }
+ }
+ },
+ "description" : "Take over the world"
+ }
+ },
+ "abstract" : "Build and install Perl modules"
+}
diff --git a/cpan/CPAN-Meta/t/data/META-1_0.yml b/cpan/CPAN-Meta/t/data/META-1_0.yml
new file mode 100644
index 0000000000..e72d9ed944
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/META-1_0.yml
@@ -0,0 +1,12 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: Template-DBI
+version: 2.64
+version_from: lib/Template/Plugin/DBI.pm
+installdirs: site
+license: perl
+requires:
+ DBI: 1
+ Template: 2.15
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.17
diff --git a/cpan/CPAN-Meta/t/data/META-1_1.yml b/cpan/CPAN-Meta/t/data/META-1_1.yml
new file mode 100644
index 0000000000..d77007737f
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/META-1_1.yml
@@ -0,0 +1,16 @@
+--- #YAML:1.0
+name: Class-Virtual
+version: 0.06
+abstract: ~
+license: unknown
+generated_by: ExtUtils::MakeMaker version 6.30_03
+author: ~
+distribution_type: module
+requires:
+ Carp::Assert: 0.1
+ Class::Data::Inheritable: 0.02
+ Class::ISA: 0.31
+ Test::More: 0.5
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.1.html
+ version: 1.1
diff --git a/cpan/CPAN-Meta/t/data/META-1_2.yml b/cpan/CPAN-Meta/t/data/META-1_2.yml
new file mode 100644
index 0000000000..51c2a963bc
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/META-1_2.yml
@@ -0,0 +1,35 @@
+---
+name: Test-Harness-Straps
+version: 0.30
+author:
+ - 'Michael G Schwern <schwern@pobox.com>'
+abstract: detailed analysis of test results
+license: perl
+resources:
+ license: http://dev.perl.org/licenses/
+requires:
+ File::Spec: 0.6
+provides:
+ Test::Harness::Assert:
+ file: lib/Test/Harness/Assert.pm
+ version: 0.02
+ Test::Harness::Iterator:
+ file: lib/Test/Harness/Iterator.pm
+ version: 0.02
+ Test::Harness::Iterator::ARRAY:
+ file: lib/Test/Harness/Iterator.pm
+ Test::Harness::Iterator::FH:
+ file: lib/Test/Harness/Iterator.pm
+ Test::Harness::Point:
+ file: lib/Test/Harness/Point.pm
+ version: 0.01
+ Test::Harness::Results:
+ file: lib/Test/Harness/Results.pm
+ version: 0.01
+ Test::Harness::Straps:
+ file: lib/Test/Harness/Straps.pm
+ version: 0.30
+generated_by: Module::Build version 0.280801
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
diff --git a/cpan/CPAN-Meta/t/data/META-1_3.yml b/cpan/CPAN-Meta/t/data/META-1_3.yml
new file mode 100644
index 0000000000..c26a3e0b74
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/META-1_3.yml
@@ -0,0 +1,29 @@
+---
+abstract: a modern perl interactive shell
+author:
+ - Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>)
+build_requires:
+ Test::More: 0
+distribution_type: module
+generated_by: Module::Install version 0.67
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.3.html
+ version: 1.3
+name: Devel-REPL
+no_index:
+ directory:
+ - inc
+ - t
+requires:
+ Data::Dump::Streamer: 0
+ File::HomeDir: 0
+ File::Spec: 0
+ Lexical::Persistence: 0
+ Moose: 0
+ MooseX::Getopt: 0
+ MooseX::Object::Pluggable: 0
+ Term::ReadLine: 0
+ namespace::clean: 0
+ perl: 5.8.1
+version: 1.001000
diff --git a/cpan/CPAN-Meta/t/data/META-1_4.yml b/cpan/CPAN-Meta/t/data/META-1_4.yml
new file mode 100644
index 0000000000..801f5797c0
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/META-1_4.yml
@@ -0,0 +1,132 @@
+---
+abstract: 'Build and install Perl modules'
+author:
+ - 'Ken Williams <kwilliams@cpan.org>'
+ - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>."
+build_requires:
+ File::Temp: 0.15
+ Test::Harness: 3.16
+ Test::More: 0.49
+generated_by: 'Module::Build version 0.3608'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: Module-Build
+provides:
+ Module::Build:
+ file: lib/Module/Build.pm
+ version: 0.36_08
+ Module::Build::Base:
+ file: lib/Module/Build/Base.pm
+ version: 0.36_08
+ Module::Build::Compat:
+ file: lib/Module/Build/Compat.pm
+ version: 0.36_08
+ Module::Build::Config:
+ file: lib/Module/Build/Config.pm
+ version: 0.36_08
+ Module::Build::Cookbook:
+ file: lib/Module/Build/Cookbook.pm
+ version: 0.36_08
+ Module::Build::Dumper:
+ file: lib/Module/Build/Dumper.pm
+ version: 0.36_08
+ Module::Build::ModuleInfo:
+ file: lib/Module/Build/ModuleInfo.pm
+ version: 0.36_08
+ Module::Build::Notes:
+ file: lib/Module/Build/Notes.pm
+ version: 0.36_08
+ Module::Build::PPMMaker:
+ file: lib/Module/Build/PPMMaker.pm
+ version: 0.36_08
+ Module::Build::Platform::Amiga:
+ file: lib/Module/Build/Platform/Amiga.pm
+ version: 0.36_08
+ Module::Build::Platform::Default:
+ file: lib/Module/Build/Platform/Default.pm
+ version: 0.36_08
+ Module::Build::Platform::EBCDIC:
+ file: lib/Module/Build/Platform/EBCDIC.pm
+ version: 0.36_08
+ Module::Build::Platform::MPEiX:
+ file: lib/Module/Build/Platform/MPEiX.pm
+ version: 0.36_08
+ Module::Build::Platform::MacOS:
+ file: lib/Module/Build/Platform/MacOS.pm
+ version: 0.36_08
+ Module::Build::Platform::RiscOS:
+ file: lib/Module/Build/Platform/RiscOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Unix:
+ file: lib/Module/Build/Platform/Unix.pm
+ version: 0.36_08
+ Module::Build::Platform::VMS:
+ file: lib/Module/Build/Platform/VMS.pm
+ version: 0.36_08
+ Module::Build::Platform::VOS:
+ file: lib/Module/Build/Platform/VOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Windows:
+ file: lib/Module/Build/Platform/Windows.pm
+ version: 0.36_08
+ Module::Build::Platform::aix:
+ file: lib/Module/Build/Platform/aix.pm
+ version: 0.36_08
+ Module::Build::Platform::cygwin:
+ file: lib/Module/Build/Platform/cygwin.pm
+ version: 0.36_08
+ Module::Build::Platform::darwin:
+ file: lib/Module/Build/Platform/darwin.pm
+ version: 0.36_08
+ Module::Build::Platform::os2:
+ file: lib/Module/Build/Platform/os2.pm
+ version: 0.36_08
+ Module::Build::PodParser:
+ file: lib/Module/Build/PodParser.pm
+ version: 0.36_08
+ Module::Build::Version:
+ file: lib/Module/Build/Version.pm
+ version: 0.77
+ Module::Build::YAML:
+ file: lib/Module/Build/YAML.pm
+ version: 1.40
+ inc::latest:
+ file: lib/inc/latest.pm
+ version: 0.36_08
+ inc::latest::private:
+ file: lib/inc/latest/private.pm
+ version: 0.36_08
+recommends:
+ ExtUtils::Install: 0.3
+ ExtUtils::Manifest: 1.54
+ version: 0.74
+requires:
+ Cwd: 0
+ Data::Dumper: 0
+ ExtUtils::CBuilder: 0.27
+ ExtUtils::Install: 0
+ ExtUtils::Manifest: 0
+ ExtUtils::Mkbootstrap: 0
+ ExtUtils::ParseXS: 2.21
+ File::Basename: 0
+ File::Compare: 0
+ File::Copy: 0
+ File::Find: 0
+ File::Path: 0
+ File::Spec: 0.82
+ Getopt::Long: 0
+ IO::File: 0
+ Test::Harness: 0
+ Text::Abbrev: 0
+ Text::ParseWords: 0
+ perl: 5.006001
+resources:
+ MailingList: mailto:module-build@perl.org
+ license: http://dev.perl.org/licenses/
+ repository: http://github.com/dagolden/module-build/
+version: 0.36_08
+x-whatever: this is a custom field
+x_whatelse: so is this
+XWhatNow: and this
diff --git a/cpan/CPAN-Meta/t/data/META-2.json b/cpan/CPAN-Meta/t/data/META-2.json
new file mode 100644
index 0000000000..d737fef231
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/META-2.json
@@ -0,0 +1,89 @@
+{
+ "resources" : {
+ "license" : [
+ "http://dev.perl.org/licenses/"
+ ],
+ "repository" : {
+ "url" : "svn://repo.example.com/foo-bar#fakeanchor",
+ "web" : "http://www.example.com"
+ }
+ },
+ "generated_by" : "Module::Build version 0.36",
+ "meta-spec" : {
+ "version" : "2",
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec"
+ },
+ "version" : "0.36",
+ "name" : "Module-Build",
+ "dynamic_config" : 1,
+ "author" : [
+ "Ken Williams <kwilliams@cpan.org>",
+ "Module-Build List <module-build@perl.org>"
+ ],
+ "release_status" : "stable",
+ "license" : [
+ "perl_5"
+ ],
+ "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah",
+ "keywords" : [
+ "toolchain",
+ "cpan",
+ "dual-life"
+ ],
+ "prereqs" : {
+ "runtime" : {
+ "requires" : {
+ "File::Copy" : "0",
+ "IO::File" : "0",
+ "Data::Dumper" : "0",
+ "File::Spec" : "0",
+ "Config" : "0",
+ "ExtUtils::Install" : "0",
+ "perl" : "5.006",
+ "File::Compare" : "0",
+ "File::Find" : "0",
+ "File::Path" : "0",
+ "File::Basename" : "0",
+ "Cwd" : "0"
+ },
+ "recommends" : {
+ "YAML" : "0.35",
+ "ExtUtils::ParseXS" : "2.02",
+ "Pod::Text" : "0",
+ "ExtUtils::Install" : "0.3",
+ "Archive::Tar" : "1.00"
+ }
+ },
+ "build" : {
+ "requires" : {
+ "Build::Requires": "1.1",
+ "Test::More" : "0"
+ }
+ },
+ "test" : {
+ "requires" : {
+ "Test::More" : "0.88",
+ "Test::Requires" : "1.2"
+ }
+ }
+ },
+ "optional_features" : {
+ "domination" : {
+ "prereqs" : {
+ "develop" : {
+ "requires" : {
+ "Genius::Evil" : "1.234"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Machine::Weather" : "2.0"
+ }
+ }
+ },
+ "description" : "Take over the world"
+ }
+ },
+ "abstract" : "Build and install Perl modules",
+ "x_whatever" : "Custom key"
+}
diff --git a/cpan/CPAN-Meta/t/data/resources.yml b/cpan/CPAN-Meta/t/data/resources.yml
new file mode 100644
index 0000000000..8013137784
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/resources.yml
@@ -0,0 +1,49 @@
+--- #YAML:1.0
+name: WWW-Mechanize
+version: 1.64
+abstract: Handy web browsing in a Perl object
+author:
+ - Andy Lester <andy@petdance.com>
+license: perl
+distribution_type: module
+configure_requires:
+ ExtUtils::MakeMaker: 0
+build_requires:
+ ExtUtils::MakeMaker: 0
+requires:
+ Carp: 0
+ File::Temp: 0
+ FindBin: 0
+ Getopt::Long: 0
+ HTML::Form: 1.038
+ HTML::HeadParser: 0
+ HTML::Parser: 3.33
+ HTML::TokeParser: 2.28
+ HTTP::Daemon: 0
+ HTTP::Request: 1.3
+ HTTP::Server::Simple: 0.35
+ HTTP::Server::Simple::CGI: 0
+ HTTP::Status: 0
+ LWP: 5.829
+ LWP::UserAgent: 5.829
+ perl: 5.008
+ Pod::Usage: 0
+ Test::More: 0.34
+ Test::Warn: 0.11
+ URI: 1.36
+ URI::file: 0
+ URI::URL: 0
+resources:
+ bugtracker: http://code.google.com/p/www-mechanize/issues/list
+ homepage: http://code.google.com/p/www-mechanize/
+ license: http://dev.perl.org/licenses/
+ MailingList: http://groups.google.com/group/www-mechanize-users
+ Repository: http://code.google.com/p/www-mechanize/source
+no_index:
+ directory:
+ - t
+ - inc
+generated_by: ExtUtils::MakeMaker version 6.56
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
diff --git a/cpan/CPAN-Meta/t/data/restricted-2.json b/cpan/CPAN-Meta/t/data/restricted-2.json
new file mode 100644
index 0000000000..88886db9fc
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/restricted-2.json
@@ -0,0 +1,89 @@
+{
+ "resources" : {
+ "license" : [
+ "http://dev.perl.org/licenses/"
+ ],
+ "repository" : {
+ "url" : "svn://repo.example.com/foo-bar#fakeanchor",
+ "web" : "http://www.example.com"
+ }
+ },
+ "generated_by" : "Module::Build version 0.36",
+ "meta-spec" : {
+ "version" : "2",
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec"
+ },
+ "version" : "0.36",
+ "name" : "Module-Build",
+ "dynamic_config" : 1,
+ "author" : [
+ "Ken Williams <kwilliams@cpan.org>",
+ "Module-Build List <module-build@perl.org>"
+ ],
+ "release_status" : "stable",
+ "license" : [
+ "restricted"
+ ],
+ "description" : "Module::Build is a system for building, testing, and installing Perl modules. It is meant to be an alternative to ExtUtils::MakeMaker... blah blah blah",
+ "keywords" : [
+ "toolchain",
+ "cpan",
+ "dual-life"
+ ],
+ "prereqs" : {
+ "runtime" : {
+ "requires" : {
+ "File::Copy" : "0",
+ "IO::File" : "0",
+ "Data::Dumper" : "0",
+ "File::Spec" : "0",
+ "Config" : "0",
+ "ExtUtils::Install" : "0",
+ "perl" : "5.006",
+ "File::Compare" : "0",
+ "File::Find" : "0",
+ "File::Path" : "0",
+ "File::Basename" : "0",
+ "Cwd" : "0"
+ },
+ "recommends" : {
+ "YAML" : "0.35",
+ "ExtUtils::ParseXS" : "2.02",
+ "Pod::Text" : "0",
+ "ExtUtils::Install" : "0.3",
+ "Archive::Tar" : "1.00"
+ }
+ },
+ "build" : {
+ "requires" : {
+ "Build::Requires": "1.1",
+ "Test::More" : "0"
+ }
+ },
+ "test" : {
+ "requires" : {
+ "Test::More" : "0.88",
+ "Test::Requires" : "1.2"
+ }
+ }
+ },
+ "optional_features" : {
+ "domination" : {
+ "prereqs" : {
+ "develop" : {
+ "requires" : {
+ "Genius::Evil" : "1.234"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Machine::Weather" : "2.0"
+ }
+ }
+ },
+ "description" : "Take over the world"
+ }
+ },
+ "abstract" : "Build and install Perl modules",
+ "x_whatever" : "Custom key"
+}
diff --git a/cpan/CPAN-Meta/t/data/restrictive-1_4.yml b/cpan/CPAN-Meta/t/data/restrictive-1_4.yml
new file mode 100644
index 0000000000..b780016da2
--- /dev/null
+++ b/cpan/CPAN-Meta/t/data/restrictive-1_4.yml
@@ -0,0 +1,132 @@
+---
+abstract: 'Build and install Perl modules'
+author:
+ - 'Ken Williams <kwilliams@cpan.org>'
+ - "Development questions, bug reports, and patches should be sent to the\nModule-Build mailing list at <module-build@perl.org>."
+build_requires:
+ File::Temp: 0.15
+ Test::Harness: 3.16
+ Test::More: 0.49
+generated_by: 'Module::Build version 0.3608'
+license: restrictive
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: Module-Build
+provides:
+ Module::Build:
+ file: lib/Module/Build.pm
+ version: 0.36_08
+ Module::Build::Base:
+ file: lib/Module/Build/Base.pm
+ version: 0.36_08
+ Module::Build::Compat:
+ file: lib/Module/Build/Compat.pm
+ version: 0.36_08
+ Module::Build::Config:
+ file: lib/Module/Build/Config.pm
+ version: 0.36_08
+ Module::Build::Cookbook:
+ file: lib/Module/Build/Cookbook.pm
+ version: 0.36_08
+ Module::Build::Dumper:
+ file: lib/Module/Build/Dumper.pm
+ version: 0.36_08
+ Module::Build::ModuleInfo:
+ file: lib/Module/Build/ModuleInfo.pm
+ version: 0.36_08
+ Module::Build::Notes:
+ file: lib/Module/Build/Notes.pm
+ version: 0.36_08
+ Module::Build::PPMMaker:
+ file: lib/Module/Build/PPMMaker.pm
+ version: 0.36_08
+ Module::Build::Platform::Amiga:
+ file: lib/Module/Build/Platform/Amiga.pm
+ version: 0.36_08
+ Module::Build::Platform::Default:
+ file: lib/Module/Build/Platform/Default.pm
+ version: 0.36_08
+ Module::Build::Platform::EBCDIC:
+ file: lib/Module/Build/Platform/EBCDIC.pm
+ version: 0.36_08
+ Module::Build::Platform::MPEiX:
+ file: lib/Module/Build/Platform/MPEiX.pm
+ version: 0.36_08
+ Module::Build::Platform::MacOS:
+ file: lib/Module/Build/Platform/MacOS.pm
+ version: 0.36_08
+ Module::Build::Platform::RiscOS:
+ file: lib/Module/Build/Platform/RiscOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Unix:
+ file: lib/Module/Build/Platform/Unix.pm
+ version: 0.36_08
+ Module::Build::Platform::VMS:
+ file: lib/Module/Build/Platform/VMS.pm
+ version: 0.36_08
+ Module::Build::Platform::VOS:
+ file: lib/Module/Build/Platform/VOS.pm
+ version: 0.36_08
+ Module::Build::Platform::Windows:
+ file: lib/Module/Build/Platform/Windows.pm
+ version: 0.36_08
+ Module::Build::Platform::aix:
+ file: lib/Module/Build/Platform/aix.pm
+ version: 0.36_08
+ Module::Build::Platform::cygwin:
+ file: lib/Module/Build/Platform/cygwin.pm
+ version: 0.36_08
+ Module::Build::Platform::darwin:
+ file: lib/Module/Build/Platform/darwin.pm
+ version: 0.36_08
+ Module::Build::Platform::os2:
+ file: lib/Module/Build/Platform/os2.pm
+ version: 0.36_08
+ Module::Build::PodParser:
+ file: lib/Module/Build/PodParser.pm
+ version: 0.36_08
+ Module::Build::Version:
+ file: lib/Module/Build/Version.pm
+ version: 0.77
+ Module::Build::YAML:
+ file: lib/Module/Build/YAML.pm
+ version: 1.40
+ inc::latest:
+ file: lib/inc/latest.pm
+ version: 0.36_08
+ inc::latest::private:
+ file: lib/inc/latest/private.pm
+ version: 0.36_08
+recommends:
+ ExtUtils::Install: 0.3
+ ExtUtils::Manifest: 1.54
+ version: 0.74
+requires:
+ Cwd: 0
+ Data::Dumper: 0
+ ExtUtils::CBuilder: 0.27
+ ExtUtils::Install: 0
+ ExtUtils::Manifest: 0
+ ExtUtils::Mkbootstrap: 0
+ ExtUtils::ParseXS: 2.21
+ File::Basename: 0
+ File::Compare: 0
+ File::Copy: 0
+ File::Find: 0
+ File::Path: 0
+ File::Spec: 0.82
+ Getopt::Long: 0
+ IO::File: 0
+ Test::Harness: 0
+ Text::Abbrev: 0
+ Text::ParseWords: 0
+ perl: 5.006001
+resources:
+ MailingList: mailto:module-build@perl.org
+ license: http://dev.perl.org/licenses/
+ repository: http://github.com/dagolden/module-build/
+version: 0.36_08
+x-whatever: this is a custom field
+x_whatelse: so is this
+XWhatNow: and this
diff --git a/cpan/CPAN-Meta/t/load-bad.t b/cpan/CPAN-Meta/t/load-bad.t
new file mode 100644
index 0000000000..d18b65caa6
--- /dev/null
+++ b/cpan/CPAN-Meta/t/load-bad.t
@@ -0,0 +1,25 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+use File::Spec;
+use IO::Dir;
+
+sub _slurp { do { local(@ARGV,$/)=shift(@_); <> } }
+
+my $data_dir = IO::Dir->new( 't/data-bad' );
+my @files = sort grep { /^\w/ } $data_dir->read;
+
+for my $f ( sort @files ) {
+ my $path = File::Spec->catfile('t','data-bad',$f);
+ my $meta = eval { CPAN::Meta->load_file( $path, { fix_errors => 1 } ) };
+ ok( defined $meta, "load_file('$f')" ) or diag $@;
+ my $string = _slurp($path);
+ my $method = $path =~ /\.json/ ? "load_json_string" : "load_yaml_string";
+ my $meta2 = eval { CPAN::Meta->$method( $string, { fix_errors => 1 } ) };
+ ok( defined $meta2, "$method(slurp('$f'))" ) or diag $@;
+}
+
+done_testing;
+
diff --git a/cpan/CPAN-Meta/t/meta-obj.t b/cpan/CPAN-Meta/t/meta-obj.t
new file mode 100644
index 0000000000..522f67dbde
--- /dev/null
+++ b/cpan/CPAN-Meta/t/meta-obj.t
@@ -0,0 +1,240 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+
+use Scalar::Util qw(blessed);
+
+my $distmeta = {
+ name => 'Module-Build',
+ abstract => 'Build and install Perl modules',
+ description => "Module::Build is a system for building, testing, "
+ . "and installing Perl modules. It is meant to be an "
+ . "alternative to ExtUtils::MakeMaker... blah blah blah",
+ version => '0.36',
+ author => [
+ 'Ken Williams <kwilliams@cpan.org>',
+ 'Module-Build List <module-build@perl.org>', # additional contact
+ ],
+ release_status => 'stable',
+ license => [ 'perl_5' ],
+ prereqs => {
+ runtime => {
+ requires => {
+ 'perl' => '5.006',
+ 'Config' => '0',
+ 'Cwd' => '0',
+ 'Data::Dumper' => '0',
+ 'ExtUtils::Install' => '0',
+ 'File::Basename' => '0',
+ 'File::Compare' => '0',
+ 'File::Copy' => '0',
+ 'File::Find' => '0',
+ 'File::Path' => '0',
+ 'File::Spec' => '0',
+ 'IO::File' => '0',
+ },
+ recommends => {
+ 'Archive::Tar' => '1.00',
+ 'ExtUtils::Install' => '0.3',
+ 'ExtUtils::ParseXS' => '2.02',
+ 'Pod::Text' => '0',
+ 'YAML' => '0.35',
+ },
+ },
+ build => {
+ requires => {
+ 'Test::More' => '0',
+ },
+ }
+ },
+ resources => {
+ license => ['http://dev.perl.org/licenses/'],
+ },
+ optional_features => {
+ domination => {
+ description => 'Take over the world',
+ prereqs => {
+ develop => { requires => { 'Genius::Evil' => '1.234' } },
+ runtime => { requires => { 'Machine::Weather' => '2.0' } },
+ },
+ },
+ },
+ dynamic_config => 1,
+ keywords => [ qw/ toolchain cpan dual-life / ],
+ 'meta-spec' => {
+ version => '2',
+ url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
+ },
+ generated_by => 'Module::Build version 0.36',
+ x_authority => 'cpan:FLORA',
+ X_deep => { deep => 'structure' },
+};
+
+my $meta = CPAN::Meta->new($distmeta);
+
+is(
+ blessed($meta->as_struct),
+ undef,
+ "the result of ->as_struct is unblessed",
+);
+
+is_deeply( $meta->as_struct, $distmeta, "->as_struct (deep comparison)" );
+isnt( $meta->as_struct, $distmeta, "->as_struct (is a deep clone)" );
+
+my $old_copy = $meta->as_struct( {version => "1.4"} );
+is( $old_copy->{'meta-spec'}{version}, "1.4", "->as_struct (downconversion)" );
+
+isnt( $meta->resources, $meta->{resources}, "->resource (map values are deep cloned)");
+
+is($meta->name, 'Module-Build', '->name');
+is($meta->abstract, 'Build and install Perl modules', '->abstract');
+
+like($meta->description, qr/Module::Build.+blah blah blah/, '->description');
+
+is($meta->version, '0.36', '->version');
+
+ok($meta->dynamic_config, "->dynamic_config");
+
+is_deeply(
+ [ $meta->author ],
+ [
+ 'Ken Williams <kwilliams@cpan.org>',
+ 'Module-Build List <module-build@perl.org>',
+ ],
+ '->author',
+);
+
+is_deeply(
+ [ $meta->authors ],
+ [
+ 'Ken Williams <kwilliams@cpan.org>',
+ 'Module-Build List <module-build@perl.org>',
+ ],
+ '->authors',
+);
+
+is_deeply(
+ [ $meta->license ],
+ [ qw(perl_5) ],
+ '->license',
+);
+
+is_deeply(
+ [ $meta->licenses ],
+ [ qw(perl_5) ],
+ '->licenses',
+);
+
+is_deeply(
+ [ $meta->keywords ],
+ [ qw/ toolchain cpan dual-life / ],
+ '->keywords',
+);
+
+is_deeply(
+ $meta->resources,
+ { license => [ 'http://dev.perl.org/licenses/' ] },
+ '->resources',
+);
+
+is_deeply(
+ $meta->meta_spec,
+ {
+ version => '2',
+ url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
+ },
+ '->meta_spec',
+);
+
+is($meta->meta_spec_version, '2', '->meta_spec_version');
+
+like($meta->generated_by, qr/Module::Build version 0.36/, '->generated_by');
+
+my $basic = $meta->effective_prereqs;
+
+is_deeply(
+ $basic->as_string_hash,
+ $distmeta->{prereqs},
+ "->effective_prereqs()"
+);
+
+is_deeply( [ sort $meta->custom_keys ] , [ 'X_deep', 'x_authority' ],
+ "->custom_keys"
+);
+
+is( $meta->custom('x_authority'), 'cpan:FLORA', "->custom(X)" );
+
+is_deeply( $meta->custom('X_deep'), $distmeta->{'X_deep'},
+ "->custom(X) [is_deeply]"
+);
+
+isnt( $meta->custom('X_deep'), $distmeta->{'X_deep'},
+ "->custom(x) [is a deep clone]"
+);
+
+my $with_features = $meta->effective_prereqs([ qw(domination) ]);
+
+is_deeply(
+ $with_features->as_string_hash,
+ {
+ develop => { requires => { 'Genius::Evil' => '1.234' } },
+ runtime => {
+ requires => {
+ 'perl' => '5.006',
+ 'Config' => '0',
+ 'Cwd' => '0',
+ 'Data::Dumper' => '0',
+ 'ExtUtils::Install' => '0',
+ 'File::Basename' => '0',
+ 'File::Compare' => '0',
+ 'File::Copy' => '0',
+ 'File::Find' => '0',
+ 'File::Path' => '0',
+ 'File::Spec' => '0',
+ 'IO::File' => '0',
+ 'Machine::Weather' => '2.0',
+ },
+ recommends => {
+ 'Archive::Tar' => '1.00',
+ 'ExtUtils::Install' => '0.3',
+ 'ExtUtils::ParseXS' => '2.02',
+ 'Pod::Text' => '0',
+ 'YAML' => '0.35',
+ },
+ },
+ build => {
+ requires => {
+ 'Test::More' => '0',
+ },
+ }
+ },
+ "->effective_prereqs([ qw(domination) ])"
+);
+
+my $chk_feature = sub {
+ my $feature = shift;
+
+ isa_ok($feature, 'CPAN::Meta::Feature');
+
+ is($feature->identifier, 'domination', '$feature->identifier');
+ is($feature->description, 'Take over the world', '$feature->description');
+
+ is_deeply(
+ $feature->prereqs->as_string_hash,
+ {
+ develop => { requires => { 'Genius::Evil' => '1.234' } },
+ runtime => { requires => { 'Machine::Weather' => '2.0' } },
+ },
+ '$feature->prereqs',
+ );
+};
+
+my @features = $meta->features;
+is(@features, 1, "we got one feature");
+$chk_feature->($features[0]);
+
+$chk_feature->( $meta->feature('domination') );
+
+done_testing;
diff --git a/cpan/CPAN-Meta/t/no-index.t b/cpan/CPAN-Meta/t/no-index.t
new file mode 100644
index 0000000000..4f8df45eb5
--- /dev/null
+++ b/cpan/CPAN-Meta/t/no-index.t
@@ -0,0 +1,86 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+
+my %distmeta = (
+ name => 'Module-Billed',
+ abstract => 'inscrutable',
+ version => '1',
+ author => 'Joe',
+ release_status => 'stable',
+ license => 'perl_5',
+ 'meta-spec' => {
+ version => '2',
+ url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
+ },
+ dynamic_config => 1,
+ generated_by => 'Module::Build version 0.36',
+);
+
+{
+ my $meta = CPAN::Meta->new({ %distmeta });
+
+ ok(
+ $meta->should_index_package('Foo::Bar::Baz'),
+ 'we index any old package, without a no_index rule'
+ );
+
+ ok(
+ $meta->should_index_file('lib/Foo/Bar/Baz.pm'),
+ 'we index any old file, without a no_index rule'
+ );
+}
+
+{
+ my $meta = CPAN::Meta->new({
+ %distmeta,
+ no_index => {
+ package => [ 'Foo::Bar' ],
+ namespace => [ 'Foo::Bar::Baz' ],
+ }
+ });
+
+ ok(
+ ! $meta->should_index_package('Foo::Bar'),
+ 'exclude a specific package'
+ );
+
+ ok(
+ $meta->should_index_package('Foo::Bar::Baz'),
+ 'namespace X does not exclude package X'
+ );
+
+ ok(
+ ! $meta->should_index_package('Foo::Bar::Baz::Quux'),
+ 'exclude something under a namespace'
+ );
+}
+
+{
+ my $meta = CPAN::Meta->new({
+ %distmeta,
+ no_index => {
+ file => [ 'lib/Foo/Bar.pm' ],
+ directory => [ 'lib/Foo/Bar/Baz' ],
+ }
+ });
+
+ ok(
+ ! $meta->should_index_file('lib/Foo/Bar.pm'),
+ 'exclude a specific file'
+ );
+
+ ok(
+ $meta->should_index_file('lib/Foo/Bar/Baz.pm'),
+ 'do not exclude a file with a name like an excluded dir',
+ );
+
+ ok(
+ ! $meta->should_index_file('lib/Foo/Bar/Baz/Quux.pm'),
+ 'exclude something under a directory'
+ );
+}
+
+done_testing;
diff --git a/cpan/CPAN-Meta/t/prereqs-finalize.t b/cpan/CPAN-Meta/t/prereqs-finalize.t
new file mode 100644
index 0000000000..040e3f3b24
--- /dev/null
+++ b/cpan/CPAN-Meta/t/prereqs-finalize.t
@@ -0,0 +1,91 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta::Prereqs;
+
+sub dies_ok (&@) {
+ my ($code, $qr, $comment) = @_;
+
+ my $lived = eval { $code->(); 1 };
+
+ if ($lived) {
+ fail("$comment: did not die");
+ } else {
+ like($@, $qr, $comment);
+ }
+}
+
+my $prereqs_struct = {
+ runtime => {
+ requires => {
+ 'Config' => '1.234',
+ 'Cwd' => '876.5',
+ 'IO::File' => 0,
+ 'perl' => '5.005_03',
+ },
+ recommends => {
+ 'Pod::Text' => 0,
+ 'YAML' => '0.35',
+ },
+ },
+ build => {
+ requires => {
+ 'Test' => 0,
+ },
+ }
+};
+
+my $prereqs = CPAN::Meta::Prereqs->new($prereqs_struct);
+
+isa_ok($prereqs, 'CPAN::Meta::Prereqs');
+
+$prereqs->finalize;
+
+ok($prereqs->is_finalized, 'cloned obj is not finalized');
+
+is_deeply($prereqs->as_string_hash, $prereqs_struct, '...and still round-trip');
+
+$prereqs->requirements_for(qw(runtime requires))->add_minimum(Cwd => 10);
+
+pass('...we can add a minimum if it has no effect');
+
+dies_ok
+ { $prereqs->requirements_for(qw(runtime requires))->add_minimum(Cwd => 1000) }
+ qr{finalized req},
+ '...but we die if it would alter a finalized prereqs';
+
+$prereqs->requirements_for(qw(develop suggests));
+
+pass('...we can get a V:R object for a previously unconfigured phase');
+
+dies_ok
+ { $prereqs->requirements_for(qw(develop suggests))->add_minimum(Foo => 1) }
+ qr{finalized req},
+ '...but we die if we try to put anything in it';
+
+my $clone = $prereqs->clone;
+
+isa_ok($clone, 'CPAN::Meta::Prereqs', 'cloned prereqs obj');
+
+ok(! $clone->is_finalized, 'cloned obj is not finalized');
+
+is_deeply($clone->as_string_hash, $prereqs_struct, '...it still round-trips');
+
+$clone->requirements_for(qw(runtime requires))->add_minimum(Cwd => 10);
+
+pass('...we can add minimum if it has no effect');
+
+$clone->requirements_for(qw(runtime requires))->add_minimum(Cwd => 1000);
+
+pass('...or if it has an effect');
+
+$clone->requirements_for(qw(develop suggests));
+
+pass('...we can get a V:R object for a previously unconfigured phase');
+
+$clone->requirements_for(qw(develop suggests))->add_minimum(Foo => 1);
+
+pass('...and we can add stuff to it');
+
+done_testing;
diff --git a/cpan/CPAN-Meta/t/prereqs-merge.t b/cpan/CPAN-Meta/t/prereqs-merge.t
new file mode 100644
index 0000000000..63e267e84e
--- /dev/null
+++ b/cpan/CPAN-Meta/t/prereqs-merge.t
@@ -0,0 +1,104 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta::Prereqs;
+
+my $prereq_struct_1 = {
+ runtime => {
+ requires => {
+ 'Config' => 0,
+ 'Cwd' => 0,
+ 'perl' => '5.005_03',
+ },
+ recommends => {
+ 'Pod::Text' => 0,
+ 'YAML' => 0.35,
+ },
+ },
+ build => {
+ requires => {
+ 'Test' => 0,
+ },
+ }
+};
+
+my $prereq_1 = CPAN::Meta::Prereqs->new($prereq_struct_1);
+
+isa_ok($prereq_1, 'CPAN::Meta::Prereqs', 'first prereq');
+
+is_deeply($prereq_1->as_string_hash, $prereq_struct_1, '...and it round trips');
+
+my $prereq_struct_2 = {
+ develop => {
+ requires => {
+ 'Dist::Mothra' => '1.230',
+ },
+ suggests => {
+ 'Blort::Blortex' => '== 10.20',
+ },
+ },
+ runtime => {
+ requires => {
+ 'Config' => 1,
+ 'perl' => '< 6',
+ },
+ },
+ build => {
+ suggests => {
+ 'Module::Build::Bob' => '20100101',
+ },
+ }
+};
+
+my $prereq_2 = CPAN::Meta::Prereqs->new($prereq_struct_2);
+
+isa_ok($prereq_2, 'CPAN::Meta::Prereqs', 'second prereq');
+
+is_deeply($prereq_1->as_string_hash, $prereq_struct_1, '...and it round trips');
+
+my $merged = $prereq_1->with_merged_prereqs($prereq_2);
+
+my $want = {
+ develop => {
+ requires => {
+ 'Dist::Mothra' => '1.230',
+ },
+ suggests => {
+ 'Blort::Blortex' => '== 10.20',
+ },
+ },
+ runtime => {
+ requires => {
+ 'Config' => 1,
+ 'Cwd' => 0,
+ 'perl' => '>= 5.005_03, < 6',
+ },
+ recommends => {
+ 'Pod::Text' => 0,
+ 'YAML' => 0.35,
+ },
+ },
+ build => {
+ requires => {
+ 'Test' => 0,
+ },
+ suggests => {
+ 'Module::Build::Bob' => '20100101',
+ },
+ },
+};
+
+is_deeply(
+ $merged->as_string_hash,
+ $want,
+ "we get the right result of merging two prereqs",
+);
+
+is_deeply(
+ $prereq_2->with_merged_prereqs($prereq_1)->as_string_hash,
+ $want,
+ "...and the merge works the same in reverse",
+);
+
+done_testing;
diff --git a/cpan/CPAN-Meta/t/prereqs.t b/cpan/CPAN-Meta/t/prereqs.t
new file mode 100644
index 0000000000..a24f27274c
--- /dev/null
+++ b/cpan/CPAN-Meta/t/prereqs.t
@@ -0,0 +1,121 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta::Prereqs;
+
+my $prereq_struct = {
+ runtime => {
+ requires => {
+ 'Config' => 0,
+ 'Cwd' => 0,
+ 'Data::Dumper' => 0,
+ 'ExtUtils::Install' => 0,
+ 'File::Basename' => 0,
+ 'File::Compare' => 0,
+ 'File::Copy' => 0,
+ 'File::Find' => 0,
+ 'File::Path' => 0,
+ 'File::Spec' => 0,
+ 'IO::File' => 0,
+ 'perl' => '5.005_03',
+ },
+ recommends => {
+ 'Archive::Tar' => '1.00',
+ 'ExtUtils::Install' => 0.3,
+ 'ExtUtils::ParseXS' => 2.02,
+ 'Pod::Text' => 0,
+ 'YAML' => 0.35,
+ },
+ },
+ build => {
+ requires => {
+ 'Test' => 0,
+ },
+ }
+};
+
+my $prereq = CPAN::Meta::Prereqs->new($prereq_struct);
+
+isa_ok($prereq, 'CPAN::Meta::Prereqs');
+
+is_deeply($prereq->as_string_hash, $prereq_struct, "round-trip okay");
+
+{
+ my $req = $prereq->requirements_for(qw(runtime requires));
+ my @req_mod = $req->required_modules;
+
+ ok(
+ (grep { 'Cwd' eq $_ } @req_mod),
+ "we got the runtime requirements",
+ );
+
+ ok(
+ (! grep { 'YAML' eq $_ } @req_mod),
+ "...but not the runtime recommendations",
+ );
+
+ ok(
+ (! grep { 'Test' eq $_ } @req_mod),
+ "...nor the build requirements",
+ );
+}
+
+{
+ my $req = $prereq->requirements_for(qw(runtime requires));
+ my $rec = $prereq->requirements_for(qw(runtime recommends));
+
+ my $merged = $req->clone->add_requirements($rec);
+
+ my @req_mod = $merged->required_modules;
+
+ ok(
+ (grep { 'Cwd' eq $_ } @req_mod),
+ "we got the runtime requirements",
+ );
+
+ ok(
+ (grep { 'YAML' eq $_ } @req_mod),
+ "...and the runtime recommendations",
+ );
+
+ ok(
+ (! grep { 'Test' eq $_ } @req_mod),
+ "...but not the build requirements",
+ );
+}
+
+{
+ my $req = $prereq->requirements_for(qw(runtime suggests));
+ my @req_mod = $req->required_modules;
+
+ is(@req_mod, 0, "empty set of runtime/suggests requirements");
+}
+
+{
+ my $req = $prereq->requirements_for(qw(develop suggests));
+ my @req_mod = $req->required_modules;
+
+ is(@req_mod, 0, "empty set of develop/suggests requirements");
+}
+
+{
+ my $new_prereq = CPAN::Meta::Prereqs->new;
+
+ $new_prereq
+ ->requirements_for(qw(runtime requires))
+ ->add_minimum(Foo => '1.000');
+
+ $new_prereq
+ ->requirements_for(qw(runtime requires))
+ ->add_minimum(Bar => '2.976');
+
+ is_deeply(
+ $new_prereq->as_string_hash,
+ { runtime => { requires => { Foo => '1.000', Bar => '2.976' } } },
+ 'we can accumulate new requirements on a prereq object',
+ );
+}
+
+done_testing;
+
diff --git a/cpan/CPAN-Meta/t/repository.t b/cpan/CPAN-Meta/t/repository.t
new file mode 100644
index 0000000000..b8800d913f
--- /dev/null
+++ b/cpan/CPAN-Meta/t/repository.t
@@ -0,0 +1,225 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+
+# 1.4 repository upgrade
+{
+ my $label = "(version 1.4) old repository winds up in 'url'";
+ my $meta = CPAN::Meta->new(
+ {
+ name => 'Module-Billed',
+ abstract => 'inscrutable',
+ version => '1',
+ author => 'Joe',
+ release_status => 'stable',
+ license => 'perl_5',
+ dynamic_config => 1,
+ generated_by => 'hand',
+ 'meta-spec' => {
+ version => '1.4',
+ url => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
+ },
+ resources => {
+ repository => 'http://example.com/',
+ },
+ },
+ { lazy_validation => 1 },
+ );
+
+ is_deeply(
+ $meta->resources,
+ {
+ repository => {
+ url => 'http://example.com/',
+ },
+ },
+ $label,
+ );
+}
+
+{
+ my $label = "(version 2 ) http in web passed through unchanged";
+ my $meta = CPAN::Meta->new(
+ {
+ name => 'Module-Billed',
+ abstract => 'inscrutable',
+ version => '1',
+ author => 'Joe',
+ release_status => 'stable',
+ license => 'perl_5',
+ dynamic_config => 1,
+ generated_by => 'hand',
+ 'meta-spec' => {
+ version => '2',
+ },
+ resources => {
+ repository => {
+ web => 'http://example.com/',
+ },
+ },
+ },
+ { lazy_validation => 1 },
+ );
+
+
+ is_deeply(
+ $meta->{resources},
+ {
+ repository => {
+ web => 'http://example.com/',
+ },
+ },
+ $label
+ );
+}
+
+{
+ my $label = "(version 2 ) http in url passed through unchanged";
+ my $meta = CPAN::Meta->new(
+ {
+ name => 'Module-Billed',
+ abstract => 'inscrutable',
+ version => '1',
+ author => 'Joe',
+ release_status => 'stable',
+ license => 'perl_5',
+ dynamic_config => 1,
+ generated_by => 'hand',
+ 'meta-spec' => {
+ version => '2',
+ },
+ resources => {
+ repository => {
+ url => 'http://example.com/',
+ },
+ },
+ },
+ { lazy_validation => 1 },
+ );
+
+
+ is_deeply(
+ $meta->{resources},
+ {
+ repository => {
+ url => 'http://example.com/',
+ },
+ },
+ $label
+ );
+}
+
+{
+ my $label = "(version 2 ) svn in url adds svn type";
+ my $meta = CPAN::Meta->new(
+ {
+ name => 'Module-Billed',
+ abstract => 'inscrutable',
+ version => '1',
+ author => 'Joe',
+ release_status => 'stable',
+ license => 'perl_5',
+ dynamic_config => 1,
+ generated_by => 'hand',
+ 'meta-spec' => {
+ version => '2',
+ },
+ resources => {
+ repository => {
+ url => 'svn://example.com/',
+ },
+ },
+ },
+ { lazy_validation => 1 },
+ );
+
+
+ is_deeply(
+ $meta->{resources},
+ {
+ repository => {
+ url => 'svn://example.com/',
+ type => 'svn',
+ },
+ },
+ $label
+ );
+}
+
+{
+ my $label = "(version 2 ) git in url adds svn type";
+ my $meta = CPAN::Meta->new(
+ {
+ name => 'Module-Billed',
+ abstract => 'inscrutable',
+ version => '1',
+ author => 'Joe',
+ release_status => 'stable',
+ license => 'perl_5',
+ dynamic_config => 1,
+ generated_by => 'hand',
+ 'meta-spec' => {
+ version => '2',
+ },
+ resources => {
+ repository => {
+ url => 'git://example.com/',
+ },
+ },
+ },
+ { lazy_validation => 1 },
+ );
+
+
+ is_deeply(
+ $meta->{resources},
+ {
+ repository => {
+ url => 'git://example.com/',
+ type => 'git',
+ },
+ },
+ $label
+ );
+}
+
+{
+ my $label = "(version 2 ) pre-existing type preserved";
+ my $meta = CPAN::Meta->new(
+ {
+ name => 'Module-Billed',
+ abstract => 'inscrutable',
+ version => '1',
+ author => 'Joe',
+ release_status => 'stable',
+ license => 'perl_5',
+ dynamic_config => 1,
+ generated_by => 'hand',
+ 'meta-spec' => {
+ version => '2',
+ },
+ resources => {
+ repository => {
+ url => 'git://example.com/',
+ type => 'msysgit',
+ },
+ },
+ },
+ { lazy_validation => 1 },
+ );
+
+
+ is_deeply(
+ $meta->{resources},
+ {
+ repository => {
+ url => 'git://example.com/',
+ type => 'msysgit',
+ },
+ },
+ $label
+ );
+}
+done_testing;
diff --git a/cpan/CPAN-Meta/t/save-load.t b/cpan/CPAN-Meta/t/save-load.t
new file mode 100644
index 0000000000..73cac57ea9
--- /dev/null
+++ b/cpan/CPAN-Meta/t/save-load.t
@@ -0,0 +1,99 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+use File::Temp 0.20 ();
+use Parse::CPAN::Meta 1.4400;
+
+my $distmeta = {
+ name => 'Module-Build',
+ abstract => 'Build and install Perl modules',
+ description => "Module::Build is a system for building, testing, "
+ . "and installing Perl modules. It is meant to be an "
+ . "alternative to ExtUtils::MakeMaker... blah blah blah",
+ version => '0.36',
+ author => [
+ 'Ken Williams <kwilliams@cpan.org>',
+ 'Module-Build List <module-build@perl.org>', # additional contact
+ ],
+ release_status => 'stable',
+ license => [ 'perl_5' ],
+ prereqs => {
+ runtime => {
+ requires => {
+ 'perl' => '5.006',
+ 'Config' => '0',
+ 'Cwd' => '0',
+ 'Data::Dumper' => '0',
+ 'ExtUtils::Install' => '0',
+ 'File::Basename' => '0',
+ 'File::Compare' => '0',
+ 'File::Copy' => '0',
+ 'File::Find' => '0',
+ 'File::Path' => '0',
+ 'File::Spec' => '0',
+ 'IO::File' => '0',
+ },
+ recommends => {
+ 'Archive::Tar' => '1.00',
+ 'ExtUtils::Install' => '0.3',
+ 'ExtUtils::ParseXS' => '2.02',
+ 'Pod::Text' => '0',
+ 'YAML' => '0.35',
+ },
+ },
+ build => {
+ requires => {
+ 'Test::More' => '0',
+ },
+ }
+ },
+ resources => {
+ license => ['http://dev.perl.org/licenses/'],
+ },
+ optional_features => {
+ domination => {
+ description => 'Take over the world',
+ prereqs => {
+ develop => { requires => { 'Genius::Evil' => '1.234' } },
+ runtime => { requires => { 'Machine::Weather' => '2.0' } },
+ },
+ },
+ },
+ dynamic_config => 1,
+ keywords => [ qw/ toolchain cpan dual-life / ],
+ 'meta-spec' => {
+ version => '2',
+ url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
+ },
+ generated_by => 'Module::Build version 0.36',
+};
+
+my $meta = CPAN::Meta->new( $distmeta );
+
+my $tmpdir = File::Temp->newdir();
+my $metafile = File::Spec->catfile( $tmpdir, 'META.json' );
+
+ok( $meta->save($metafile), "save returns true" );
+ok( -f $metafile, "save meta to file" );
+
+ok( my $loaded = Parse::CPAN::Meta->load_file($metafile), 'load saved file' );
+is($loaded->{name}, 'Module-Build', 'name correct');
+
+
+ok( $loaded = Parse::CPAN::Meta->load_file('t/data/META-1_4.yml'), 'load META-1.4' );
+is($loaded->{name}, 'Module-Build', 'name correct');
+
+# Test saving with conversion
+
+my $metayml = File::Spec->catfile( $tmpdir, 'META.yml' );
+
+$meta->save($metayml, {version => "1.4"});
+ok( -f $metayml, "save meta to META.yml with conversion" );
+
+ok( $loaded = Parse::CPAN::Meta->load_file($metayml), 'load saved file' );
+is( $loaded->{name}, 'Module-Build', 'name correct');
+is( $loaded->{requires}{perl}, "5.006", 'prereq correct' );
+
+done_testing;
diff --git a/cpan/CPAN-Meta/t/validator.t b/cpan/CPAN-Meta/t/validator.t
new file mode 100644
index 0000000000..e76fcc2eca
--- /dev/null
+++ b/cpan/CPAN-Meta/t/validator.t
@@ -0,0 +1,35 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+
+use CPAN::Meta;
+use CPAN::Meta::Validator;
+use File::Spec;
+use IO::Dir;
+use Parse::CPAN::Meta 1.4400;
+
+{
+ my $data_dir = IO::Dir->new( 't/data' );
+ my @files = sort grep { /^\w/ } $data_dir->read;
+
+ for my $f ( @files ) {
+ my $meta = Parse::CPAN::Meta->load_file( File::Spec->catfile('t','data',$f) );
+ my $cmv = CPAN::Meta::Validator->new({%$meta});
+ ok( $cmv->is_valid, "$f validates" )
+ or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) );
+ }
+}
+
+{
+ my $data_dir = IO::Dir->new( 't/data-fail' );
+ my @files = sort grep { /^\w/ } $data_dir->read;
+
+ for my $f ( @files ) {
+ my $meta = Parse::CPAN::Meta->load_file( File::Spec->catfile('t','data-fail',$f) );
+ my $cmv = CPAN::Meta::Validator->new({%$meta});
+ ok( ! $cmv->is_valid, "invalid $f doesn't validate" );
+ }
+}
+
+done_testing;
+