NAME
Perl::Metrics::Simple - Count packages, subs, lines, etc. of many files.
SYNOPSIS
use Perl::Metrics::Simple;
$file_count = $analysis->file_count;
$package_count = $analysis->package_count;
$sub_count = $analysis->sub_count;
$lines = $analysis->lines;
$main_stats = $analysis->main_stats;
$file_stats = $analysis->file_stats;
DESCRIPTION
USAGE
use Perl::Metrics::Simple;
my $analzyer = Perl::Metrics::Simple->new;
my $analysis = $analzyer->analyze_files(@ARGV);
EXAMPLE SCRIPT
use strict;
use warnings;
use Data::Dumper;
use Perl::Metrics::Simple;
use Pod::Usage;
use Statistics::Basic::StdDev;
use Statistics::Basic::Mean;
use Statistics::Basic::Median;
pod2usage( -verbose => 1 ) if ( !@ARGV );
my $analzyer = Perl::Metrics::Simple->new;
my $IMPROBABLY_LARGE_NUMBER = 999_999_999_999;
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 %lines = ();
@lines{ 'min', 'max', 'counts' } =
_get_min_max_values( $analysis->subs, 'lines' );
$lines{average} = sprintf '%.2f',
Statistics::Basic::Mean->new( $lines{counts} )->query;
$lines{median} = sprintf '%.2f',
Statistics::Basic::Median->new( $lines{counts} )->query;
my %complexity = ();
@complexity{ 'min', 'max', 'scores' } =
_get_min_max_values( $analysis->subs, 'mccabe_complexity' );
$complexity{average} = sprintf '%.2f',
Statistics::Basic::Mean->new( $complexity{scores} )->query;
$complexity{median} = sprintf '%.2f',
Statistics::Basic::Median->new( $complexity{scores}, $sub_count )->query;
$complexity{standard_deviation} = sprintf '%.2f',
Statistics::Basic::StdDev->new( $complexity{scores}, $sub_count )->query;
my %main_complexity = ();
$main_complexity{average} = sprintf '%.2f',
$main_stats->{mccabe_complexity} / $file_count;
@main_complexity{ 'min', 'max', 'scores' } =
_get_min_max_values( $analysis->subs, 'mccabe_complexity' );
$main_complexity{median} = sprintf '%.2f',
Statistics::Basic::Median->new( $main_complexity{scores}, $file_count )->query;
$main_complexity{standard_deviation} = sprintf '%.2f',
Statistics::Basic::StdDev->new( $main_complexity{scores}, $file_count )->query;
print <<"EOS";
Perl Files: $file_count
Line Counts
-----------
lines: $lines
packages: $package_count
subs: $sub_count
all main code: $main_stats->{lines}
min. sub size: $lines{min} lines
max. sub size: $lines{max} lines
avg. sub size: $lines{average} lines
median sub size: $lines{median}
McCabe Complexity
-----------------
min. main: $main_complexity{min}
max. main: $main_complexity{max}
median main: $main_complexity{median}
average main: $main_complexity{average}
subs:
min: $complexity{min}
max: $complexity{max}
avg: $complexity{average}
median: $complexity{median}
std. deviation: $complexity{standard_deviation}
EOS
my @sorted_subs = sort _by_complexity(), @{ $analysis->subs };
print join( "\t", 'complexity', 'sub', 'path', 'size' ), "\n";
foreach my $sub (@sorted_subs) {
my %sub_hash = %{$sub};
print join( "\t",
@sub_hash{ 'mccabe_complexity', 'name', 'file_path', 'lines' } ),
"\n";
}
exit;
sub _by_complexity {
return $b->{mccabe_complexity} <=> $a->{mccabe_complexity};
}
sub _get_min_max_values {
my $nodes = shift;
my $hash_key = shift;
my @values = ();
my $min = $IMPROBABLY_LARGE_NUMBER;
my $max = 0;
foreach my $node ( @{$nodes} ) {
my $value = $node->{$hash_key};
$max = $value > $max ? $value : $max;
$min = $value < $min ? $value : $min;
push @values, $value;
}
return ( $min, $max, \@values );
}
__END__
PACKAGE PROPERTIES
Readonly values:
Used to measure mccabe_complexity, each occurance adds 1:
Readonly::Array our @LOGIC_OPERATORS =>
qw( && || ||= &&= or and xor ? <<= >>= );
Readonly::Hash our %LOGIC_OPERATORS => hashify(@LOGIC_OPERATORS);
Readonly::Array our @LOGIC_KEYWORDS =>
qw( for foreach if else elsif unless until while );
Readonly::Hash our %LOGIC_KEYWORDS => hashify(@LOGIC_KEYWORDS);
CLASS METHODS
new
Blah blah
OBJECT METHODS
analyze_files( @files_and_or_dirs )
Takes an array of files and or directory paths and returns a Perl::Metrics::Simple::Analysis object.
analyze_one_file
find_files
get_node_length
list_perl_files
measure_complexity($PPI_node)
Attempts to measure the cyclomatic complexity of a chunk of code.
Takes a PPI::Node and returns the total number of logic keywords and logic operators. plus 1. See the PACKAGE PROPERTIES
section for a list.
See also: http://en.wikipedia.org/wiki/Cyclomatic_complexity
The code for this method was copied from Perl::Critic::Policy::Subroutines::ProhibitExcessComplexity
is_perl_file($path)
Takes a path to a file and returns true if the file appears to be a Perl file, otherwise returns false.
If the file name does not match any of @Perl::Metrics::Simple::PERL_FILE_SUFFIXES then the file is opened for reading and the first line examined for a a Perl 'shebang' line. An exception is thrown if the file cannot be opened in this case.
BUGS
None reported yet :-) See: http://rt.cpan.org/NoAuth/Bugs.html?Dist=Perl-Metrics-Simple
SUPPORT
Via CPAN:
Disussion Forum
http://www.cpanforum.com/dist/Perl-Metrics-Simple
Bug Reports
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Perl-Metrics-Simple
AUTHOR
Matisse Enzer
CPAN ID: MATISSE
Eigenstate Consulting, LLC
matisse@eigenstate.net
http://www.eigenstate.net/
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.
SEE ALSO
- PPI
- Perl::Critic
- http://en.wikipedia.org/wiki/Cyclomatic_complexity