Module-CPANTS-Analyse-1.01/0000755000175000017500000000000013522716652015413 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/AUTHORS0000644000175000017500000000160212411273577016462 0ustar ishigakiishigaki=encoding UTF-8 =head1 NAME AUTHORS - Authors of and contributors to Module-CPANTS-Analyse =head2 Principal authors =over =item L =item L =item L =item L =item L =back =head2 Contributors =over =item L =item L =item L =item L =item L =back Many other people who provided unattributed patches, advice and bug reports are mentioned in the F file. Module-CPANTS-Analyse-1.01/lib/0000755000175000017500000000000013522716652016161 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/lib/Module/0000755000175000017500000000000013522716652017406 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/lib/Module/CPANTS/0000755000175000017500000000000013522716652020376 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee.pm0000644000175000017500000001104713522715156022502 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee; use 5.006; use strict; use warnings; use base qw(Class::Accessor::Fast); use Carp; use Module::Find qw(usesub); our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic __PACKAGE__->mk_accessors(qw(_available _total)); my @Plugins; my @SearchPaths = ('Module::CPANTS::Kwalitee'); my @Indicators; my %IndicatorHash; my $Total; my $Available; sub import { my ($class, @search_paths) = @_; for my $path (@search_paths) { next unless $path =~ /^[A-Za-z][A-Za-z0-9_]*(::[A-Za-z][A-Za-z0-9_]*)*$/; push @SearchPaths, $path =~ /^Module::CPANTS::/ ? $path : "Module::CPANTS::$path"; my %seen; @SearchPaths = grep {!$seen{$_}++} @SearchPaths; } } sub _load_plugins { my $class = shift; unless (@Plugins) { my %seen; @Plugins = sort {$a->order <=> $b->order or $a cmp $b} grep {!$seen{$_}++} map {usesub $_} @SearchPaths; $class->_cache_indicators; } } # I suppose nobody wants to change the generators dynamically though sub _cache_indicators { my $class = shift; @Indicators = (); $Total = $Available = 0; for my $plugin (@Plugins) { for my $indicator (@{$plugin->kwalitee_indicators}) { $indicator->{defined_in} = $plugin; $indicator->{is_core} = 1 if !$indicator->{is_extra} and !$indicator->{is_experimental}; push @Indicators, $indicator; $Total++ unless $indicator->{is_experimental}; $Available++ if $indicator->{is_core}; } } } sub plugins { @Plugins } sub new { my $class = shift; $class->_load_plugins; bless {}, $class; } sub generators { my $self = shift; return \@Plugins unless @_; @Plugins = @{$_[0]}; $self->_cache_indicators; \@Plugins; } sub get_indicators { my ($self, $type) = @_; unless ($type) { # almost always true return wantarray ? @Indicators : \@Indicators; } $type = 'is_core' if $type eq 'core'; $type = 'is_extra' if $type eq 'optional'; $type = 'is_experimental' if $type eq 'experimental'; my @indicators; for my $indicator (@Indicators) { next if !$indicator->{$type}; push @indicators, $indicator; } return wantarray ? @indicators : \@indicators; } sub get_indicators_hash { my $self = shift; return \%IndicatorHash if %IndicatorHash; foreach my $ind (@Indicators) { $IndicatorHash{$ind->{name}} = $ind; } return \%IndicatorHash; } sub available_kwalitee { $Available } sub total_kwalitee { $Total } sub _indicator_names { my ($self, $coderef) = @_; my @names = map { $_->{name} } grep {$coderef->($_)} $self->get_indicators; return wantarray ? @names : \@names; } sub all_indicator_names { shift->_indicator_names(sub {1}) } sub core_indicator_names { shift->_indicator_names(sub {$_->{is_core}}); } sub optional_indicator_names { shift->_indicator_names(sub {$_->{is_extra}}); } sub experimental_indicator_names { shift->_indicator_names(sub {$_->{is_experimental}}); } q{Favourite record of the moment: Jahcoozi: Pure Breed Mongrel}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee - Interface to Kwalitee generators =head1 SYNOPSIS my $mck = Module::CPANTS::Kwalitee->new; my @generators = $mck->generators; =head1 DESCRIPTION =head2 Methods =head3 new Plain old constructor. Loads all Plugins. =head3 get_indicators Get the list of all Kwalitee indicators, either as an ARRAY or ARRAYREF. =head3 get_indicators_hash Get the list of all Kwalitee indicators as an HASHREF. =head3 core_indicator_names Get a list of core indicator names (NOT the whole indicator HASHREF). =head3 optional_indicator_names Get a list of optional indicator names (NOT the whole indicator HASHREF). =head3 experimental_indicator_names Get a list of experimental indicator names (NOT the whole indicator HASHREF). =head3 all_indicator_names Get a list of all indicator names (NOT the whole indicator HASHREF). =head3 available_kwalitee Get the number of available kwalitee points =head3 total_kwalitee Get the total number of kwalitee points. This is bigger the available_kwalitee as some kwalitee metrics are marked as 'extra' (e.g. C). =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/0000755000175000017500000000000013522716652022143 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Pod.pm0000644000175000017500000001474313522715156023232 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Pod; use warnings; use strict; use File::Spec::Functions qw/catfile/; use Encode; use Data::Binary qw/is_binary/; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic our @ABSTRACT_STUBS = ( q{Perl extension for blah blah blah}, # h2xs q{[One line description of module's purpose here]}, # Module::Starter etc q{The great new}, # Module::Starter q{It's new $module}, # Minilla ); sub order { 100 } ################################################################## # Analyse ################################################################## sub analyse { my ($class, $me) = @_; my $distdir = $me->distdir; my %abstract; my @errors; for my $module (@{$me->d->{modules} || []}) { my ($package, $abstract, $error, $has_binary_data) = $class->_parse_abstract(catfile($distdir, $module->{file})); push @errors, "$error ($package)" if $error; $me->d->{abstracts_in_pod}{$package} = $abstract if $package; $me->d->{files_hash}{$module->{file}}{has_binary_data} = 1 if $has_binary_data; } # sometimes pod for .pm file is put into .pod for my $file (@{$me->d->{files_array} || []}) { next unless $file =~ /\.pod$/ && ($file =~ m!^lib/! or $file =~ m!^[^/]+$!); local $@; my ($package, $abstract, $error, $has_binary_data) = $class->_parse_abstract(catfile($distdir, $file)); push @errors, "$error ($package)" if $error; $me->d->{abstracts_in_pod}{$package} = $abstract if $package; $me->d->{files_hash}{$file}{has_binary_data} = 1 if $has_binary_data; } $me->d->{error}{has_abstract_in_pod} = join ';', @errors if @errors; } # adapted from ExtUtils::MM_Unix and Module::Build::PodParser sub _parse_abstract { my ($class, $file) = @_; my ($package, $abstract); my $inpod = 0; open my $fh, '<', $file or return; my $directive; my $encoding; my $package_name_pattern = '(?:[A-Za-z0-9_]+::)*[A-Za-z0-9_]+ | [BCIF] < (?:[A-Za-z0-9_]+::)*[A-Za-z0-9_]+ >'; if ( $file !~ /\.p(?:m|od)$/ ) { $package_name_pattern .= ' | [A-Za-z0-9_.-]+ | [BCIF] < [A-Za-z0-9_.-]+ >'; } while(<$fh>) { if (/^\s*__DATA__\s*$/) { my $copy = $_ = <$fh>; last unless defined $copy; return (undef, undef, undef, 1) if is_binary($copy); } if (substr($_, 0, 1) eq '=') { if (/^=encoding\s+(.+)/) { $encoding = $1; } if (/^=cut/) { $inpod = 0; } elsif (/^=(?!cut)(.+)/) { $directive = $1; $inpod = 1; } } next if !$inpod; next unless $directive =~ /^head/; if ( /^\s*(${package_name_pattern}) \s+ -+ (?:\s+ (.*)\s*$|$)/x ) { ($package, $abstract) = ($1, $2); $package =~ s![BCIF]<([^>]+)>!$1!; next; } next unless $abstract; last if /^\s*$/ || /^=/; s/\s+$//s; $abstract .= "\n$_"; } my $error; if ($encoding && $abstract) { my $encoder = find_encoding($encoding); if (!$encoder) { $error = "unknown encoding: $encoding"; } else { $abstract = eval { $encoder->decode($abstract) }; if ($@) { $error = $@; $error =~ s|\s*at .+ line \d+.+$||s; } } } return ($package, $abstract, $error); } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { return [ { name => 'has_abstract_in_pod', error => q{No abstract (short description of a module) is found in pod from this distribution.}, remedy => q{Provide a short description in the NAME section of the pod (after the module name followed by a hyphen) at least for the main module of this distribution.}, code => sub { my $d = shift; return 0 if $d->{error}{has_abstract_in_pod}; my @abstracts = grep {defined $_ && length $_} values %{$d->{abstracts_in_pod} || {}}; return @abstracts ? 1 : 0; }, details => sub { my $d = shift; return "No abstracts in pod"; }, }, { name => 'no_abstract_stub_in_pod', is_extra => 1, error => q{A well-known abstract stub (typically generated by an authoring tool) is found in this distribution.}, remedy => q{Modify the stub. You might need to modify other stubs (for name, synopsis, license, etc) as well.}, code => sub { my $d = shift; my %mapping = map {$_ => 1} @ABSTRACT_STUBS; my @errors; for (sort keys %{$d->{abstracts_in_pod} || {}}) { push @errors, $_ if $mapping{$d->{abstracts_in_pod}{$_} || ''}; } if (@errors) { $d->{error}{no_abstract_stub_in_pod} = join ',', @errors; } return @errors ? 0 : 1; }, details => sub { my $d = shift; my %mapping = map {$_ => 1} @ABSTRACT_STUBS; return "Abstracts in the following packages are stubs:". $d->{error}{no_abstract_stub_in_pod}; }, }, ]; } q{Favourite record of the moment: Fat Freddys Drop: Based on a true story}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Pod - Check Pod =head1 SYNOPSIS Some of the check in this module has moved to L to double-check the pod correctness on the server side. If you do care, it is recommended to add a test to test pod (with L) in "xt/" directory in your distribution. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>. =head3 analyse Parses pod to see if it has a proper abstract. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over 4 =item * has_abstract_in_pod =item * no_abstract_stub_in_pod =back =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Signature.pm0000644000175000017500000000265613522715156024451 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Signature; use strict; use warnings; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 100 } sub analyse { my ($class, $self) = @_; # NOTE: The analysis/metric in this module has moved to # Module::CPANTS::SiteKwalitee because this requires an external # tool (though optional) and decent network connection to # validate a signature. # Note also that this stub should not be removed so that # this can replace the old ::Signature module, and the old # metrics will not be loaded while loading plugins. } sub kwalitee_indicators { return []; } 1; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Signature - dist has a valid signature =head1 SYNOPSIS The metrics in this module have moved to L. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>. =head3 analyse Does nothing now. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =head1 SEE ALSO L =head1 AUTHOR Lars Dɪᴇᴄᴋᴏᴡ C<< >> =head1 LICENCE AND COPYRIGHT Copyright © 2012, Lars Dɪᴇᴄᴋᴏᴡ C<< >>. This module is free software; you can redistribute it and/or modify it under the same terms as Perl 5.14. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Distname.pm0000644000175000017500000000364513522715156024253 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Distname; use warnings; use strict; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 20 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; # NOTE: The analysis code has moved to ::Analyse to avoid # duplication. # Note also that this stub should not be removed so that # this can replace the old ::Distname module, and the old # metrics will not be loaded while loading plugins. return; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { # NOTE: The metrics in this module have moved to # Module::CPANTS::SiteKwalitee because these require an archived # distribution which you don't have while testing local Kwalitee # with Test::Kwalitee. return []; } q{Favourite record of the moment: Fat Freddys Drop: Based on a true story}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Distname - Proper Distname layout =head1 SYNOPSIS The metrics in this module have moved to L. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<20>. =head3 analyse Does nothing now. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =back =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Repackageable.pm0000644000175000017500000000350313522715156025206 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Repackageable; use warnings; use strict; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 900 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; # NOTE: The analysis/metric in this module has moved to # Module::CPANTS::SiteKwalitee. # Note also that this stub should not be removed so that # this can replace the old ::Repackageable module, and the old # metrics will not be loaded while loading plugins. return; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators{ return []; } q{Favourite record of the moment: Lili Allen - Allright, still}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Repackageable - Checks for various signs that make a module packageable =head1 SYNOPSIS The metrics in this module have moved to L. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. =head3 analyse =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =head1 SEE ALSO L =head1 AUTHOR L and L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2009 L Copyright © 2006–2008 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/BrokenInstaller.pm0000644000175000017500000001156013522715156025600 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::BrokenInstaller; use warnings; use strict; use File::Spec::Functions qw(catfile); our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 100 } sub analyse { my $class = shift; my $me = shift; my $distdir = $me->distdir; # inc/Module/Install.pm file my $mi = catfile($distdir, 'inc', 'Module', 'Install.pm'); # Must be okay if not using Module::Install return if not -f $mi; open my $ih, '<', $mi or die "Could not open file '$mi' for checking the bad_installer metric: $!"; my $buf; read $ih, $buf, 100000 or die $!; close $ih; if ($buf =~ /VERSION\s*=\s*("|'|)(\d+|\d*\.\d+(?:_\d+)?)\1/m) { $me->d->{module_install}{version} = my $version = $2; my $non_devel = $version; $non_devel =~ s/_\d+$//; if ($non_devel < 0.61 or $non_devel == 1.04) { $me->d->{module_install}{broken} = 1; } if ($non_devel < 0.89) { my $makefilepl = catfile($distdir, 'Makefile.PL'); return if not -f $makefilepl; open my $ih, '<', $makefilepl or die "Could not open file '$makefilepl' for checking the bad_installer metric: $!"; local $/ = undef; my $mftext = <$ih>; close $ih; return if not defined $mftext; if ($mftext =~ /auto_install/) { $me->d->{module_install}{broken_auto_install} = 1; } else { return; } if ($non_devel < 0.64) { $me->d->{module_install}{broken} = 1; } } } else { # Unknown version (parsing $VERSION failed) $me->d->{module_install}{broken} = 1; } return; } sub kwalitee_indicators { return [ { name => 'no_broken_module_install', error => q{This distribution uses an obsolete version of Module::Install. Versions of Module::Install prior to 0.61 might not work on some systems at all. Additionally if your Makefile.PL uses the 'auto_install()' feature, you need at least version 0.64. Also, 1.04 is known to be broken.}, remedy => q{Upgrade the bundled version of Module::Install to the most current release. Alternatively, you can switch to another build system / installer that does not suffer from this problem. (ExtUtils::MakeMaker, Module::Build both of which have their own set of problems.)}, code => sub { my $d = shift; return 1 unless exists $d->{module_install}; $d->{module_install}{broken} ? 0 : 1; }, details => sub { q{This distribution uses obsolete Module::Install version }.(shift->{module_install}{version}); }, }, { name => 'no_broken_auto_install', error => q{This distribution uses an old version of Module::Install. Versions of Module::Install prior to 0.89 do not detect correctly that CPAN/CPANPLUS shell is used.}, remedy => q{Upgrade the bundled version of Module::Install to at least 0.89, but preferably to the most current release. Alternatively, you can switch to another build system / installer that does not suffer from this problem. (ExtUtils::MakeMaker, Module::Build both of which have their own set of problems.)}, code => sub { my $d = shift; return 1 unless exists $d->{module_install}; $d->{module_install}{broken_auto_install} ? 0 : 1; }, details => sub { q{This distribution uses obsolete Module::Install version }.(shift->{module_install}{version}); }, }, ]; } 1 __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::BrokenInstaller - Check for broken Module::Install =head1 SYNOPSIS Find out whether the distribution uses an outdated version of Module::Install. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>, as data generated by this should not be used by any other tests. =head3 analyse C checks whether the distribution uses Module::Install and if so whether it uses a reasonably current version of it (0.61 or later). It also checks whether the F uses the C feature. If so, C should be at least version 0.64. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =item * no_broken_module_install =item * no_broken_auto_install =back =head1 SEE ALSO L =head1 AUTHOR L L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2009 L Copyright © 2006 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/MetaYML.pm0000644000175000017500000002672113522715156023757 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::MetaYML; use warnings; use strict; use File::Spec::Functions qw(catfile); use CPAN::Meta::YAML; use CPAN::Meta::Validator; use CPAN::Meta::Converter; use List::Util qw/first/; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 10 } my $JSON_DECODER = _load_json_decoder() || do { require JSON::PP; JSON::PP->can('decode_json') }; ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; my $distdir = $me->distdir; my $meta_yml = catfile($distdir, 'META.yml'); my $meta_json = catfile($distdir, 'META.json'); my $mymeta_yml = catfile($distdir, 'MYMETA.yml'); # META.yml is not always the most preferred meta file, # but test it anyway because it may be broken sometimes. if (-f $meta_yml && -r _) { _analyse_yml($me, $meta_yml); } # check also META.json (if exists). if (-f $meta_json && -r _) { _analyse_json($me, $meta_json); } # If, and only if META.yml and META.json don't exist, # try MYMETA.yml if (!$me->d->{meta_yml} && -f $mymeta_yml && -r _) { _analyse_yml($me, $mymeta_yml); } if (!$me->d->{meta_yml}) { return; } # Theoretically it might be better to convert 1.* to 2.0. # However, converting 2.0 to 1.4 is much cheaper for CPANTS # website as it's much rarer as of this writing. if (($me->d->{meta_yml_spec_version} || '1.0') gt '1.4') { my $cmc = CPAN::Meta::Converter->new($me->d->{meta_yml}); my $meta_14 = eval { $cmc->convert(version => '1.4') }; if (!$@ && $meta_14) { $me->d->{meta_yml} = $meta_14; } } $me->d->{dynamic_config} = (!exists $me->d->{meta_yml}{dynamic_config} or $me->d->{meta_yml}{dynamic_config}) ? 1 : 0; } sub _analyse_yml { my ($me, $file) = @_; my @warnings; eval { # CPAN::Meta::YAML warns if it finds a duplicate key local $SIG{__WARN__} = sub { push @warnings, @_ }; my $meta = CPAN::Meta::YAML->read($file) or die CPAN::Meta::YAML->errstr; # Broken META.yml may return a "YAML 1.0" string first. # eg. M/MH/MHASCH/Date-Gregorian-0.07.tar.gz if (@$meta > 1 or ref $meta->[0] ne ref {}) { $me->d->{meta_yml} = first { ref $_ eq ref {} } @$meta; $me->d->{error}{meta_yml_is_parsable} = "multiple parts found in META.yml"; } else { $me->d->{meta_yml} = $meta->[0]; $me->d->{meta_yml_is_parsable} = 1; } }; if (my $error = $@) { $error =~ s/ at \S+ line \d+.+$//s; $me->d->{error}{meta_yml_is_parsable} = $error; } if ($me->d->{meta_yml}) { my ($spec, $error) = _validate_meta($me->d->{meta_yml}); $me->d->{error}{meta_yml_conforms_to_known_spec} = $error if $error; $me->d->{meta_yml_spec_version} = $spec->{spec}; } if (@warnings) { $me->d->{error}{meta_yml_has_duplicate_keys} = join ',', @warnings; } } sub _analyse_json { my ($me, $file) = @_; my $meta; eval { my $json = do { open my $fh, '<', $file or die "$file: $!"; local $/; <$fh> }; $meta = $JSON_DECODER->($json); $me->d->{meta_json_is_parsable} = 1; }; if (my $error = $@) { $error =~ s/ at \S+ line \d+.+$//s; $me->d->{error}{meta_json_is_parsable} = $error; } if ($meta) { my ($spec, $error) = _validate_meta($meta); $me->d->{error}{meta_json_conforms_to_known_spec} = $error if $error; $me->d->{meta_json_spec_version} = $spec->{spec}; } if (!$me->d->{meta_yml}) { $me->d->{meta_yml} = $meta; $me->d->{meta_yml_spec_version} = $me->d->{meta_json_spec_version}; $me->d->{meta_yml_is_meta_json} = 1; } } sub _load_json_decoder { my $json_class = $ENV{CPAN_META_JSON_BACKEND} || $ENV{PERL_JSON_BACKEND} || 'JSON::PP'; eval "require $json_class; 1" or return; $json_class->can('decode_json'); } sub _validate_meta { my $meta = shift; my $error; my $spec = eval { CPAN::Meta::Validator->new($meta) }; if ($error = $@) { $error =~ s/ at \S+ line \d+.+$//s; } elsif (!$spec->is_valid) { $error = join ';', sort $spec->errors; } $error =~ s/(SCALAR|ARRAY|HASH|GLOB|REF)\(0x[0-9a-f]+\)/$1(...)/g; return ($spec, $error); } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators{ return [ { name => 'meta_yml_is_parsable', error => q{The META.yml file of this distribution could not be parsed by the version of CPAN::Meta::YAML.pm CPANTS is using.}, remedy => q{Upgrade your YAML generator so it produces valid YAML.}, code => sub { my $d = shift; !$d->{error}{meta_yml_is_parsable} ? 1 : 0 }, details => sub { my $d = shift; $d->{error}{meta_yml_is_parsable}; }, }, { name => 'meta_json_is_parsable', error => q{The META.json file of this distribution could not be parsed by the version of JSON parser CPANTS is using.}, remedy => q{Upgrade your META.json generator so it produces valid JSON.}, code => sub { my $d = shift; !$d->{error}{meta_json_is_parsable} ? 1 : 0 }, details => sub { my $d = shift; $d->{error}{meta_json_is_parsable}; }, }, { name => 'meta_yml_has_provides', is_experimental => 1, error => q{This distribution does not have a list of provided modules defined in META.yml.}, remedy => q{Add all modules contained in this distribution to the META.yml field 'provides'. Module::Build or Dist::Zilla::Plugin::MetaProvides do this automatically for you.}, code => sub { my $d = shift; return 1 if !$d->{meta_yml}; return 1 if $d->{meta_yml}{provides}; return 0; }, details => sub { my $d = shift; return "No META.yml." unless $d->{meta_yml}; return q{No "provides" was found in META.yml.}; }, }, { name => 'meta_yml_conforms_to_known_spec', error => q{META.yml does not conform to any recognised META.yml Spec.}, remedy => q{Take a look at the META.yml Spec at https://metacpan.org/pod/CPAN::Meta::History::Meta_1_4 (for version 1.4) or https://metacpan.org/pod/CPAN::Meta::Spec (for version 2), and change your META.yml accordingly.}, code => sub { my $d = shift; return 0 if $d->{error}{meta_yml_conforms_to_known_spec}; return 1; }, details => sub { my $d = shift; return "No META.yml." unless $d->{meta_yml}; return "META.yml is broken." unless $d->{meta_yml_is_parsable}; return $d->{error}{meta_yml_conforms_to_known_spec}; }, }, { name => 'meta_json_conforms_to_known_spec', error => q{META.json does not conform to any recognised META Spec.}, remedy => q{Take a look at the META.json Spec at https://metacpan.org/pod/CPAN::Meta::History::Meta_1_4 (for version 1.4) or https://metacpan.org/pod/CPAN::Meta::Spec (for version 2), and change your META.json accordingly.}, code => sub { my $d = shift; return 0 if $d->{error}{meta_json_is_parsable}; return 0 if $d->{error}{meta_json_conforms_to_known_spec}; return 1; }, details => sub { my $d = shift; return "META.json is broken." unless $d->{meta_json_is_parsable}; return $d->{error}{meta_json_conforms_to_known_spec}; }, }, { name => 'meta_yml_declares_perl_version', error => q{This distribution does not declare the minimum perl version in META.yml.}, is_extra => 1, remedy => q{If you are using Build.PL define the {requires}{perl} = VERSION field. If you are using MakeMaker (Makefile.PL) you should upgrade ExtUtils::MakeMaker to 6.48 and use MIN_PERL_VERSION parameter. Perl::MinimumVersion can help you determine which version of Perl your module needs.}, code => sub { my $d = shift; my $yaml = $d->{meta_yml}; return 1 unless $yaml; return ref $yaml->{requires} eq ref {} && $yaml->{requires}{perl} ? 1 : 0; }, details => sub { my $d = shift; my $yaml = $d->{meta_yml}; return "No META.yml." unless $yaml; return q{No "requires" was found in META.yml.} unless ref $yaml->{requires} eq ref {}; return q{No "perl" subkey was found in META.yml.} unless $yaml->{requires}{perl}; }, }, { name => 'meta_yml_has_repository_resource', is_experimental => 1, error => q{This distribution does not have a link to a repository in META.yml.}, remedy => q{Add a 'repository' resource to the META.yml via 'meta_add' accessor (for Module::Build) or META_ADD parameter (for ExtUtils::MakeMaker).}, code => sub { my $d = shift; my $yaml = $d->{meta_yml}; return 1 unless $yaml; return ref $yaml->{resources} eq ref {} && $yaml->{resources}{repository} ? 1 : 0; }, details => sub { my $d = shift; my $yaml = $d->{meta_yml}; return "No META.yml." unless $yaml; return q{No "resources" was found in META.yml.} unless ref $yaml->{resources} eq ref {}; return q{No "repository" subkey was found in META.yml.} unless $yaml->{resources}{repository}; }, }, ]; } q{Barbies Favourite record of the moment: Nine Inch Nails: Year Zero}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::MetaYML - Checks data available in META.yml =head1 SYNOPSIS Checks various pieces of information in F =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<10>. C should be checked earlier than C to handle C correctly. =head3 analyse C checks C. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =item * meta_yml_is_parsable =item * meta_yml_has_provides =item * meta_yml_conforms_to_known_spec =item * meta_yml_declares_perl_version =item * meta_yml_has_repository_resource =item * meta_json_is_parsable =item * meta_json_conforms_to_known_spec =back =head1 SEE ALSO L =head1 AUTHOR L and L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2009 L Copyright © 2006–2008 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Uses.pm0000644000175000017500000002603713522715156023426 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Uses; use warnings; use strict; use File::Spec::Functions qw(catfile); use Perl::PrereqScanner::NotQuiteLite 0.9901; use List::Util 1.33 qw/none/; use version; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic # These equivalents should be reasonably well-known and, preferably, # well-documented. Don't add obscure modules used by only one person # or a few people, to keep the list relatively small and to encourage # people to use a better equivalent. # "use_(strict|warnings)" should fail if someone feels the need # to add "use $1;" in the modules. our @STRICT_EQUIV = qw( strict ); our @WARNINGS_EQUIV = qw( warnings warnings::compat ); our @STRICT_WARNINGS_EQUIV = qw( common::sense Any::Moose Catmandu::Sane Coat Dancer Mo Mu Modern::Perl Moo Moo::Role Moose Moose::Role Moose::Exporter Moose::Util::TypeConstraints Moose::Util::MetaRole MooseX::Declare MooseX::Role::Parameterized MooseX::Types Mouse Mouse::Role perl5 perl5i::1 perl5i::2 perl5i::latest Pegex::Base Role::Tiny strictures ); # These modules require a flag to enforce strictness. push @STRICT_WARNINGS_EQUIV, qw( Mojo::Base Spiffy ); sub order { 100 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; my $distdir = $me->distdir; my $modules = $me->d->{modules}; my $files = $me->d->{files_hash}; # NOTE: all files in xt/ should be ignored because they are # for authors only and their dependencies may not be (and # often are not) listed in meta files. my @test_files = grep {m!^t\b.*\.t$!} sort keys %$files; $me->d->{test_files} = \@test_files; my %test_modules = map { my $m = my $f = $_; $m =~ s|\.pm$||; $m =~ s|/|::|g; (my $m0 = $m) =~ s|^t::(?:lib::)?||; ($m => $f, $m0 => $f) } grep {m|^t\b.*\.pm$|} keys %$files; my %skip=map {$_->{module}=>1 } @$modules; # d->{versions} (from SiteKwalitee) knows inner packages as well if (my $versions = $me->d->{versions}) { for my $file (keys %$versions) { for my $module (keys %{$versions->{$file}}) { $skip{$module} = 1; } } } my %uses; my $scanner = Perl::PrereqScanner::NotQuiteLite->new( parsers => [':bundled'], suggests => 1, recommends => 1, quick => 1, ); # modules my @module_files = map {$_->{file}} grep {!$_->{not_exists}} @$modules; # Makefile.PL runs other Makefile.PL files at configure time (except ones under t) # Build.PL runs other *.PL files at build time my @configure_files = grep {/(?:^Build|\bMakefile)\.PL$/ && !/^t[\\\/]/} @{$me->d->{files_array} || []}; my %configure_files_map = map {$_ => 1} @configure_files; # Other *.PL files (including lib/Build.PL) would (probably) be run at bulid time my @build_files = grep {/\.PL$/ && !/^t[\\\/]/ && !$configure_files_map{$_}} @{$me->d->{files_array} || []}; $uses{runtime} = $class->_scan($scanner, $files, $distdir, \@module_files); $uses{configure} = $class->_scan($scanner, $files, $distdir, \@configure_files); $uses{build} = $class->_scan($scanner, $files, $distdir, \@build_files); $uses{test} = $class->_scan($scanner, $files, $distdir, \@test_files); # See also .pm files under t (only) if they are used in .t files my $test_requirements = $uses{test}{requires}->as_string_hash; my @test_pmfiles; for my $module (keys %$test_requirements) { push @test_pmfiles, $test_modules{$module} if $test_modules{$module}; } my $additional_test_requirements = $class->_scan($scanner, $files, $distdir, \@test_pmfiles); for my $relationship (keys %$additional_test_requirements) { $uses{test}{$relationship} = ($uses{test}{$relationship}) ? $uses{test}{$relationship}->add_requirements($additional_test_requirements->{$relationship}) : $additional_test_requirements->{$relationship}; } for my $phase (keys %uses) { for my $relationship (keys %{$uses{$phase}}) { my $requirements = $uses{$phase}{$relationship}->as_string_hash; for my $requirement (keys %$requirements) { if ( $skip{$requirement} or $requirement =~ /^(?:inc|t)::/ or ($phase eq 'test' and $test_modules{$requirement}) ) { delete $requirements->{$requirement}; } } if (%$requirements) { $uses{$phase}{$relationship} = $requirements; } else { delete $uses{$phase}{$relationship}; } } delete $uses{$phase} unless %{$uses{$phase}}; } $me->d->{uses} = \%uses; return; } sub _scan { my ($class, $scanner, $files_hash, $distdir, $files) = @_; my @methods = qw/requires recommends suggests noes/; my %reqs = map {$_ => CPAN::Meta::Requirements->new} @methods; for my $file (@$files) { my $ctx = $scanner->scan_file("$distdir/$file"); # There may be broken files (intentionally, or unintentionally, esp in tests) if (@{$ctx->{errors} || []}) { my $error = join ',', @{$ctx->{errors}}; $error =~ s/ at \S+ line \d+[^\n]*//gs; $error =~ s/Scan Error: //g; $files_hash->{$file}{scan_error} = $error; } if ($ctx->{perl6}) { $files_hash->{$file}{perl6} = 1; next; } for my $method (@methods) { my $requirements = $ctx->$method; my $hash = $requirements->as_string_hash; next unless %$hash; $files_hash->{$file}{$method} = $hash; $reqs{$method} = $reqs{$method}->add_requirements($requirements); } } return \%reqs; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { return [ { name => 'use_strict', error => q{This distribution does not 'use strict;' (or its equivalents) in all of its modules. Note that this is not about the actual strictness of the modules. It's bad if nobody can tell whether the modules are strictly written or not, without reading the source code of your favorite clever module that actually enforces strictness. In other words, it's bad if someone feels the need to add 'use strict' to your modules.}, remedy => q{Add 'use strict' (or its equivalents) to all modules, or convince us that your favorite module is well-known enough and people can easily see the modules are strictly written.}, ignorable => 1, code => sub { my $d = shift; my $files = $d->{files_hash} || {}; my $perl_version_with_implicit_stricture = version->new('5.011')->numify; my @no_strict; for my $file (keys %$files) { next unless exists $files->{$file}{module}; next if $files->{$file}{unreadable}; next if $files->{$file}{perl6}; next if $file =~ /\.pod$/; my $module = $files->{$file}{module}; my $requires = $files->{$file}{requires} || {}; my $required_perl = $requires->{perl}; if (defined $required_perl) { $required_perl =~ s/_//; # tweak 5.008_001 and the likes for silence next if version->parse($required_perl)->numify >= $perl_version_with_implicit_stricture; } # There are lots of acceptable strict alternatives push @no_strict, $module if none {exists $requires->{$_}} (@STRICT_EQUIV, @STRICT_WARNINGS_EQUIV); } if (@no_strict) { $d->{error}{use_strict} = join ", ", sort @no_strict; return 0; } return 1; }, details => sub { my $d = shift; return "The following modules don't use strict (or equivalents): " . $d->{error}{use_strict}; }, }, { name => 'use_warnings', error => q{This distribution does not 'use warnings;' (or its equivalents) in all of its modules. Note that this is not about that your modules actually warn when something bad happens. It's bad if nobody can tell if a module warns or not, without reading the source code of your favorite module that actually enforces warnings. In other words, it's bad if someone feels the need to add 'use warnings' to your modules.}, is_extra => 1, ignorable => 1, remedy => q{Add 'use warnings' (or its equivalents) to all modules, or convince us that your favorite module is well-known enough and people can easily see the modules warn when something bad happens.}, code => sub { my $d = shift; my $files = $d->{files_hash} || {}; my @no_warnings; for my $file (keys %$files) { next unless exists $files->{$file}{module}; next if $files->{$file}{unreadable}; next if $files->{$file}{perl6}; next if $file =~ /\.pod$/; my $module = $files->{$file}{module}; my $requires = $files->{$file}{requires} || {}; push @no_warnings, $module if none {exists $requires->{$_}} (@WARNINGS_EQUIV, @STRICT_WARNINGS_EQUIV); } if (@no_warnings) { $d->{error}{use_warnings} = join ", ", sort @no_warnings; return 0; } return 1; }, details => sub { my $d = shift; return "The following modules don't use warnings (or equivalents): " . $d->{error}{use_warnings}; }, }, ]; } q{Favourite record of the moment: Fat Freddys Drop: Based on a true story}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Uses - Checks which modules are used =head1 SYNOPSIS Check which modules are actually used in the code. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>. =head3 analyse C uses C to find all C statements in code (actual code and tests). =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =item * use_strict =item * use_warnings =back =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Prereq.pm0000644000175000017500000002605213522715156023742 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Prereq; use warnings; use strict; use File::Spec::Functions qw(catfile); use Text::Balanced qw/extract_bracketed/; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 100 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; $class->_from_meta($me) or $class->_from_cpanfile($me) or $class->_from_build_pl($me) or $class->_from_makefile_pl($me) or $class->_from_dist_ini($me); } sub _from_meta { my ($class, $me) = @_; my $meta = $me->d->{meta_yml}; return unless $meta && ref $meta eq ref {}; my $spec = $meta->{'meta-spec'}; my %res; if ($spec && ref $spec eq ref {} && ($spec->{version} || 0) =~ /^(\d+)/ && $1 >= 2) { # meta spec ver2 my $prereqs = $meta->{prereqs}; %res = $class->_handle_prereqs_v2($meta->{prereqs}); } else { # meta spec ver1 my %map = ( requires => 'is_prereq', build_requires => 'is_build_prereq', recommends => 'is_optional_prereq', ); for my $rel (qw/requires recommends build_requires configure_requires conflicts/) { if ($meta->{$rel} && ref $meta->{$rel} eq ref {}) { my $prereqs_r = $meta->{$rel}; next unless $prereqs_r && ref $prereqs_r eq ref {}; for my $module (keys %$prereqs_r) { my $type = $rel =~ /_/ ? $rel : "runtime_$rel"; push @{$res{$module} ||= []}, { requires => $module, version => $prereqs_r->{$module}, type => $type, ($map{$rel} ? ($map{$rel} => 1) : ()), }; } } } # TODO: optional_features handling } return unless %res; $me->d->{prereq} = [sort {$a->{requires} cmp $b->{requires}} map {@$_} values %res]; $me->d->{got_prereq_from} = 'META.yml'; } sub _from_cpanfile { my ($class, $me) = @_; my $cpanfile = catfile($me->distdir, "cpanfile"); return unless -f $cpanfile; eval { require Module::CPANfile; 1 }; return if $@; my $prereqs = Module::CPANfile->load($cpanfile)->prereqs->as_string_hash; my %res = $class->_handle_prereqs_v2($prereqs); return unless %res; $me->d->{prereq} = [sort {$a->{requires} cmp $b->{requires}} map {@$_} values %res]; $me->d->{got_prereq_from} = 'cpanfile'; } sub _from_build_pl { my ($class, $me) = @_; my $build_pl_file = catfile($me->distdir, "Build.PL"); return unless -f $build_pl_file; my $build_pl = do { local $/; open my $fh, '<', $build_pl_file; <$fh> }; return unless $build_pl; my %map = ( requires => 'is_prereq', build_requires => 'is_build_prereq', test_requires => 'is_build_prereq', recommends => 'is_optional_prereq', ); my %res; # TODO: auto_features while($build_pl =~ s/^.*?((?:(?:configure|build|test)_)?requires|recommends|conflicts)\s*=>\s*\{/{/s) { my $rel = $1; my ($block, $left) = extract_bracketed($build_pl, '{}'); last unless $block; my $hashref = do { no strict; no warnings; eval $block }; ## no critic if ($hashref && ref $hashref eq ref {}) { for my $module (keys %$hashref) { my $type = $rel =~ /_/ ? $rel : "runtime_$rel"; my ($version) = ($hashref->{$module} || 0) =~ /^([0-9.]+)/; push @{$res{$module} ||= []}, { requires => $module, version => $version, type => $type, ($map{$rel} ? ($map{$rel} => 1) : ()), }; } } $build_pl = $left; } $me->d->{prereq} = [sort {$a->{requires} cmp $b->{requires}} map {@$_} values %res]; $me->d->{got_prereq_from} = 'Build.PL'; } sub _from_makefile_pl { my ($class, $me) = @_; my $distdir = $me->distdir; my %map = ( PREREQ_PM => 'is_prereq', BUILD_REQUIRES => 'is_build_prereq', TEST_REQUIRES => 'is_build_prereq', ); # There may be multiple Makefile.PLs in a distribution my %res; for my $file (@{$me->d->{files_array} || []}) { next unless $file =~ /Makefile\.PL$/; my $makefile_pl_file = catfile($distdir, $file); next unless -f $makefile_pl_file; my $makefile_pl = do { local $/; open my $fh, '<', $makefile_pl_file; <$fh> }; next unless $makefile_pl; if ($makefile_pl =~ /use\s+inc::Module::Install/) { # Module::Install # TODO while($makefile_pl =~ s/(?:^|;).+?((?:(?:configure|build|test)_)?requires|recommends)\s*([^;]+);//s) { my ($rel, $tuple_text) = ($1, $2); my @tuples = do { no strict; no warnings; eval $tuple_text }; ## no critic my $type = $rel =~ /_/ ? $rel : "runtime_$rel"; while(@tuples) { my $module = shift @tuples or last; my $version = shift @tuples || 0; push @{$res{$module} ||= []}, { requires => $module, version => $version, type => $type, ($map{$rel} ? ($map{$rel} => 1) : ()), }; } } } else { # EUMM while($makefile_pl =~ s/^.*?((?:BUILD|TEST)_REQUIRES|PREREQ_PM)\s*=>\s*\{/{/s) { my $rel = $1; my ($block, $left) = extract_bracketed($makefile_pl, '{}'); last unless $block; my $hashref = do { no strict; no warnings; eval $block }; ## no critic if ($hashref && ref $hashref eq ref {}) { for my $module (keys %$hashref) { my $type = $rel eq 'PREREQ_PM' ? "runtime_requires" : lc $rel; push @{$res{$module} ||= []}, { requires => $module, version => $hashref->{$module}, type => $type, ($map{$rel} ? ($map{$rel} => 1) : ()), }; } } $makefile_pl = $left; } } } $me->d->{prereq} = [sort {$a->{requires} cmp $b->{requires}} map {@$_} values %res]; $me->d->{got_prereq_from} = 'Makefile.PL'; } # for META spec v2 and cpanfile sub _handle_prereqs_v2 { my ($class, $prereqs) = @_; return unless $prereqs && ref $prereqs eq ref {}; # XXX: this mapping is for backward compat only my %map = ( runtime_requires => 'is_prereq', build_requires => 'is_build_prereq', test_requires => 'is_build_prereq', runtime_recommends => 'is_optional_prereq', build_recommends => 'is_optional_prereq', test_recommends => 'is_optional_prereq', runtime_suggests => 'is_optional_prereq', build_suggests => 'is_optional_prereq', test_suggests => 'is_optional_prereq', ); my %res; for my $phase (keys %$prereqs) { my $prereqs_p = $prereqs->{$phase}; next unless $prereqs_p && ref $prereqs_p eq ref {}; for my $rel (keys %$prereqs_p) { my $prereqs_r = $prereqs_p->{$rel}; next unless $prereqs_r && ref $prereqs_r eq ref {}; for my $module (keys %$prereqs_r) { my $type = join '_', $phase, $rel; push @{$res{$module} ||= []}, { requires => $module, version => $prereqs_r->{$module}, type => $type, ($map{$type} ? ($map{$type} => 1) : ()), }; } } } %res; } sub _from_dist_ini { my ($class, $me) = @_; my $inifile = catfile($me->distdir, "dist.ini"); return unless -f $inifile; eval { require Config::INI::Reader } or return; my $config = Config::INI::Reader->read_file($inifile); return unless $config && ref $config eq ref {}; my %map = ( runtime_requires => 'is_prereq', build_requires => 'is_build_prereq', test_requires => 'is_build_prereq', runtime_recommends => 'is_optional_prereq', build_recommends => 'is_optional_prereq', test_recommends => 'is_optional_prereq', runtime_suggests => 'is_optional_prereq', build_suggests => 'is_optional_prereq', test_suggests => 'is_optional_prereq', ); my %res; for my $key (keys %$config) { next unless $key =~ /^Prereqs\b/; my ($phase, $rel) = qw(runtime requires); (undef, my $type) = split /\s*\/\s*/, $key, 2; if ($type) { if ($type =~ s/^(Configure|Build|Test|Runtime)//) { $phase = lc $1; } if ($type =~ s/^(Requires|Recommends|Suggests)//) { $rel = lc $1; } } my $conf = $config->{$key}; next unless $conf && ref $conf eq ref {}; if ($conf->{-phase}) { $phase = delete $conf->{-phase}; } if ($conf->{-relationship}) { $rel = delete $conf->{-relationship}; } for my $module (keys %$conf) { $type = join '_', $phase, $rel; push @{$res{$module} ||= []}, { requires => $module, version => $conf->{$module}, type => $type, ($map{$type} ? ($map{$type} => 1) : ()), }; } } $me->d->{prereq} = [sort {$a->{requires} cmp $b->{requires}} map {@$_} values %res]; $me->d->{got_prereq_from} = 'dist.ini'; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators{ # NOTE: The metrics in this module have moved to # Module::CPANTS::SiteKwalitee because these require databases. return []; } q{Favourite record of the moment: Fat Freddys Drop: Based on a true story}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Prereq - Checks listed prerequisites =head1 SYNOPSIS The metrics in this module have moved to L. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>. =head3 analyse Find information on prerequisite distributions from meta files etc. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/FindModules.pm0000644000175000017500000002037513522715156024717 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::FindModules; use warnings; use strict; use File::Spec::Functions qw(catfile); our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 30 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; my $files = $me->d->{files_array} || []; if ($me->d->{meta_yml} && $me->d->{meta_yml}{provides}) { my $provides = $me->d->{meta_yml}{provides}; for my $module (sort keys %$provides) { my $data = $provides->{$module}; next unless ref $data eq ref {}; # ignore wrong format my $file = $data->{file} || ''; my $found = { module => $module, file => $file, in_basedir => 0, in_lib => 0, }; my $loc; if ($file =~ /^lib\W/) { $found->{in_lib} = 1; } elsif ($file !~ /\//) { $found->{in_basedir} = 1; } push @{$me->d->{modules}}, $found; if (exists $me->d->{files_hash}{$file}) { (my $path_part = $module) =~ s|::|/|g; if ($file =~ /\b$path_part\.pm$/) { $me->d->{files_hash}{$file}{module} = $module; } elsif ("$path_part.pm" =~ /\b$file$/) { $me->d->{files_hash}{$file}{module} ||= $module; } } else { $found->{not_exists} = 1; } } } else { my %in_basedir = map {$_ => 1} grep {/^[^\/]+\.pm$/} @$files; foreach my $file (@$files) { next unless $file =~ /\.pm$/; next if $file =~ m{^x?t/}; next if $file =~ m{^test/}; next if $file =~ m/^(bin|scripts?|ex|eg|examples?|samples?|demos?)\/\w/i; next if $file =~ m{^inc/}; # skip Module::Install stuff next if $file =~ m{^(local|perl5|fatlib)/}; # proper file in lib/ if ($file =~ m|^lib/(.*)\.pm$|) { my $module = $1; $module =~ s|/|::|g; push (@{$me->d->{modules}}, { module => $module, file => $file, in_basedir => 0, in_lib => 1, }); $me->d->{files_hash}{$file}{module} = $module; } else { # open file and find first package my ($basename) = $file =~ /(\w+)\.pm/; my $module; my $max_lines_to_look_at = 666; open (my $fh, "<", catfile($me->distdir, $file)) or die "__PACKAGE__: Cannot open $file to find package declaration: $!"; while (my $line = <$fh>) { next if $line =~ /^\s*#/; # ignore comments if ($line =~ /^\s*package\s*(.*?)\s*;/) { $module = $1; last if $basename and $module =~ /\b$basename$/; } last if $line =~ /^__(DATA|END)__/; $max_lines_to_look_at--; last unless $max_lines_to_look_at; } # try to guess from filename unless ($module) { $file =~ m|(.*)\.pm$|; $module = $1; $module =~ s|^[a-z]+/||; # remove lowercase prefixes which most likely are not part of the distname (but something like 'src/') $module =~ s|/|::|g; } if ($module) { push(@{$me->d->{modules}}, { module => $module, file => $file, in_basedir => $in_basedir{$file} ? 1 : 0, in_lib => 0, }); $me->d->{files_hash}{$file}{module} = $module; } } } } for my $file (keys %{$me->d->{files_hash}}) { next unless $file =~ /^inc\/(.+)\.pm/; my $module = $1; $module =~ s|/|::|g; push @{$me->d->{included_modules} ||= []}, $module; } if (exists $me->d->{modules}) { $me->d->{modules} = [sort {$a->{module} cmp $b->{module}} @{$me->d->{modules}}]; } if (exists $me->d->{included_modules}) { $me->d->{included_modules} = [sort @{$me->d->{included_modules}}]; } return 1; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { return [ { name => 'proper_libs', error => q{There is more than one .pm file in the base dir, or the .pm files are not in lib/ directory.}, remedy => q{Move your *.pm files in a directory named 'lib'. The directory structure should look like 'lib/Your/Module.pm' for a module named 'Your::Module'. If you need to provide additional files, e.g. for testing, that should not be considered for Kwalitee, then you should look at the 'provides' map in META.yml to limit the files scanned; or use the 'no_index' map to exclude parts of the distribution.}, is_extra => 1, code => sub { my $d = shift; my @modules = @{$d->{modules} || []}; return 1 unless @modules; my @not_in_lib = grep { !$_->{in_lib} } @modules; return 1 unless @not_in_lib; my @in_basedir = grep { $_->{in_basedir} } @not_in_lib; return 1 if @in_basedir == 1; $d->{error}{proper_libs} = join ', ', map {$_->{file}} @not_in_lib; return 0; }, details => sub { my $d = shift; my @modules = @{$d->{modules} || []}; return "No modules were found" unless @modules; return "The following files were found: ".$d->{error}{proper_libs}; }, }, { name => 'no_missing_files_in_provides', error => q{Provides field in the META.yml lists a file that does not found in the distribution.}, remedy => q{Use authoring tool like Dist::Zilla, Milla, and Minilla to generate correct provides.}, is_extra => 1, code => sub { my $d = shift; my @modules = @{$d->{modules} || []}; return 1 unless @modules; if (my @not_exists = grep { $_->{not_exists} } @modules) { $d->{error}{no_missing_files_in_provides} = join ', ', map {$_->{file}} @not_exists; return 0; } return 1; }, details => sub { my $d = shift; my @modules = @{$d->{modules} || []}; return "No modules were found" unless @modules; return "The following files were missing: ".$d->{error}{no_missing_files_in_provides}; }, }, ]; } q{Favourite record of the moment: Fat Freddys Drop: Based on a true story}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::FindModules - Find modules provided by a dist =head1 SYNOPSIS Finds and reports all modules (i.e. F<*.pm> files) in a distribution. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<30>, as data generated by C is used by other tests. =head3 analyse C first looks in C and F for C<*.pm> files. If it doesn't find any, it looks in the whole dist, but the C kwalitee point is only awarded if the modules are F or there's only one module in C. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =item * proper_libs =back =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Manifest.pm0000644000175000017500000001033013522715156024242 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Manifest; use warnings; use strict; use File::Spec::Functions qw(catfile); use Array::Diff; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 100 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; my $distdir = $me->distdir; my $manifest_file = catfile($distdir, 'MANIFEST'); if (-e $manifest_file) { # read manifest open(my $fh, '<', $manifest_file) or die "cannot read MANIFEST $manifest_file: $!"; my %seen; while (<$fh>) { chomp; next if /^\s*#/; # discard pure comments if (s/^'(\\[\\']|.+)+'\s*.*/$1/) { s/\\([\\'])/$1/g; } else { s/\s.*$//; } # strip quotes and comments next unless $_; # discard blank lines $seen{$_}++; } close $fh; my @manifest = sort keys %seen; my @files = sort keys %{$me->d->{files_hash} || {}}; my @dupes = grep {$seen{$_} > 1} @manifest; my $diff = Array::Diff->diff(\@manifest, \@files); if ($diff->count == 0 && !@dupes) { $me->d->{manifest_matches_dist} = 1; } else { $me->d->{manifest_matches_dist} = 0; my @error = ( 'MANIFEST ('.(@manifest + @dupes).') does not match dist ('.@files."):", ); if (my @added = @{$diff->added}) { push @error, "Missing in MANIFEST: ".join(', ', @added); } if (my @deleted = @{$diff->deleted}) { push @error, "Missing in Dist: " . join(', ', @deleted); } if (@dupes) { push @error, "Duplicates in MANIFEST: " . join(', ', @dupes); } $me->d->{error}{manifest_matches_dist} = \@error; } # Tweak symlinks error for a local distribution (RT #97858) if ($me->d->{is_local_distribution} && $me->d->{error}{symlinks}) { my %manifested = map {$_ => 1} @manifest; my @symlinks = grep {$manifested{$_}} split ',', $me->d->{error}{symlinks}; if (@symlinks) { $me->d->{error}{symlinks} = join ',', @symlinks; } else { delete $me->d->{error}{symlinks}; } } } else { $me->d->{manifest_matches_dist} = 0; $me->d->{error}{manifest_matches_dist} = q{Cannot find MANIFEST in dist.}; } } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { return [ { name => 'manifest_matches_dist', error => q{MANIFEST does not match the contents of this distribution.}, remedy => q{Run a proper command ("make manifest" or "./Build manifest", maybe with a force option), or use a distribution builder to generate the MANIFEST. Or update MANIFEST manually.}, code => sub { shift->{manifest_matches_dist} ? 1 : 0 }, details => sub { my $d = shift; my $error = $d->{error}{manifest_matches_dist}; return $error unless ref $error; return join "\n", @$error; }, } ]; } q{Listening to: YAPC::Europe 2007}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Manifest - Check MANIFEST =head1 SYNOPSIS Check if MANIFEST and dist contents match. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>. =head3 analyse Check if MANIFEST and dist contents match. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =item * manifest_matches_dist =back =head1 SEE ALSO L =head1 AUTHOR Thomas Klausner, , https://domm.plix.at/ =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/License.pm0000644000175000017500000002246313522715156024070 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::License; use warnings; use strict; use File::Spec::Functions qw(catfile); use Software::LicenseUtils; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 100 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; my $distdir = $me->distdir; # check META.yml my $yaml = $me->d->{meta_yml}; $me->d->{license} = ''; if ($yaml) { if ($yaml->{license} and $yaml->{license} ne 'unknown') { my $license = $yaml->{license}; $license = join ',', @$license if ref $license eq 'ARRAY'; $me->d->{license_from_yaml} = $license; $me->d->{license} = $license.' defined in META.yml'; } } # use "files_array" to exclude files listed in "no_index". my $files = $me->d->{files_array} || []; # check if there's a LICEN[CS]E file # (also accept LICENSE.txt etc; RT #114247) if (my ($file) = grep {$_ =~ /^(?:LICEN[CS]E|COPYING)\b/} @$files) { $me->d->{license} .= " defined in $file"; $me->d->{external_license_file} = $file; } # check pod my %licenses; foreach my $file (grep { /\.(?:pm|pod|pl|PL)$/ } sort @$files ) { next if $file =~ /(?:Makefile|Build)\.PL$/; my $path = catfile($distdir, $file); next unless -r $path; # skip if not readable open my $fh, '<', $path or next; my $in_pod = 0; my $pod = ''; my $pod_head = ''; my @possible_licenses; my @unknown_license_texts; my $uc_head; while(<$fh>) { my $first_four = substr($_, 0, 4); if ($first_four eq '=hea' && (($uc_head = uc $_) =~ /(?:LICEN[CS]E|LICEN[CS]ING|COPYRIGHT|LEGAL)/)) { $me->d->{license_in_pod} = 1; $me->d->{license} ||= "defined in POD ($file)"; if ($in_pod) { my @guessed = Software::LicenseUtils->guess_license_from_pod("=head1 LICENSE\n$pod\n\n=cut\n"); if (@guessed) { push @possible_licenses, @guessed; } else { push @unknown_license_texts, "$pod_head$pod"; } } $in_pod = 1; $pod_head = $_; $pod = ''; } elsif ($first_four eq '=hea' or $first_four eq '=cut') { if ($in_pod) { my @guessed = Software::LicenseUtils->guess_license_from_pod("=head1 LICENSE\n$pod\n\n=cut\n"); if (@guessed) { push @possible_licenses, @guessed; } else { push @unknown_license_texts, "$pod_head$pod"; } } $in_pod = 0; $pod = ''; } elsif ($in_pod) { $pod .= $_; } } if ($pod) { my @guessed = Software::LicenseUtils->guess_license_from_pod("=head1 LICENSE\n$pod\n\n=cut\n"); if (@guessed) { push @possible_licenses, @guessed; } else { push @unknown_license_texts, "$pod_head$pod"; } } if (@possible_licenses) { @possible_licenses = map { s/^Software::License:://; $_ } @possible_licenses; push @{$licenses{$_} ||= []}, $file for @possible_licenses; $me->d->{files_hash}{$file}{license} = join ',', @possible_licenses; } else { $me->d->{unknown_license_texts}{$file} = join "\n", @unknown_license_texts if @unknown_license_texts; } } if (%licenses) { $me->d->{licenses} = \%licenses; my @possible_licenses = keys %licenses; if (@possible_licenses == 1) { my ($type) = @possible_licenses; $me->d->{license_type} = $type; $me->d->{license_file} = join ',', @{$licenses{$type}}; } } return; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators{ return [ { name => 'meta_yml_has_license', error => q{This distribution does not have a license defined in META.yml.}, remedy => q{Define the license if you are using in Build.PL. If you are using MakeMaker (Makefile.PL) you should upgrade to ExtUtils::MakeMaker version 6.31.}, is_extra => 1, code => sub { my $d = shift; my $yaml = $d->{meta_yml}; ($yaml->{license} and $yaml->{license} ne 'unknown') ? 1 : 0 }, details => sub { my $d = shift; my $yaml = $d->{meta_yml}; return "No META.yml." unless $yaml; return "No license was found in META.yml." unless $yaml->{license}; return "Unknown license was found in META.yml."; }, }, { name => 'has_human_readable_license', error => q{This distribution does not have a license defined in the documentation or in a file called LICENSE}, remedy => q{Add a section called "LICENSE" to the documentation, or add a file named LICENSE to the distribution.}, code => sub { my $d = shift; return $d->{external_license_file} || $d->{license_in_pod} ? 1 : 0; }, details => sub { my $d = shift; return "Neither LICENSE file nor LICENSE section in pod was found."; }, }, { name => 'has_separate_license_file', error => q{This distribution does not have a LICENSE or LICENCE file in its root directory.}, remedy => q{This is not a critical issue. Currently mainly informative for the CPANTS authors. It might be removed later.}, is_experimental => 1, code => sub { shift->{external_license_file} ? 1 : 0 }, details => sub { my $d = shift; return "LICENSE file was found."; }, }, { name => 'has_license_in_source_file', error => q{Does not have license information in any of its source files}, remedy => q{Add =head1 LICENSE and the text of the license to the main module in your code.}, code => sub { my $d = shift; return $d->{license_in_pod} ? 1 : 0; }, details => sub { my $d = shift; return "LICENSE section was not found in the pod."; }, }, { name => 'has_known_license_in_source_file', error => q{Does not have license information in any of its source files, or the information is not recognized by Software::License}, remedy => q{Add =head1 LICENSE and/or the proper text of the well-known license to the main module in your code.}, is_extra => 1, code => sub { my $d = shift; return 0 unless $d->{license_in_pod}; my @files_with_licenses = grep {$d->{files_hash}{$_}{license}} keys %{$d->{files_hash}}; return @files_with_licenses ? 1 : 0; }, details => sub { my $d = shift; return "LICENSE section was not found in the pod, or the license information was not recognized by Software::License."; }, }, ]; } q{Favourite record of the moment: Lili Allen - Allright, still}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::License - Checks if there is a license =head1 SYNOPSIS Checks if the distribution specifies a license. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>. =head3 analyse C checks if there's a C field C. Additionally, it looks for a file called LICENSE and a POD section named LICENSE =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =item * meta_yml_has_license =item * has_known_license_in_source_file =item * has_license_in_source_file =item * has_human_readable_license =item * has_separate_license_file =back =head2 License information Places where the license information is taken from: Has a LICENSE file file_license 1|0 Content of LICENSE file matches License X from Software::License License in META.yml License in META.yml matches one of the known licenses License in source files recognized by Software::LicenseUtils For each file keep where is was it recognized. Has license or copyright entry in pod (that might not be recognized by Software::LicenseUtils) # has_license =head1 SEE ALSO L =head1 AUTHOR L and L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2009 L Copyright © 2006–2008 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Distros.pm0000644000175000017500000000414313522715156024130 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Distros; use warnings; use strict; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 800 } ################################################################## # Analyse ################################################################## my $debian; sub analyse { my $class = shift; my $me = shift; # NOTE: The data source of these debian metrics has not been # updated for more than a year, and mirroring stuff from # external source every time you test is very nasty. # These metrics are deprecated and actually removed to # reduce unwanted dependencies for Test::Kwalitee users. # Note also that this stub should not be removed so that # this can replace the old ::Distro module, and the old # metrics will not be loaded while loading plugins. return; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators{ return []; } q{Favourite record of the moment: Lili Allen - Allright, still}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Distros - Information retrieved from the various Linux and other distributions =head1 SYNOPSIS The metrics here were based on data provided by the various downstream packaging systems, but are deprecated now. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. =head3 analyse Does nothing now. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =head1 SEE ALSO L =head1 AUTHOR L and L with the help of Martín Ferrari and the Debian Perl packaging team =head1 COPYRIGHT AND LICENSE Copyright © 2003–2009 L Copyright © 2006–2008 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Files.pm0000644000175000017500000004014013522715156023540 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Files; use warnings; use strict; use File::Find::Object; use File::Spec::Functions qw(catfile); use File::stat; use ExtUtils::Manifest qw(maniskip); $ExtUtils::Manifest::Quiet = 1; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic our $RespectManiskip = 1; # for Test::Kwalitee and its friends sub order { 15 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; my $distdir = $me->distdir; $distdir =~ s|\\|/|g if $^O eq 'MSWin32'; # Respect no_index if possible my $no_index_re = $class->_make_no_index_regex($me); my $maniskip = $class->_make_maniskip($me, $distdir); my (%files, %dirs); my (@files_array, @dirs_array, @files_to_be_skipped); my $size = 0; my $latest_mtime = 0; my @base_dirs; my $finder = File::Find::Object->new({ depth => 1, followlink => 0, }, $distdir); my %seen; # GH-83 while(defined(my $name = $finder->next)) { $name =~ s|\\|/|g if $^O eq 'MSWin32'; (my $path = $name) =~ s!^\Q$distdir\E(?:/|$)!! or next; next if $path eq ''; next if $seen{$path}++; if ($me->d->{is_local_distribution}) { next if $path =~ m!/\.!; } if ($maniskip && $maniskip->($path)) { next if $RespectManiskip; push @files_to_be_skipped, $path; if (-d $name) { $dirs{$path}{maniskip} = 1 } else { $files{$path}{maniskip} = 1 } } if (-d $name) { $dirs{$path} ||= {}; if (-l $name) { $dirs{$path}{symlink} = 1; } push @dirs_array, $path; next; } if (my $stat = stat($name)) { $files{$path}{size} = $stat->size || 0; $size += $files{$path}{size}; my $mtime = $files{$path}{mtime} = $stat->mtime; $latest_mtime = $mtime if $mtime > $latest_mtime; } else { $files{$path}{stat_error} = $!; next; } if (-l $name) { $files{$path}{symlink} = 1; } if ($no_index_re && $path =~ qr/$no_index_re/) { $files{$path}{no_index} = 1; next; } if (!-r $name) { $files{$path}{unreadable} = 1; next; } # ignore files in dot directories (probably VCS stuff) next if $path =~ m!(?:^|/)\.[^/]+/!; push @files_array, $path; # distribution may have several Makefile.PLs, thus # several 'lib' or 't' directories to care if ($path =~ m!/Makefile\.PL$! && $path !~ m!(^|/)x?t/!) { (my $dir = $path) =~ s|/[^/]+$||; push @base_dirs, $dir; } } $me->d->{size_unpacked} = $size; $me->d->{latest_mtime} = $latest_mtime; my @symlinks = sort {$a cmp $b} ( grep({ $files{$_}{symlink} } keys %files), grep({ $dirs{$_}{symlink} } keys %dirs) ); if (@symlinks) { $me->d->{error}{symlinks} = join ',', @symlinks; } if (@files_to_be_skipped) { $me->d->{error}{no_files_to_be_skipped} = join ',', @files_to_be_skipped; } $me->d->{base_dirs} = [sort @base_dirs] if @base_dirs; my $base_dirs_re = join '|', '', map {quotemeta "$_/"} @base_dirs; # find special files/dirs my @special_files = sort (qw(Makefile.PL Build.PL META.yml META.json MYMETA.yml MYMETA.json dist.ini cpanfile SIGNATURE MANIFEST MANIFEST.SKIP test.pl LICENSE LICENCE)); my @special_dirs = sort (qw(lib t xt)); my %special_files_re = ( file_changelog => qr{^(?:$base_dirs_re)(?:chang|history)}i, file_readme => qr{^(?:$base_dirs_re)readme(?:\.(?:txt|md|pod|mkdn|mdown|markdown))?}i, ); for my $base_dir ('', @base_dirs) { $base_dir = "$base_dir/" if $base_dir; for my $name (@special_files) { my $file = "$base_dir$name"; if (exists $files{$file}) { (my $key = "file_".lc $name) =~ s/\./_/; $me->d->{$key} = $me->d->{$key} ? $me->d->{$key}.",$file" : $file; } } for my $name (@special_dirs) { my $dir = "$base_dir$name"; if (exists $dirs{$dir}) { my $key = "dir_$name"; $me->d->{$key} = $me->d->{$key} ? $me->d->{$key}.",$dir" : $dir; } } } for my $file (sort keys %files) { next unless $file =~ m!^(?:$base_dirs_re)[^/]+$!; while(my ($key, $re) = each %special_files_re) { if ($file =~ /$re/) { $me->d->{$key} = $me->d->{$key} ? $me->d->{$key}.",$file" : $file; } } } # store stuff $me->d->{files} = scalar @files_array; $me->d->{files_array} = \@files_array; $me->d->{files_hash} = \%files; $me->d->{dirs} = scalar @dirs_array; $me->d->{dirs_array} = \@dirs_array; my @ignored = grep {$files{$_}{no_index}} sort keys %files; $me->d->{ignored_files_array} = \@ignored if @ignored; # check STDIN in Makefile.PL and Build.PL # objective: convince people to use prompt(); for my $type (qw/makefile_pl build_pl/) { for my $path (split ',', $me->d->{"file_$type"} || '') { next unless $path; my $file = catfile($me->distdir, $path); next if not -e $file; open my $fh, '<', $file or next; my $content = do { local $/; <$fh> } or next; $me->d->{"stdin_in_$type"} = 1 if $content =~ //; } } return; } sub _make_no_index_regex { my ($class, $me) = @_; my $meta = $me->d->{meta_yml}; return unless $meta && ref $meta eq ref {}; my $no_index = $meta->{no_index} || $meta->{private}; return unless $no_index && ref $no_index eq ref {}; my %map = ( file => '\z', directory => '/', ); my @ignore; for my $type (qw/file directory/) { next unless $no_index->{$type}; my $rest = $map{$type}; my @entries = ref $no_index->{$type} eq ref [] ? @{ $no_index->{$type} } : ( $no_index->{$type} ); # entries may possibly have escape chars; DAGOLDEN/Class-InsideOut-0.90_01.tar.gz push @ignore, map {s/\\/\\\\/g; "^$_$rest"} @entries; } return unless @ignore; $me->d->{no_index} = join ';', sort @ignore; return '(?:' . (join '|', @ignore) . ')'; } sub _make_maniskip { my ($class, $me, $distdir) = @_; my $maniskip_file = "$distdir/MANIFEST.SKIP"; return unless -f $maniskip_file && -r _; # ignore MANIFEST.SKIP if it has an invalid entry my $maniskip_bak_file = "$maniskip_file.bak"; my $has_maniskip_bak = -f $maniskip_bak_file; my $maniskip = maniskip($maniskip_file); my $maniskip_warning; local $SIG{__WARN__} = sub { $maniskip_warning = shift; }; eval { $maniskip->(""); }; if ($@ or $maniskip_warning) { $me->d->{error}{no_maniskip_error} = $@ || $maniskip_warning; $maniskip = undef; } if (-f $maniskip_bak_file && !$has_maniskip_bak) { my $mtime = stat($maniskip_bak_file)->mtime; utime $mtime, $mtime, $maniskip_file; unlink $maniskip_bak_file; # probably generated by #include_default } $maniskip; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { return [ { name => 'has_readme', error => q{The file "README" is missing from this distribution. The README provides some basic information to users prior to downloading and unpacking the distribution.}, remedy => q{Add a README to the distribution. It should contain a quick description of your module and how to install it.}, code => sub { shift->{file_readme} ? 1 : 0 }, details => sub { my $d = shift; return "README was not found."; }, }, { name => 'has_manifest', error => q{The file "MANIFEST" is missing from this distribution. The MANIFEST lists all files included in the distribution.}, remedy => q{Add a MANIFEST to the distribution. Your buildtool should be able to autogenerate it (eg "make manifest" or "./Build manifest")}, code => sub { shift->{file_manifest} ? 1 : 0 }, details => sub { my $d = shift; return "MANIFEST was not found."; }, }, { name => 'has_meta_yml', error => q{The file "META.yml" is missing from this distribution. META.yml is needed by people maintaining module collections (like CPAN), for people writing installation tools, or just people who want to know some stuff about a distribution before downloading it.}, remedy => q{Add a META.yml to the distribution. Your buildtool should be able to autogenerate it.}, code => sub { my $d = shift; return 1 if $d->{file_meta_yml}; return 1 if $d->{is_local_distribution} && $d->{file_mymeta_yml}; return 0; }, details => sub { my $d = shift; return "META.yml was not found."; }, }, { name => 'has_meta_json', error => q{The file "META.json" is missing from this distribution. META.json has better information than META.yml and is preferred by people maintaining module collections (like CPAN), for people writing installation tools, or just people who want to know some stuff about a distribution before downloading it.}, remedy => q{Add a META.json to the distribution. Your buildtool should be able to autogenerate it.}, code => sub { my $d = shift; return 1 if $d->{file_meta_json}; return 1 if $d->{is_local_distribution} && $d->{file_mymeta_json}; return 0; }, details => sub { my $d = shift; return "META.json was not found."; }, is_extra => 1, }, { name => 'has_buildtool', error => q{Makefile.PL and/or Build.PL are missing. This makes installing this distribution hard for humans and impossible for automated tools like CPAN/CPANPLUS/cpanminus.}, remedy => q{Add a Makefile.PL (for ExtUtils::MakeMaker/Module::Install) or a Build.PL (for Module::Build and its friends), or use a distribution builder such as Dist::Zilla, Dist::Milla, Minilla.}, code => sub { my $d = shift; return 1 if $d->{file_makefile_pl} || $d->{file_build_pl}; return 0; }, details => sub { my $d = shift; return "Neither Makefile.PL nor Build.PL was found."; }, }, { name => 'has_changelog', error => q{The distribution hasn't got a Changelog (named something like m/^chang(es?|log)|history$/i). A Changelog helps people decide if they want to upgrade to a new version.}, remedy => q{Add a Changelog (best named 'Changes') to the distribution. It should list at least major changes implemented in newer versions.}, code => sub { shift->{file_changelog} ? 1 : 0 }, details => sub { my $d = shift; return "Any Changelog file was not found."; }, }, { name => 'no_files_to_be_skipped', error => q{This distribution contains files that should be skipped by MANIFEST.SKIP.}, remedy => q{Fix MANIFEST.SKIP or use an authoring tool which respects MANIFEST.SKIP. Note that each entry in MANIFEST.SKIP is a regular expression. You may need to add appropriate meta characters not to ignore necessary stuff.}, code => sub {shift->{error}{no_files_to_be_skipped} ? 0 : 1}, details => sub { my $d = shift; return "The following files were found: ".$d->{error}{no_files_to_be_skipped}; }, }, { name => 'no_symlinks', error => q{This distribution includes symbolic links (symlinks). This is bad, because there are operating systems that do not handle symlinks.}, remedy => q{Remove the symlinks from the distribution.}, code => sub {shift->{error}{symlinks} ? 0 : 1}, details => sub { my $d = shift; return "The following symlinks were found: ".$d->{error}{symlinks}; }, }, { name => 'has_tests', error => q{This distribution doesn't contain either a file called 'test.pl' or a directory called 't'. This indicates that it doesn't contain even the most basic test-suite. This is really BAD!}, remedy => q{Add tests!}, code => sub { my $d = shift; # TODO: make sure if .t files do exist in t/ directory. return 1 if $d->{file_test_pl} || $d->{dir_t}; return 0; }, details => sub { my $d = shift; return q{Neither "test.pl" nor "t/" directory was not found.}; }, }, { name => 'has_tests_in_t_dir', is_extra => 1, error => q{This distribution contains either a file called 'test.pl' (the old test file) or is missing a directory called 't'. This indicates that it uses the old test mechanism or it has no test-suite.}, remedy => q{Add tests or move tests.pl to the t/ directory!}, code => sub { my $d = shift; # TODO: make sure if .t files do exist in t/ directory. return 1 if !$d->{file_test_pl} && $d->{dir_t}; return 0; }, details => sub { my $d = shift; return q{"test.pl" was found.} if $d->{file_test_pl}; return q{"t/" directory was not found.}; }, }, { name => 'no_stdin_for_prompting', error => q{This distribution is using direct call from STDIN instead of prompt(). Make sure STDIN is not used in Makefile.PL or Build.PL.}, is_extra => 1, remedy => q{Use the prompt() method from ExtUtils::MakeMaker/Module::Build.}, code => sub { my $d = shift; if ($d->{stdin_in_makefile_pl}||$d->{stdin_in_build_pl}) { return 0; } return 1; }, details => sub { my $d = shift; return " was found in Makefile.PL" if $d->{stdin_in_makefile_pl}; return " was found in Build.PL" if $d->{stdin_in_build_pl}; }, }, { name => 'no_maniskip_error', error => q{This distribution's MANIFEST.SKIP has a problematic entry.}, is_extra => 1, remedy => q{Fix the problematic entry.}, code => sub { my $d = shift; if ($d->{error}{no_maniskip_error}) { return 0; } return 1; }, details => sub { my $d = shift; return $d->{error}{no_maniskip_error}; }, }, ]; } q{Favourite record of the moment: Fat Freddys Drop: Based on a true story}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Files - Check for various files =head1 SYNOPSIS Find various files and directories that should be part of every self-respecting distribution. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<15>, as data generated by C is used by all other tests. =head3 analyse C uses C to get a list of all files and directories in a distribution. It checks if certain crucial files are there, and does some other file-specific stuff. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =over =item * has_readme =item * has_manifest =item * has_meta_yml =item * has_buildtool =item * has_changelog =item * no_symlinks =item * has_tests =item * has_tests_in_t_dir =item * no_stdin_for_prompting =back =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/CpantsErrors.pm0000644000175000017500000000450213522715156025125 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::CpantsErrors; use warnings; use strict; use version; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 1000 } ################################################################## # Analyse ################################################################## sub analyse { # NOTE: CPANTS error should be logged somewhere, but it # should not annoy people. If anything wrong or interesting # is found in the log, add some metrics (if it's worth), # or just fix our problems. # Note also that this stub should not be removed so that # this can replace the old ::CpantsErrors module, and the old # metrics will not be loaded while loading plugins. } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { # Older Test::Kwalitee (prior to 1.08) has hardcoded metrics # names in it, and if those metrics are gone from # Module::CPANTS::Kwalitee, it fails because the number of tests # is not as expected. This is not beautiful, but better than # to break others' distributions needlessly. if ($INC{"Test/Kwalitee.pm"}) { return [ map {+{name => $_, code => sub {1}}} qw/extractable no_pod_errors has_test_pod has_test_pod_coverage/ ] if version->parse(Test::Kwalitee->VERSION) < version->parse(1.08); } return []; } q{Listeing to: FM4 the early years}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::CpantsErrors - Check for CPANTS testing errors =head1 SYNOPSIS Checks if something strange happened during testing =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<1000>. =head3 analyse Uses C to check for any strange things that might happen during testing =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/Version.pm0000644000175000017500000000335313522715156024130 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::Version; use warnings; use strict; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 100 } ################################################################## # Analyse ################################################################## sub analyse { # NOTE: The analysis/metrics in this module have moved to # Module::CPANTS::SiteKwalitee because these require # a finalized META file to detect (or ignore) versions # correctly. # Note also that this stub should not be removed so that # this can replace the old ::Version module, and the old # metrics will not be loaded while loading plugins. } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators { return []; } q{Favourite record of the moment: Fat Freddys Drop: Based on a true story}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::Version - check versions =head1 SYNOPSIS The metrics in this module have moved to L. =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<100>. =head3 analyse Does nothing now. =head3 kwalitee_indicators Returns the Kwalitee Indicators data structure. =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2003–2006, 2009 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Kwalitee/NeedsCompiler.pm0000644000175000017500000000476413522715156025243 0ustar ishigakiishigakipackage Module::CPANTS::Kwalitee::NeedsCompiler; use warnings; use strict; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic sub order { 200 } ################################################################## # Analyse ################################################################## sub analyse { my $class = shift; my $me = shift; my $files = $me->d->{files_array}; foreach my $f (@$files) { if ($f =~ /\.[hc]$/i or $f =~ /\.xs$/i) { $me->d->{needs_compiler} = 1; return; } } if (defined ref($me->d->{prereq}) and ref($me->d->{prereq}) eq 'ARRAY') { for my $m (@{ $me->d->{prereq} }) { if ($m->{requires} =~ /^Inline::/ or $m->{requires} eq 'ExtUtils::CBuilder' or $m->{requires} eq 'ExtUtils::ParseXS') { $me->d->{needs_compiler} = 1; return; } } } return; } ################################################################## # Kwalitee Indicators ################################################################## sub kwalitee_indicators{ return [ ]; } q{Favourite compiler: gcc}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Kwalitee::NeedsCompiler - Checks if the module needs a (probably C) compiler =head1 SYNOPSIS Checks if there is some indication in the module that it needs a C compiler to build and install =head1 DESCRIPTION =head2 Methods =head3 order Defines the order in which Kwalitee tests should be run. Returns C<200>. =head3 analyse Checks for file with F<.c>, F<.h> or F<.xs> extensions. Check is the module depends on any of the Inline:: modules or on ExtUtils::CBuilder or ExtUtils::ParseXS. =head3 TODO: How to recognize cases such as https://metacpan.org/release/GAAS/Perl-API-0.01/ and https://metacpan.org/release/Term-Size-Perl that generate the .c files during installation In addition there are modules that can work without their XS part. E.g. Scalar-List-Utils, Net-DNS, Template-Toolkit For our purposes these all should be marked as "need C compiler" as they need it for their full functionality and speed. =head3 kwalitee_indicators No Kwalitee Indicator. =head1 SEE ALSO L =head1 AUTHOR L =head1 COPYRIGHT AND LICENSE Copyright © 2006–2008 L You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/lib/Module/CPANTS/Analyse.pm0000644000175000017500000001677613522715156022347 0ustar ishigakiishigakipackage Module::CPANTS::Analyse; use 5.008001; use strict; use warnings; use base qw(Class::Accessor::Fast); use File::Temp qw(tempdir); use File::Spec::Functions qw(catfile catdir splitpath); use File::Copy; use File::stat; use Archive::Any::Lite; use Carp; use CPAN::DistnameInfo; our $VERSION = '1.01'; $VERSION =~ s/_//; ## no critic __PACKAGE__->mk_accessors(qw(dist opts tarball distdir d mck)); __PACKAGE__->mk_accessors(qw(_testdir _dont_cleanup _tarball _x_opts)); sub import { my $class = shift; require Module::CPANTS::Kwalitee; Module::CPANTS::Kwalitee->import(@_); } sub new { my $class = shift; my $opts = shift || {}; $opts->{d} = {}; $opts->{opts} ||= {}; my $me = bless $opts, $class; Carp::croak("need a dist") if not defined $opts->{dist}; $me->mck(Module::CPANTS::Kwalitee->new); # For Test::Kwalitee and friends $me->d->{is_local_distribution} = 1 if -d $opts->{dist}; return $me; } sub run { my $me = shift; $me->unpack unless $me->d->{is_local_distribution}; $me->analyse; $me->calc_kwalitee; $me->d; } sub unpack { my $me = shift; return 'cant find dist' unless $me->dist; my $di = CPAN::DistnameInfo->new($me->dist); my $ext = $di->extension || 'unknown'; $me->d->{package} = $di->filename; $me->d->{vname} = $di->distvname; $me->d->{extension} = $ext; $me->d->{version} = $di->version; $me->d->{dist} = $di->dist; $me->d->{author} = $di->cpanid; $me->d->{released} = stat($me->dist)->mtime; $me->d->{size_packed} = -s $me->dist; unless($me->d->{package}) { $me->d->{package} = $me->tarball; } copy($me->dist, $me->testfile); my @pax_headers; eval { my $archive = Archive::Any::Lite->new($me->testfile); $archive->extract($me->testdir, {tar_filter_cb => sub { my $entry = shift; if ($entry->name eq Archive::Tar::Constant::PAX_HEADER() or $entry->type eq 'x' or $entry->type eq 'g') { push @pax_headers, $entry->name; return; } return 1; }}); }; if (@pax_headers) { $me->d->{no_pax_headers} = 0; $me->d->{error}{no_pax_headers} = join ',', @pax_headers; } else { $me->d->{no_pax_headers} = 1; } if (my $error = $@) { $me->d->{extractable} = 0; $me->d->{error}{extractable} = $error; $me->d->{kwalitee}{extractable} = 0; my ($vol, $dir, $name) = splitpath($me->dist); $name =~ s/\..*$//; $name =~ s/\-[\d\.]+$//; $name =~ s/\-TRIAL[0-9]*//; $me->d->{dist} = $name; return $error; } $me->d->{extractable} = 1; unlink($me->testfile); opendir(my $fh_testdir, $me->testdir) or die "Cannot open ".$me->testdir.": $!"; my @stuff = grep {/\w/} readdir($fh_testdir); if (@stuff == 1) { $me->distdir(catdir($me->testdir, $stuff[0])); if (-d $me->distdir) { my $vname = $di->distvname; $vname =~ s/\-TRIAL[0-9]*//; $me->d->{extracts_nicely} = 1; if ($vname ne $stuff[0]) { $me->d->{error}{extracts_nicely} = "expected $vname but got $stuff[0]"; } } else { $me->distdir($me->testdir); $me->d->{extracts_nicely} = 0; $me->d->{error}{extracts_nicely} = join ",", @stuff; } } else { $me->distdir($me->testdir); $me->d->{extracts_nicely} = 0; $me->d->{error}{extracts_nicely} = join ",", @stuff; } return; } sub analyse { my $me = shift; foreach my $mod (@{$me->mck->generators}) { $mod->analyse($me); } } sub calc_kwalitee { my $me = shift; my $kwalitee = 0; $me->d->{kwalitee} = {}; my %x_ignore = %{$me->x_opts->{ignore} || {}}; foreach my $i ($me->mck->get_indicators) { next if $i->{needs_db}; my $rv = $i->{code}($me->d, $i); $me->d->{kwalitee}{$i->{name}} = $rv; if ($x_ignore{$i->{name}} && $i->{ignorable}) { $me->d->{kwalitee}{$i->{name}} = 1; if ($me->d->{error}{$i->{name}}) { $me->d->{error}{$i->{name}} .= ' [ignored]'; } } $kwalitee += $rv; } $me->d->{'kwalitee'}{'kwalitee'} = $kwalitee; } #---------------------------------------------------------------- # helper methods #---------------------------------------------------------------- sub testdir { my $me = shift; return $me->_testdir if $me->_testdir; if ($me->_dont_cleanup) { return $me->_testdir(tempdir()); } else { return $me->_testdir(tempdir(CLEANUP => 1)); } } sub testfile { my $me = shift; return catfile($me->testdir, $me->tarball); } sub tarball { my $me = shift; return $me->_tarball if $me->_tarball; my (undef, undef, $tb) = splitpath($me->dist); return $me->_tarball($tb); } sub x_opts { my $me = shift; return $me->_x_opts if $me->_x_opts; my %opts; if (my $x_cpants = $me->d->{meta_yml}{x_cpants}) { if (my $ignore = $x_cpants->{ignore}) { if (ref $ignore eq ref {}) { $opts{ignore} = $ignore; } else { $me->d->{error}{x_cpants} = "x_cpants ignore should be a hash reference (key: metric, value: reason to ignore)"; } } } $me->_x_opts(\%opts); } q{Favourite record of the moment: Jahcoozi: Pure Breed Mongrel}; __END__ =encoding UTF-8 =head1 NAME Module::CPANTS::Analyse - Generate Kwalitee ratings for a distribution =head1 SYNOPSIS use Module::CPANTS::Analyse; my $analyser = Module::CPANTS::Analyse->new({ dist => 'path/to/Foo-Bar-1.42.tgz', }); $analyser->run; # results are in $analyser->d; =head1 DESCRIPTION =head2 Methods =head3 new my $analyser = Module::CPANTS::Analyse->new({dist => 'path/to/file'}); Plain old constructor. =head3 unpack Unpack the distribution into a temporary directory. Returns an error if something went wrong, C if all went well. =head3 analyse Run all analysers (defined in C on the dist. =head3 calc_kwalitee Check if the dist conforms to the Kwalitee indicators. =head3 run Unpacks, analyses, and calculates kwalitee, and returns a resulting stash. =head2 Helper Methods =head3 testdir Returns the path to the unique temp directory. =head3 testfile Returns the location of the unextracted tarball. =head3 tarball Returns the filename of the tarball. =head3 x_opts Returns a hash reference that holds normalized information set in the "x_cpants" custom META field. =head1 WEBSITE L =head1 BUGS Please report any bugs or feature requests, or send any patches, to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 AUTHOR L Please use the C mailing list for discussing all things CPANTS: L Based on work by L and the original idea proposed by L. =head1 LICENSE This code is Copyright © 2003–2006 L. All rights reserved. You may use and distribute this module according to the same terms that Perl is distributed under. Module-CPANTS-Analyse-1.01/t/0000755000175000017500000000000013522716652015656 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/t/lib/0000755000175000017500000000000013522716652016424 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/t/lib/Module/0000755000175000017500000000000013522716652017651 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/t/lib/Module/CPANTS/0000755000175000017500000000000013522716652020641 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/t/lib/Module/CPANTS/TestAnalyse.pm0000644000175000017500000000572713425453447023450 0ustar ishigakiishigakipackage # Module::CPANTS::TestAnalyse; use strict; use warnings; use Carp; use base 'Exporter'; use File::Temp qw/tempdir/; use File::Path; use File::Spec::Functions qw/splitpath catfile abs2rel/; use File::Find; use Cwd; use Module::CPANTS::Analyse; use CPAN::Meta::YAML; use Test::More; our @EXPORT = qw/ test_distribution write_file write_pmfile write_metayml archive_and_analyse /; push @EXPORT, \$Test::More::TODO, grep {Test::More->can($_)} qw/ ok use_ok require_ok is isnt like unlike is_deeply cmp_ok skip todo_skip pass fail eq_array eq_hash eq_set plan done_testing can_ok isa_ok new_ok diag note explain BAIL_OUT subtest nest /; sub test_distribution (&) { my $code = shift; my $cwd = cwd; my $dir = tempdir(CLEANUP => 1); my $mca = Module::CPANTS::Analyse->new({ dist => $dir, distdir => $dir, }); note "tests under $dir"; eval { $code->($mca, $dir) }; ok !$@, "no errors"; diag $@ if $@; chdir $cwd; rmtree $dir; } sub write_file { my ($path, $content) = @_; my ($vol, $dir, $file) = splitpath($path); $dir = "$vol$dir" if $vol; mkpath $dir unless -d $dir; open my $fh, '>:encoding(utf8)', $path or croak "Can't open $path: $!"; print $fh $content; note "wrote to $path"; } sub write_pmfile { my ($path, $content) = @_; my @lines = ('package '.'Module::CPANTS::Analyse::Test'); push @lines, $content if defined $content; push @lines, '1'; write_file($path, join ";\n", @lines, ""); } sub write_metayml { my ($path, $args) = @_; my $meta = { name => 'Module::CPANTS::Analyse::Test', abstract => 'test', author => ['A.U.Thor'], generated_by => 'hand', license => 'perl', 'meta-spec' => {version => '1.4', url => 'http://module-build.sourceforge.net/META-spec-v1.4.html'}, version => '0.01', %{$args || {}}, }; write_file($path, CPAN::Meta::YAML->new($meta)->write_string); } sub archive_and_analyse { my ($dir, $name) = @_; my $archive_path = catfile($dir, $name); (my $basename = $name) =~ s/(?:\.tar\.(?:gz|bz)|\.zip)$//; require Archive::Tar; my $archive = Archive::Tar->new; find({ wanted => sub { my $file = $File::Find::name; my $relpath = abs2rel($file, $dir); return if $relpath =~ /^\./; my $path = catfile($basename, $relpath); if (-l $file) { $archive->add_data($path, '', { type => Archive::Tar::SYMLINK, linkname => readlink $file, }) or die "failed to add symlink: $path"; } elsif (-f $file) { my $content = do { local $/; open my $fh, '<', $file; <$fh> }; $archive->add_data($path, $content); } elsif (-d $dir && $path ne '.') { $archive->add_data($path, '', Archive::Tar::DIR) or die "failed to add dir: $path"; } }, no_chdir => 1, }, $dir); $archive->write($archive_path, Archive::Tar::COMPRESS_GZIP); ok -f $archive_path, "archive exists"; Module::CPANTS::Analyse->new({ dist => $archive_path, })->run; } 1; Module-CPANTS-Analyse-1.01/t/analyse/0000755000175000017500000000000013522716652017312 5ustar ishigakiishigakiModule-CPANTS-Analyse-1.01/t/analyse/manifest.t0000644000175000017500000000402312411273577021304 0ustar ishigakiishigakiuse strict; use warnings; use FindBin; use lib "$FindBin::Bin/../lib"; use Module::CPANTS::TestAnalyse; test_distribution { my ($mca, $dir) = @_; write_file("$dir/MANIFEST", <<"EOF"); lib/Module/CPANTS/Analyse/Test.pm MANIFEST EOF write_pmfile("$dir/lib/Module/CPANTS/Analyse/Test.pm"); my $stash = $mca->run; is $stash->{manifest_matches_dist} => 1, "manifest matches dist"; }; test_distribution { my ($mca, $dir) = @_; write_pmfile("$dir/lib/Module/CPANTS/Analyse/Test.pm"); my $stash = $mca->run; is $stash->{manifest_matches_dist} => 0, "manifest does not match dist"; like $stash->{error}{manifest_matches_dist} => qr/^Cannot find MANIFEST/, "proper error message"; }; test_distribution { my ($mca, $dir) = @_; write_file("$dir/MANIFEST", <<"EOF"); eg/demo.pl lib/Module/CPANTS/Analyse/Test.pm MANIFEST EOF write_pmfile("$dir/lib/Module/CPANTS/Analyse/Test.pm"); write_file("$dir/TODO", "TODO!"); my $stash = $mca->run; is $stash->{manifest_matches_dist} => 0, "manifest does not match dist"; my @errors = @{ $stash->{error}{manifest_matches_dist} || [] }; ok grep /^Missing in MANIFEST: TODO/, @errors; ok grep /^Missing in Dist: eg\/demo\.pl/, @errors; }; # should hide symlink errors not in MANIFEST for a local distribution test_distribution { my ($mca, $dir) = @_; write_file("$dir/MANIFEST", <<"EOF"); MANIFEST EOF eval { symlink "$dir/MANIFEST", "$dir/MANIFEST.lnk" }; if ($@) { diag "symlink is not supported"; return; } my $stash = $mca->run; ok !$stash->{error}{symlinks}, "symlinks not listed in MANIFEST is ignored for a local distribution"; }; test_distribution { my ($mca, $dir) = @_; write_file("$dir/MANIFEST", <<"EOF"); MANIFEST EOF eval { symlink "$dir/MANIFEST", "$dir/MANIFEST.lnk" }; if ($@) { diag "symlink is not supported"; return; } my $stash = archive_and_analyse($dir, "Module-CPANTS-Analyse-Test-0.01.tar.gz"); ok $stash->{error}{symlinks}, "symlinks not listed in MANIFEST is not ignored for a non-local distribution"; }; done_testing; Module-CPANTS-Analyse-1.01/t/analyse/uses.t0000644000175000017500000000075712411222347020454 0ustar ishigakiishigakiuse strict; use warnings; use FindBin; use lib "$FindBin::Bin/../lib"; use Module::CPANTS::TestAnalyse; for my $vstr (qw/v5.14 5.012/) { test_distribution { my ($mca, $dir) = @_; my $content = join "\n", 'package '.'Module::CPANTS::Analyse::Test;', "use $vstr;", '1;', ; write_pmfile("$dir/lib/Module/CPANTS/Analyse/Test.pm", $content); my $stash = $mca->run; is $stash->{kwalitee}{use_strict} => 1; note explain $stash; }; } done_testing; Module-CPANTS-Analyse-1.01/t/analyse/pod.t0000644000175000017500000000110612411273577020257 0ustar ishigakiishigakiuse strict; use warnings; use FindBin; use lib "$FindBin::Bin/../lib"; use Module::CPANTS::TestAnalyse; test_distribution { my ($mca, $dir) = @_; my $content = join "\n\n", ( '=pod', '=encoding utf-8;', '=head1 NAME', 'Module::CPANTS::Analyse::Test - test abstract', '=cut', ); write_pmfile("$dir/lib/Module/CPANTS/Analyse/Test.pm", $content); my $stash = $mca->run; like $stash->{error}{has_abstract_in_pod} => qr/^unknown encoding: utf-8;/; is $stash->{abstracts_in_pod}{'Module::CPANTS::Analyse::Test'} => 'test abstract'; }; done_testing; Module-CPANTS-Analyse-1.01/t/05_testfile.t0000644000175000017500000000061212411274466020163 0ustar ishigakiishigakiuse strict; use warnings; use Test::More; use Test::FailWarnings; use Module::CPANTS::Analyse; use File::Basename; my $a=Module::CPANTS::Analyse->new({ dist=>'D/DO/DOMM/Foo-Bar-1.05.tgz', }); my $td=$a->testdir; ok(-e $td,"testdir $td created"); $td=basename($td); like($a->testfile,qr/$td/,"testdir in testfile"); like($a->testfile,qr/Foo-Bar/,"filename in testfile"); done_testing; Module-CPANTS-Analyse-1.01/t/00_load.t0000644000175000017500000000020112411274466017250 0ustar ishigakiishigakiuse strict; use warnings; use Test::More; use Test::FailWarnings; BEGIN { use_ok( 'Module::CPANTS::Analyse' ); } done_testing; Module-CPANTS-Analyse-1.01/t/05_testdir.t0000644000175000017500000000043312411274466020023 0ustar ishigakiishigakiuse strict; use warnings; use Test::More; use Test::FailWarnings; use Module::CPANTS::Analyse; my $a=Module::CPANTS::Analyse->new({dist => 'dummy'}); my $td=$a->testdir; ok(-e $td,"testdir $td created"); my $td2=$a->testdir; is($td,$td2,"still the same testdir"); done_testing; Module-CPANTS-Analyse-1.01/t/older_test_kwalitee.t0000644000175000017500000000127112411273577022075 0ustar ishigakiishigakiuse strict; use warnings; use Test::More; use Module::CPANTS::Kwalitee; local $INC{"Test/Kwalitee.pm"} = 1; local $Test::Kwalitee::VERSION = 1.01; my @hardcoded_metrics = qw/ extractable has_readme has_manifest has_meta_yml has_buildtool has_changelog no_symlinks has_tests proper_libs no_pod_errors use_strict has_test_pod has_test_pod_coverage /; my %seen; my $kwalitee = Module::CPANTS::Kwalitee->new; for my $generator (@{ $kwalitee->generators }) { for (@{ $generator->kwalitee_indicators }) { $seen{$_->{name}}++ if ref $_->{code} eq ref sub {}; } } for (@hardcoded_metrics) { is $seen{$_} => 1, "$_ is available for Test::Kwalitee"; } done_testing; Module-CPANTS-Analyse-1.01/t/x_cpants.t0000644000175000017500000000303112411273577017657 0ustar ishigakiishigakiuse strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib"; use Module::CPANTS::TestAnalyse; test_distribution { my ($mca, $dir) = @_; write_metayml("$dir/META.yml"); write_pmfile("$dir/Test.pm"); my $res = $mca->run; ok !$res->{kwalitee}{use_strict}, "use_strict fails correctly"; ok !$res->{kwalitee}{has_tests}, "has_tests fails correctly"; }; test_distribution { my ($mca, $dir) = @_; write_pmfile("$dir/Test.pm"); write_metayml("$dir/META.yml", { x_cpants => {ignore => { use_strict => 'for some reason', }} }); my $res = $mca->run; ok $res->{kwalitee}{use_strict}, "use_strict is ignored (and treated as pass)"; ok $res->{error}{use_strict} && $res->{error}{use_strict} =~ /Module::CPANTS::Analyse::Test/ && $res->{error}{use_strict} =~ /ignored/, "error is not removed and marked as 'ignored'"; ok !$res->{kwalitee}{has_tests}, "has_tests fails correctly"; }; test_distribution { my ($mca, $dir) = @_; write_pmfile("$dir/Test.pm"); write_metayml("$dir/META.yml", { x_cpants => {ignore => { use_strict => 'for some reason', has_tests => 'because I am so lazy', }} }); my $res = $mca->run; ok $res->{kwalitee}{use_strict}, "use_strict is ignored (and treated as pass)"; ok $res->{error}{use_strict} && $res->{error}{use_strict} =~ /Module::CPANTS::Analyse::Test/ && $res->{error}{use_strict} =~ /ignored/, "error is not removed and marked as 'ignored'"; ok !$res->{kwalitee}{has_tests}, "has_tests fails correctly regardless of the x_cpants"; }; done_testing; Module-CPANTS-Analyse-1.01/TODO0000644000175000017500000001521012411273577016102 0ustar ishigakiishigaki#----------------------------------------------------------------- # TODO Module-CPANTS-Analyse # $Rev: 409 $ # $Date: 2006-09-14 19:42:31 +0200 (Thu, 14 Sep 2006) $ #----------------------------------------------------------------- #----------------------------------------------------------------- # BUGS #----------------------------------------------------------------- Robert 'phaylon' Sedlacek Meldung, dass 'has_proper_version' nicht bestanden wird. http://rt.cpan.org/Ticket/Display.html?id=21370 Win32 test fail: analyse.t, analyse_afs.t, calc.t, testfile.t Moose and MooseX turn on strict, so count Moose[X] as use_strict The "ownership of a modules does not seem to get updated" e.g. still shows DAGOLDEN even tough it should be ADAMK http://cpants.perl.org/dist/external/Perl-Dist-Strawberry #----------------------------------------------------------------- # New Metrics #----------------------------------------------------------------- - no_boilerplate - has_valid_filenames - declares_dependencies - no_open_bugs - no_old_open_bugs (older than a year?) - license_is_actual might be a good addition, like "copyright 2001-2002" is rather outdated - add list of modules that fail the use_warnings to $d->{error}{use_warnings} - same for use_strict - Allow the Debian and/or the Fedora packagers to "manually" report problems they encounter with certain packages directly from their systems. So if there is a module that cannot automatically packaged (or tested?) because they are interactive (in the wrong way) or they need network access... On the Debian list it was discussed that they might start saving this information from themself and then export this information with the rest of the data about packages. - Signature checking ? - has_rating ? - relation of subs to lines of code ? - easily_repackagable - easily_repackagable_by_debian - easily_repackagable_by_fedora on http://www.perlfoundation.org/perl5/index.cgi?cpan_packaging there are guidelines for module authors to make their modules easily repackagable by downstream distros. It would be great if we could add as many to CPANTS as possible. Some we can check without executing code. Others might be verified by the CPAN Testers, reported by the tools and then collected from the reports by CPANTS. - version_number_is_sane There are several issues here: 1) Is the version number sane for perl (I think there is a metric already) 2) Is the version number sane for Debian/RedHat (they have different meaning of sane) 3) Is the scheme of the version numbers stable? (In Debian they don't like when ppl are changing from D.DD to a D.D scheme or vice versa. 1.1.1 is not considered correct by MakeMaker but it is currently accepted by CPANTS http://cpants.perl.org/dist/kwalitee/Sys-HostIP http://www.nntp.perl.org/group/perl.qa/2007/12/msg10025.html - has_same_version_number_in_all_files ??? Some people will argue that when one of the files does not change, there is no need to change its version number. So this might not be a good metric. - no_bugs_in_freebsd - has_patches_in_freebsd The Debian and FreeBSD ppl will provide the interface for this -probably a csv file that can be fetched using http. This should be (an optional?) negative metric in case the module is included in FreeBSD or Debian but it had to be patched. (Maybe we need to make sure that we set this negative metric only when the module versions are the same so we won't penalize a module because XYZ has not yet integrated the newer version that possibly already includes the patch. - We might even have an optional metric to show that "the latest version of the module is included in Debian/FreeBSD etc". This will be lost every time a new version of a module is released but over time it will become ok again. (in xt/ or in t/ and the same file has RELEASE_TESTING in it) - has_no_indirect_code Check the source code (and/or) the documentation if you see new Module::Name anywhere mark the metric as failed. - all_links_in_the_documentation_still_exist - declares_minimal_version_of_perl It has "use N" somewhere in the Makefile.PL and/or Build.PL and/or the source code. (and they match to each other :-) (No specific N should be required) - "something about has good perl code" (e.g. if uses 3 param open but does not say use perl 5.6 or similar) - has_humanreadable_license the actual name of the license (perl, etc.) is in the database, use it Module::License::Report integration (though I am not sure if that should mean the main .pm file only or all the files or what) - licenses_are_consistent Locate places where hard-coded pathes to perl (or other files?) are: > > my @cmd = qw{/usr/bin/perl -Ilib -MPod::HtmlEasy -e}; actually try to locate places where perl is called instead of $^X <@Tux> has no open bugs in RT older than 2 months <@Tux> and debian shipped last version is only ok is last version is older than 3 months #----------------------------------------------------------------- # Other Stuff #----------------------------------------------------------------- - include more dists in test (for better test coverage) - improve NeedsCompiler (see its TODO) - Perl Critic report: As this is not really in the consensus probably it is better not add it as a metric now but it might be nice to run it on each module (starting at level 5 ) and display it along with the metrics. Maybe it can be added as an optional metric. - http://cpants.perl.org/author/search should also work on partial names adding % % automatically (or at least tell the users on the search page to use % as wildcards. - create stats (or metrics) for distros that were uploaded recently with failing metrics. e.g. the fact that 9920 Distributions failing 'metayml_has_license' is skewed by the many modules that were not updated in the past 1-2 years. It would be more important to see the number of modules uploaded in the last year without metayml of without license field in the metayaml. - Export the kwalitee of each distro in a csv file like so it can be easily integrated into other web sites such as the search engines. - Export the kwalitee of each distro in a csv file like so it can be easily integrated into other web sites such as the search engines. - Create a hierarchical report (aka CPANDepth) showing all the dependencies their kwalitee, their age, their license (the name of the license from META.yml for now) - honor the META.yml key no_index. See RT#32777 - Display the version of CPANTS used for indexing and show the date when the last update was executed. Maybe do so per distribution? Module-CPANTS-Analyse-1.01/.travis.yml0000644000175000017500000000026413522715243017521 0ustar ishigakiishigakidist: trusty language: perl perl: # - "5.8.1" - "5.8" - "5.10" - "5.12" - "5.14" - "5.16" - "5.18" - "5.20" - "5.22" - "5.24" - "5.26" - "5.28" # - "blead" Module-CPANTS-Analyse-1.01/META.json0000644000175000017500000000442013522716652017034 0ustar ishigakiishigaki{ "abstract" : "Generate Kwalitee ratings for a distribution", "author" : [ "Thomas Klausner ", "Kenichi Ishigaki " ], "dynamic_config" : 0, "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010", "keywords" : [ "CPANTS", "kwalitee" ], "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Module-CPANTS-Analyse", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker::CPANfile" : "0.08", "perl" : "5.008001" } }, "runtime" : { "requires" : { "Archive::Any::Lite" : "0.06", "Archive::Tar" : "1.76", "Array::Diff" : "0.04", "CPAN::DistnameInfo" : "0.06", "CPAN::Meta::Validator" : "2.133380", "CPAN::Meta::YAML" : "0.008", "Class::Accessor" : "0.19", "Data::Binary" : "0", "File::Find::Object" : "v0.2.1", "JSON::PP" : "0", "List::Util" : "1.33", "Module::Find" : "0", "Perl::PrereqScanner::NotQuiteLite" : "0.9901", "Software::License" : "0.103012", "Text::Balanced" : "0", "perl" : "5.008001", "version" : "0.73" }, "suggests" : { "Config::INI::Reader" : "0", "Module::CPANfile" : "0" } }, "test" : { "requires" : { "Cwd" : "0", "Test::FailWarnings" : "0", "Test::More" : "0.88" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Module-CPANTS-Analyse" }, "homepage" : "https://cpants.cpanauthors.org", "repository" : { "url" : "https://github.com/cpants/Module-CPANTS-Analyse" } }, "version" : "1.01", "x_serialization_backend" : "JSON::PP version 4.00" } Module-CPANTS-Analyse-1.01/Changes0000644000175000017500000004105313522716625016711 0ustar ishigakiishigakiRevision history for Module-CPANTS-Analyse 1.01 2019-08-08 - Fixed not to set an error message when extracted nicely (spotted by Martin Becker++) - Fixed to restore mtime of MANIFEST.SKIP if it is modified by #include_default - Improved primary module detection - Fixed to catch CPAN::Meta::YAML's warnings (of duplicate keys) - Improved test_prereqs_match to handle t::lib::Util, and ignore files that contain but don't end with .t - Fixed to store multiple licenses in META files 1.00 2019-02-03 ** BACKWARD INCOMPATIBLE CHANGE ** - Module::CPANTS::Kwalitee::Uses now uses a different prereq scanner (Perl::PrereqScanner::NotQuiteLite). - Added new kwalitee metrics: no_maniskip_error, no_missing_files_in_provides, no_files_to_be_skipped - Delayed plugin loading 0.99 2019-01-15 - requires Module::Find 0.98 2019-01-15 ** BACKWARD INCOMPATIBLE (INTERNAL) CHANGE ** - Module::CPANTS::Kwalitee now uses Module::Find to find Kwalitee modules (instead of Module::Pluggable that unconditonally spits a deprecation warning). You usually don't need to care but if you have your custom Kwalitee plugin loader (such as Module::CPANTS::SiteKwalitee), you need to change it. Sorry for the inconvenience. - Allow dash and dot in script name in the NAME section for non-pm, non-pod files 0.97_11 2018-04-22 - no changes; for testing 0.97_10 2018-04-22 - no changes; for testing 0.97_09 2018-04-22 - no changes; for testing 0.97_08 2018-04-22 - no changes; for testing 0.97_07 2018-04-22 - no changes; for testing 0.97_06 2018-04-22 - no changes; for testing 0.97_05 2018-04-22 - no changes; for testing 0.97_04 2018-04-21 - Skip everything in MANIFEST.SKIP while testing symlinks (GH#33, Tux++) 0.97_03 2016-09-01 - Not to check use_strict/use_warnings for Perl 6 modules in a Perl 5 distribution (Stefan Seifert++) - Worked around a File::Find::Object issue (reported by dolmen) - Fixed dynamic_config handling (David Golden++) - Improved LICENSE file detection (RT#114247) 0.97_02 2016-04-27 - Requires List::Util 1.33 0.97_01 2016-04-24 - Added has_meta_json metric (RT#107885) - Accept a few more README extensions (mrcaron) - Accept two more Moose modules as strict equivalents - Various micro optimization for performance - Dropped a few dependencies - Doc patch from brac-mac and joenio 0.96 2014-11-24 - Added an import option to load extra Kwalitee plugins. - Fixed RT#100512 - has_readme now accepts README.pod as well - Improved no_abstract_stub_in_pod to detect "The great new" as a boilerplate - Switched to File::Find::Object 0.95 2014-09-26 - Switched to Test::FailWarnings to make CPAN testers happier 0.94 2014-09-26 - Fixed RT#99141 - use_strict metric does not recognize `use v5.14` syntax (ishigaki) 0.93_04 2014-09-05 - Accept COPYING as a license file - Take included module (under inc/) into consideration while analyzing prereq_matches_use - Changed most of the META.yml metrics to pass if META.yml doesn't exist 0.93_03 2014-08-13 - Added meta_json_is_parsable and meta_json_conforms_to_known_spec - Added meta_yml_has_repository_resource - Renamed metayml_ metrics to meta_yml_ - Fixed abstract encoding issues - Refactored tests - Fixed not to ignore directory symlinks - Fixed RT#97858 - wrong no_symlinks test in files not in MANIFEST (for a local distribution; CPANTS site doesn't ignore symlinks not listed in MANIFEST) - Fixed RT#97601 - Test::Kwalitee incorrectly reports non-use of strict in Inline::CPP 0.93_02 2014-06-30 - Removed cpants_lint.pl in favor of App::CPANTS::Lint - Fixed RT#94468 - "use_strict" metric doesn't like .pod files that contain no perl (ishigaki) - Fixed RT#96492 - 0.93_01 test failures on OSX (ether) 0.93_01 2014-05-27 - Added the following metrics: - has_known_license_in_source_file - has_abstract_in_pod - no_abstract_stub_in_pod - Removed metayml_conforms_spec_current metric. - Supported x_cpants custom META field to tell analyzer to ignore some of the metrics (only) when calculating a kwalitee score. - Refactored several Kwalitee files, and internal stash layout has changed rather significantly. You might need to modify your tools if they happen to depend on the stash directly. 0.92 2013-09-22 - Fixed a case when more than one license sections come in row (spotted by ysasaki++) (ishigaki) - stopped checking auto_features (ishigaki) 0.91 2013-09-05 - Fixed RT#69233 - doesn't detect use >= 5.012 as use strict (ishigaki) - Fixed RT#83336 - Fails to detect strict via `use MooseX::Types` (ether) - Fixed RT#83851 - 'use v5.16' and greater not deemed "strict" (ishigaki) - Fixed RT#86504 - fix sort order of Kwalitee generators (ether) - Fixed RT#87155 - more Module::Install tests needed (1.04 is broken) (ishigaki) - Fixed RT#87597 - proper_libs is a dubious test (ishigaki) - Fixed RT#87598 - Can't use an undefined value as an ARRAY reference at .../FindModules.pm line 115. (ishigaki) - Fixed RT#87988 - Fix use of $Test::Kwalitee::VERSION (ether) - Fixed RT#88216 - extracts_nicely metric fails for -TRIAL releases (ishigaki) - Fixed RT#88365 - YAML/JSON tests are not failing when improperly encoded characters are seen (ishigaki) - Moose::Exporter also provides strict and warnings (doy) 0.90_02 2013-08-03 - Fixed rt#87535 - incorrect version specification in 0.90_01 (ether) - Fixed rt#87534 - Test failure in 0.90_01 (ether) - Fixed rt#87561 - t/11_hash_random.t fails due to undeclared test dependency (wyant) 0.90_01 2013-08-01 - Applied all the changes in 0.88 again, and removed a few non-portable metrics for Test::Kwalitee. 0.89 2013-08-01 - Tentatively reverted all the changes in 0.88 0.88 2013-08-01 - add metric "no_dot_underscore_files" (daxim, charsbar) - remove metrics "distributed_by_debian", "latest_version_distributed_by_debian", "has_no_bugs_reported_in_debian", "has_no_patches_in_debian", "no_cpants_errors", "uses_test_nowarnings", "has_test_pod", "has_test_pod_coverage", "has_examples" (charsbar) - add metric "portable_filenames" (charsbar) - numerous fixes for a smoother operation of www-cpants (charsbar) 0.87 2013-02-12 - fix rt#80225 - Test failures due to Test::CPAN::Meta::YAML::Version interface change (wyant) - fix rt#82939 - Hash-Randomization causes 10_analyse.t to fail (kentnl, chorny) - fix rt#44796 - Module::CPANTS::Kwalitee::Manifest broken for MANIFESTs containing files with spaces (rivy) 0.86 2012-04-11 - add several strict and warnings equivalents & make it easy to add more - fix when Moose is used and strict is not used - add info about "MIN_PERL_VERSION" - better remedy for metayml_declares_perl_version - metayml_declares_perl_version moved from experimental to extra some pod improvements (jquelin) - fix rt#65903 - no more "Test::YAML::Meta::Version" on CPAN (jquelin) - replace YAML::Syck with YAML::Any (jquelin) - no_symlinks checks only files in MANIFEST, use "maniread" in ExtUtils::Manifest (rurban) - add more equivalents for use_strict and use_warnings tests (doherty) - implement valid_signature metric (daxim) 0.85 2009-07-12, Alexandr Ciornii - fix fails on non-Win32 0.84 2009-07-08, Alexandr Ciornii - require Test::Warn 0.11 - add Test::More to deps - add LWP::Simple to deps - fix calc_test_yaml_meta.t - better META.yml - list of changes for 0.83 (domm) 0.83 2009-06-10 - ignore "no_index" when searching for examples (xdaveg) - skip the debian metrics and downloading the debian file when in LINT (szabgab) - has_test_pod and has_test_pod_coverage are now optional metrics (domm) 0.82 2008-07-08 10:23:30 - update META.yml spec to 1.4 - fixed experimental metrics - use Moose now counts for using strict - lots of commits from Gábor - honor META.yml key "no_index". - Fixes RT#32777 and an IRC complaint by BinGOs 0.81 Sun Apr 13 16:45:29 CEST 2008 - fixed doc bug in SYNOPSIS (reported by ADAMOWSKI as RT#34773) - made Module::CPANTS::Kwalitee::FindModules smarter (domm): If available, use META.yml "provides". If not, look for "package" statements in files. It now also finds stuff like Tk::Widget and App::Ack upgrade to Software::License 0.003 (Gábor) 0.80 Sat Apr 12 10:53:40 CEST 2008 domm: - add metayml_has_provides metric Gábor Szabó: - simplify the way the VERSION number is looked up, keep the full version line - increase the no_large_files limit to 200_000 - some unit test fixes thanks to Tux - some of {error} fields are now ARRAY refs instead of strings - more detailed unit tests - add "LICENCE" to the list of special files (not only LICENSE) - collect the license information of each file using Software::LicenseUtils - add has_separate_license_file metric - add has_license_in_source_file metric 0.79 Tue Apr 8 01:25:12 CEST 2008 - released at the Oslo QA Hackathon 2008 Gábor Szabó: - replace File::Find by File::Find::Rule - add no_large_files metrics - add fits_fedora_license metric that was inside the - easily_repackageable_by_fedora metric - add "is_experimental" flag to some of the metrics - add aggregating key to metric to list the other metrics being aggregated - unhide some errors during testing - renamed some error fields - add metayml_declares_perl_version metric 0.78 2008-04-06 - released at the Oslo QA Hackathon 2008 - very hacky workaround for problems with Meta.YML, version objects, etc - moved "has_version_in_each_file" into - Module::CPANTS::Kwalitee::Version & fixed a bug in it Gábor Szabó: - add fits_fedora_license metric that was inside the - easily_repackageable_by_fedora metric - add "is_experimental" and "is_aggregate" flags to some of the metrics - unhide some errors during testing - add no_generated_files metric - add easily_repackageable_by_fedora, - easily_repackagable_by_debian and easily_repackageable metric - add has_version_in_each_file metric - add has_tests_in_t_dir metric - add no_stdin_for_prompting metric checking for STDIN in Makefile.PL and Build.PL 0.77 2008-01-29 - made prereq_matches_use and build_prereq_matches_use optional metrics - changed data structure: all errors are now in a hashref called "error" 0.76 2007-11-14 - added new metrics prereq_matches_use and build_prereq_matches_use - added "needs_db" to metrics and removed hardcoded workaround for is_prereq - removed workaround in Module::CPANTS::Kwalitee::MetaYML (Barbie fixed it the problem in Test::YAML::Meta) - reworded metayml_is_parsable remedy 0.75 2007-10-29 - added optional metric use_warnings - added directory xt as a potential location for test files - finally applied patch provided by Adriano Ferreira to fix some issues in Module::CPANTS::Kwalitee::Manifest. See RT #28982 0.74 2007-10-24 - removed metric "metayml_conforms_spec_1_0" - fixed bug in "check_spec_conformance" in Module::CPANTS::Kwalitee::MetaYML, which caused wrong results in metayml_conforms_spec* - switched to YAML::Syck - work around Pod::Simple::Checker returning strange data 0.73 2007-09-12 - added version of dist to dump file name - fixed bug in Module::CPANTS::Kwalitee::NeedsCompiler (RT #28134 plus all reported merged into that one) 0.72 2007-06-30 - added docs to cpants_lint.pl - cpants_lint.pl can now dump metadata to a file - added YAML output to cpants_lint.pl Gábor Szabó: - added Module::CPANTS::Kwalitee::NeedsCompiler MCK::NeedsCompiler does not contain any "kwalitee_indicator", but adds much needed metadata. Barbie: - Module::CPANTS::Analyse assumes Unix paths after munging with File::Spec, thus breaking portability at every turn in a non-Unix-like environment… bad Thomas no biscuit! Refined META.yml metrics using Test::YAML::Meta and brought *current spec* up to date with version 1.3 :) 0.71 2007-04-23 - moved svn repo to - has_license now also checks for LICENCE (as suggested by David Cantrell) - fixed RT #26535 reported by MTHURN - has_example now also checks for "p(m|od)" files (as suggested by JUERD) - fixed RT #24228 reported by THALJEF - t/99_critic.t now only runs if $ENV{AUTHOR_TEST} is set - resolved RT #25198 reported by bdfoy using his patch Module::CPANTS::Kwalitee::FindModules: do not check META.yml for "provides" because META.yml might list semi-garbage (eg according to META.yml, Siesta provides Apache::Constants, which it does not.) - skip very large test-files and only check *.t files (not everything in t/) as suggested by CASIANO - cpants_lint.pl: - switched from Getopt::Std to Getopt::Long - added "--no_capture" option for easier debugging - added "--verbose" options - hopefully fixed RT #25207 (test failures on Win32) reported (and patched…) by HEMINGWAY. This should also solve RT #26535 reported by Martin Thurn - applied doc patch submitted by MSTEVENS as RT #26379 0.69 2006-11-04 - split up "metayml_conforms_spec" to metayml_conforms_spec_1_0 and "metayml_conforms_spec_1_2" (which is optional) - added "metayml_error" and docu pointers to it. 0.68 2006-10-28 - fixed bug in Module::CPANTS::Kwalitee::FindModules reported by JDHEDDEN in RT #22081 (the module name of modules living in the top-level namespace (eg 'threads.pm') was not guessed correctly use META.yml "provides" (if it exists) instead of guessing module names in Module::CPANTS::Kwalitee::FindModules modifed changelog-regex in Module::CPANTS::Kwalitee::Files as suggested by CDOLAN in RT #21999 - added Module::CPANTS::Kwalitee::License - moved license checking to Module::CPANTS::Kwalitee::License - added checks for LICENSE file and "LICENSE" POD section - moved "meta_yml" parsing to Module::CPANTS::Kwalitee::MetaYML - changed "has_license|Module::CPANTS::Kwalitee::License" error text after Schwern (and Andreas Koenig) suggested that ExtUtils::MakeMaker now supports a "license" field 0.67 2006-09-13 - cpants_lint.pl now handles reporting of optional metrics better. - added t/99_critic.t (Gábor Szabó) - some code cleanups as reported by Test::Perl::Critic (Gábor Szabó) - new metric: "has_license|Module::CPANTS::Kwalitee::License"; - Module::CPANTS::Kwalitee::MetaYML (Gábor Szabó) - Module::CPANTS::Kwalitee::Pod now reports the error messages returned by Pod::Simple::Checker (suggested by Gábor Szabó) 0.66 2006-09-06 - added "optional_indicator_names utility" in Module::CPANTS::Kwalitee method 0.65 2006-09-05 (YAPC::Europe hackathon release) - updated test suite - added "has_example" to Module::CPANTS::Kwalitee::Files - added "buildtool_not_executable" to Module::CPANTS::Kwalitee::Files - added Module::CPANTS::Kwalitee::Manifest ("manifest_matches_dist") 0.64 2006-08-29 - updated Module::CPANTS::Kwalitee::BrokenInstaller submitted by Steffen Müller 0.63 2006-07-31 - we now also find README.txt - resolves RT #20633 reported by MBARBON (thanks for the patch!) 0.62 2006-07-20 - added Module::CPANTS::Kwalitee::BrokenInstaller submitted by Steffen Müller 0.61 2006-07-17 - Kwalitee metrics can now be marked as "is_extra" Such metrics do not count for available kwalitee - marked is_prereq as "is_extra" - cpants_lint now reports percentages additional to absolute values - cpants_lint won't list failed "is_extra" metrics - added some method caching to Module::CPANTS::Kwalitee - added Ctotal_kwalitee> to Module::CPANTS::Kwalitee. 0.60 2006-05-18 - activated is_prereq metric - added helper method ("available_kwalitee") - Module::CPANTS::Kwalitee::FindModules: skip stuff in inc (Module::Install) 0.52 2006-03-12 - added some dependencies to Build.PL/META.yml (thanks to Achim Grolms and BLBLACK (RT #17977)) - enhanced output of cpants_lint.pl (list failed tests) - Module::CPANTS::Kwalitee::FindModules: die if we cannot find a namespace - Module::CPANTS::Kwalitee::FindModules: remove stuff that doesn't seem to be namespace (eg lowercase) from module names - changed the name of some fields to work with the (upcoming) DB added some tests 0.51 2006-02-16 - adapted Module::CPANTS::Kwalitee::Prereq to work with newer versions of YAML (reported by Andreas Koenig as RT #17670) 0.50 2006-01-26 - first release to CPAN 0.01 - started rewrite Module-CPANTS-Analyse-1.01/README.md0000644000175000017500000000230112707172025016660 0ustar ishigakiishigaki# Module-CPANTS-Analyse ## NAME README - basic information for users prior to downloading ## DESCRIPTION Module-CPANTS-Analyse tests a dist for Kwalitee. This module is part of the [CPANTS project](http://cpants.cpanauthors.org). ## AUTHOR [Thomas Klausner](https://metacpan.org/author/domm), ## Distribution maintainer [Kenichi Ishigaki](https://metacpan.org/author/ishigaki), ## Contributors See file AUTHORS. ## COPYRIGHT Copyright © 2003–2009 [Thomas Klausner](https://metacpan.org/author/domm), Some files are Copyright © 2006–2008 [Gábor Szabó](https://metacpan.org/author/szabgab), Some files are Copyright © 2006 [Steffen Müller](https://metacpan.org/author/smueller), Some files are Copyright © 2012 [Lars Dɪᴇᴄᴋᴏᴡ](https://metacpan.org/author/daxim), Some files are Copyright © 2013- [Kenichi Ishigaki](https://metacpan.org/author/ishigaki), Copyright © 2012, Perl QA team The module distributions in the F directory are copyright by their respective authors. ## LICENSE This code is distributed under the same license as Perl. Module-CPANTS-Analyse-1.01/Makefile.PL0000644000175000017500000000131213425457651017365 0ustar ishigakiishigakiuse 5.008001; use strict; use warnings; use ExtUtils::MakeMaker::CPANfile; WriteMakefile( NAME => 'Module::CPANTS::Analyse', AUTHOR => [ 'Thomas Klausner ', 'Kenichi Ishigaki ', ], ABSTRACT_FROM => 'lib/Module/CPANTS/Analyse.pm', VERSION_FROM => 'lib/Module/CPANTS/Analyse.pm', LICENSE => 'perl', META_MERGE => { resources => { homepage => 'https://cpants.cpanauthors.org', repository => 'https://github.com/cpants/Module-CPANTS-Analyse', bugtracker => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Module-CPANTS-Analyse', }, keywords => [ 'CPANTS','kwalitee', ], }, test => {TESTS => 't/*.t t/*/*.t'}, ); Module-CPANTS-Analyse-1.01/META.yml0000644000175000017500000000252713522716652016672 0ustar ishigakiishigaki--- abstract: 'Generate Kwalitee ratings for a distribution' author: - 'Thomas Klausner ' - 'Kenichi Ishigaki ' build_requires: Cwd: '0' ExtUtils::MakeMaker: '0' Test::FailWarnings: '0' Test::More: '0.88' configure_requires: ExtUtils::MakeMaker::CPANfile: '0.08' perl: '5.008001' dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010' keywords: - CPANTS - kwalitee license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Module-CPANTS-Analyse no_index: directory: - t - inc requires: Archive::Any::Lite: '0.06' Archive::Tar: '1.76' Array::Diff: '0.04' CPAN::DistnameInfo: '0.06' CPAN::Meta::Validator: '2.133380' CPAN::Meta::YAML: '0.008' Class::Accessor: '0.19' Data::Binary: '0' File::Find::Object: v0.2.1 JSON::PP: '0' List::Util: '1.33' Module::Find: '0' Perl::PrereqScanner::NotQuiteLite: '0.9901' Software::License: '0.103012' Text::Balanced: '0' perl: '5.008001' version: '0.73' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Module-CPANTS-Analyse homepage: https://cpants.cpanauthors.org repository: https://github.com/cpants/Module-CPANTS-Analyse version: '1.01' x_serialization_backend: 'CPAN::Meta::YAML version 0.012' Module-CPANTS-Analyse-1.01/cpanfile0000644000175000017500000000164613522714744017126 0ustar ishigakiishigakirequires 'Array::Diff' => '0.04'; requires 'Archive::Any::Lite' => '0.06'; requires 'Archive::Tar' => '1.76'; # filter_cb requires 'Class::Accessor' => '0.19'; requires 'CPAN::DistnameInfo' => '0.06'; requires 'CPAN::Meta::YAML' => '0.008'; requires 'CPAN::Meta::Validator' => '2.133380'; requires 'Data::Binary' => '0'; requires 'File::Find::Object' => '0.2.1'; requires 'JSON::PP' => 0; requires 'List::Util' => '1.33'; requires 'Module::Find'; requires 'Perl::PrereqScanner::NotQuiteLite' => '0.9901'; requires 'perl' => '5.008001'; requires 'Software::License' => '0.103012'; requires 'Text::Balanced' => 0; requires 'version' => '0.73'; suggests 'Module::CPANfile'; suggests 'Config::INI::Reader'; on configure => sub { requires 'ExtUtils::MakeMaker::CPANfile' => '0.08'; requires 'perl' => '5.008001'; }; on test => sub { requires 'Cwd' => 0; requires 'Test::More' => '0.88'; requires 'Test::FailWarnings' => 0; }; Module-CPANTS-Analyse-1.01/MANIFEST0000644000175000017500000000215713522716652016551 0ustar ishigakiishigaki.travis.yml AUTHORS Changes cpanfile lib/Module/CPANTS/Analyse.pm lib/Module/CPANTS/Kwalitee.pm lib/Module/CPANTS/Kwalitee/BrokenInstaller.pm lib/Module/CPANTS/Kwalitee/CpantsErrors.pm lib/Module/CPANTS/Kwalitee/Distname.pm lib/Module/CPANTS/Kwalitee/Distros.pm lib/Module/CPANTS/Kwalitee/Files.pm lib/Module/CPANTS/Kwalitee/FindModules.pm lib/Module/CPANTS/Kwalitee/License.pm lib/Module/CPANTS/Kwalitee/Manifest.pm lib/Module/CPANTS/Kwalitee/MetaYML.pm lib/Module/CPANTS/Kwalitee/NeedsCompiler.pm lib/Module/CPANTS/Kwalitee/Pod.pm lib/Module/CPANTS/Kwalitee/Prereq.pm lib/Module/CPANTS/Kwalitee/Repackageable.pm lib/Module/CPANTS/Kwalitee/Signature.pm lib/Module/CPANTS/Kwalitee/Uses.pm lib/Module/CPANTS/Kwalitee/Version.pm Makefile.PL MANIFEST This list of files MANIFEST.SKIP README.md t/00_load.t t/05_testdir.t t/05_testfile.t t/analyse/manifest.t t/analyse/pod.t t/analyse/uses.t t/lib/Module/CPANTS/TestAnalyse.pm t/older_test_kwalitee.t t/x_cpants.t TODO META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Module-CPANTS-Analyse-1.01/MANIFEST.SKIP0000644000175000017500000000153313425457651017316 0ustar ishigakiishigaki# Avoid version control files. \bRCS\b \bCVS\b \bSCCS\b ,v$ \B\.svn\b \B\.git\b \B\.gitignore\b \b_darcs\b \B\.cvsignore$ # Avoid VMS specific MakeMaker generated files \bDescrip.MMS$ \bDESCRIP.MMS$ \bdescrip.mms$ # Avoid Makemaker generated and utility files. \bMANIFEST\.bak \bMakefile$ \bblib/ \bMakeMaker-\d \bpm_to_blib\.ts$ \bpm_to_blib$ \bblibdirs\.ts$ # 6.18 through 6.25 generated this # Avoid Module::Build generated and utility files. \bBuild$ \b_build/ \bBuild.bat$ \bBuild.COM$ \bBUILD.COM$ \bbuild.com$ # Avoid temp and backup files. ~$ \.old$ \#$ \b\.# \.bak$ \.tmp$ \.# \.rej$ # Avoid OS-specific files/dirs # Mac OSX metadata \B\.DS_Store # Mac OSX SMB mount metadata files \B\._ # Avoid Devel::Cover and Devel::CoverX::Covered files. \bcover_db\b \bcovered\b # Avoid MYMETA files ^MYMETA\. ^Module-CPANTS-Analyse ^tmp/ ^xt/