#!/usr/bin/perl

# $Header: /usr/local/CVS/Perl-Metrics-Simple/bin/countperl,v 1.9 2009/04/27 15:35:37 matisse Exp $
# $Revision: 1.9 $
# $Author: matisse $
# $Source: /usr/local/CVS/Perl-Metrics-Simple/bin/countperl,v $
# $Date: 2009/04/27 15:35:37 $
###############################################################################

package main;
use strict;
use warnings;
use Carp qw();
use Perl::Metrics::Simple qw(0.13);
use Pod::Usage;

our $VERSION = 0.13;

if ( !@ARGV ) {
    pod2usage( -verbose => 1 );
}
my $analzyer = Perl::Metrics::Simple->new;

my $analysis = $analzyer->analyze_files(@ARGV);

my $file_count    = $analysis->file_count;
my $package_count = $analysis->package_count;
my $sub_count     = $analysis->sub_count;
my $lines         = $analysis->lines;
my $main_stats    = $analysis->main_stats;
my $file_stats    = $analysis->file_stats;

my $summary_stats = $analysis->summary_stats;

print <<"EOS" or Carp::croak('Could not print!');

Perl files found:                $file_count

Counts
------
total code lines:        $lines
lines of non-sub code:   $main_stats->{lines}
packages found:          $package_count
subs/methods:            $sub_count

Subroutine/Method Size
----------------------
min:                  $summary_stats->{sub_length}->{min} lines
max:                  $summary_stats->{sub_length}->{max} lines
mean:                 $summary_stats->{sub_length}->{mean} lines
std. deviation:       $summary_stats->{sub_length}->{standard_deviation}
median:               $summary_stats->{sub_length}->{median}

McCabe Complexity
-----------------
Code not in any subroutine::
min:                  $summary_stats->{main_complexity}->{min}
max                   $summary_stats->{main_complexity}->{max}
mean:                 $summary_stats->{main_complexity}->{mean}
std. deviation:       $summary_stats->{main_complexity}->{standard_deviation}
median:               $summary_stats->{main_complexity}->{median}

Subroutines/Methods:
min:                  $summary_stats->{sub_complexity}->{min}
max:                  $summary_stats->{sub_complexity}->{max}
mean:                 $summary_stats->{sub_complexity}->{mean}
std. deviation:       $summary_stats->{sub_complexity}->{standard_deviation}
median:               $summary_stats->{sub_complexity}->{median}

Tab-delimited list of subroutines, with most complex at top
-----------------------------------------------------------
EOS

my @main_from_each_file = map { $_->{main_stats} } @{ $analysis->file_stats };

my @sorted_subs = sort _by_complexity(), @{ $analysis->subs },
    @main_from_each_file;
my $header = join( "\t", 'complexity', 'sub', 'path', 'size' );
$header .= "\n";
print "$header"
    || Carp::croak('Could not print to currently selectd filehandle.');
foreach my $sub (@sorted_subs) {
    my %sub_hash = %{$sub};
    my $line     = join( "\t",
        @sub_hash{ 'mccabe_complexity', 'name', 'path', 'lines' } );
    $line .= "\n";
    print "$line"
        || Carp::croak('Could not print to currently selected file handle.');
}

exit;

sub _by_complexity {
    return $b->{mccabe_complexity} <=> $a->{mccabe_complexity};
}

__END__

=head1 NAME

countperl - count lines, packages, subs and complexity of Perl files.

=head1 SYNOPSIS

B<countperl> F<FILE_OR_DIRECTORY> [F<FILE_OR_DIRECTORY> ....]

=head1 REQUIRED ARGUMENTS

At least one file or directory path must be supplied.

=head1 EXIT STATUS

Exits zero on success, non-zero on failure.

=head1 DESCRIPTION

F<countperl> uses B<Perl::Metrics::Simple> to examines the named files and
recursivesly searches named directories for Perl files.


Perl files are identified by B<Perl::Metrics::Simple-E<gt>is_perl_file>. Basically
if the file ends in C<.pl>, C<.pm>, or C<.t> or has what appears to be a perl
I<shebang> line.

F<countperl> produces a report on F<STDOUT> of counts of total lines,
packages, subroutines/methods,
the minimum, maximum, mean, standard deviation, and median size and
mccabe_complexity (cyclomatic complexity) of subroutines and
the 'main' portion of each file (everything not in a subroutine.)

=head2 Output Format

Line counts do not include comments nor pod.

The current output format is human-readable text:

    Perl files found:                3
    
    Counts
    ------
    total code lines:       856
    lines of non-sub code:  450
    packages found:           3
    subs/methods:            42
    
    Subroutine/Method Size
    ----------------------
    min:                  3 lines
    max:                  32 lines
    mean:                 9.67 lines
    std. deviation:       7.03
    median:               7.50
    
    McCabe Complexity
    -----------------
    Code not in any subroutine::
    min:                  1
    max                   1
    mean:                 1.00
    std. deviation:       0.00
    median:               1.00
    
    Subroutines/Methods:
    min:                  1
    max:                  5
    avg:                  1.00
    std. deviation:       1.36
    median:               1.00
    
    Tab-delimited list of subroutines, with most complex at top
    -----------------------------------------------------------
    complexity      sub     path    size
    5       is_perl_file    lib/Perl/Metrics/Simple.pm      11
    5       _has_perl_shebang       lib/Perl/Metrics/Simple.pm      13
    5       _init   lib/Perl/Metrics/Simple/Analysis/File.pm        30
    4       find_files      lib/Perl/Metrics/Simple.pm      11
    4       new     lib/Perl/Metrics/Simple/Analysis.pm     10
    4       is_ref  lib/Perl/Metrics/Simple/Analysis.pm     8

=head1 VERSION

This is version 0.031 of F<countperl>.


=head1 BUGS AND LIMITATIONS

=head2 Bugs
No bugs reported yet :-)
See: http://rt.cpan.org/NoAuth/Bugs.html?Dist=Perl-Metrics-Simple

=head2 Limitations

=over 4

=item Does not accept input from STDIN.

=item No machine-readable report format available (e.g. XML, tab-delimited)

=back

=head1 SUPPORT

Via CPAN:

=head2 Disussion Forum

http://www.cpanforum.com/dist/Perl-Metrics-Simple

=head2 Bug Reports

http://rt.cpan.org/NoAuth/Bugs.html?Dist=Perl-Metrics-Simple

=head1 DEPENDENCIES

=over 4

=item L<Perl::Metrics::Simple> 0.03 (which depends upon L<PPI>.)

=item L<Pod::Usage>

=back

=head1 SEE ALSO

=over 4

=item L<PPI>

=item L<Perl::Critic>

=item L<Perl::Metrics>

=item http://en.wikipedia.org/wiki/Cyclomatic_complexity

=back

=head1 AUTHOR

    Matisse Enzer
    CPAN ID: MATISSE
    Eigenstate Consulting, LLC
    matisse@eigenstate.net
    http://www.eigenstate.net/

=head1 LICENSE AND COPYRIGHT

This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the
LICENSE file included with this module.

=cut
