package Module::CPANTS::Kwalitee::FindModules;
use warnings;
use strict;
use Data::Dumper;
use File::Spec::Functions;
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};
while (my ($module,$data)=each %$provides) {
my $file=$data->{file};
my $found={
module=>$module,
file=>$data->{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);
}
}
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
# 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,
});
}
else {
# open file and find first package
my $module;
my $max_lines_to_look_at=666;
open (my $fh,"<",catfile($me->distdir,$file)) || 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;
}
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,
});
}
}
}
}
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 directory lib.},
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'.},
code=>sub {
my $d=shift;
my $modules=$d->{modules};
return 0 unless $modules;
my @in_basedir=grep { $_->{in_basedir} } @$modules;
return 1 if $d->{dir_lib} && @in_basedir == 0;
return 1 if @in_basedir == 1;
return 0;
},
},
];
}
q{Favourite record of the moment:
Fat Freddys Drop: Based on a true story};
__END__
=pod
=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<MCK::FindModules> is used by other tests.
=head3 analyse
C<MCK::FindModules> first looks in C<basedir> and F<lib/> for C<*.pm> files. If it doesn't find any, it looks in the whole dist, but the C<proper_libs> kwalitee point is only awarded if the modules are F<lib/> or there's only one module in C<basedir>.
=head3 kwalitee_indicators
Returns the Kwalitee Indicators datastructure.
=over
=item * proper_libs
=back
=head1 SEE ALSO
L<Module::CPANTS::Analyse>
=head1 AUTHOR
Thomas Klausner, <domm@cpan.org>, http://domm.zsi.at
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2003-2006, 2009 Thomas Klausner
You may use and distribute this module according to the same terms
that Perl is distributed under.
=cut