Analizo
view release on metacpan or search on metacpan
lib/Analizo/Command/graph.pm view on Meta::CPAN
package Analizo::Command::graph;
use Analizo -command;
use parent qw(Analizo::Command);
use strict;
use warnings;
use Analizo::Extractor;
use Graph::Writer::Dot;
use File::Basename;
# ABSTRACT: dependency graph generator
=head1 NAME
analizo-graph - dependency graph generator
=head1 USAGE
analizo graph [OPTIONS] <input> [<input> [<input> ...]]
=cut
sub usage_desc { "%c graph %o <input> [<input> [<input> ...]]" }
sub opt_spec {
return (
[ 'extractor=s', 'which extractor method use to parse the source code' ],
[ 'output|o=s', 'output file name' ],
[ 'omit=s', 'omit the given functions from the call graph', { default => '' } ],
[ 'cluster', 'cluster the functions into files' ],
[ 'modules', 'group the functions by modules(files)' ],
);
}
sub validate {
my ($self, $opt, $args) = @_;
$self->usage_error("No input files!") unless @$args;
my @unreadable = grep { ! -r $_ || ! -e $_ } @$args;
if (@unreadable) {
foreach my $file (@unreadable) {
$self->usage_error("$file is not readable");
}
}
if ($opt->output && ! -w dirname($opt->output)) {
$self->usage_error("No such file or directory");
}
}
sub execute {
my ($self, $opt, $args) = @_;
my $extractor = Analizo::Extractor->load($opt->extractor);
$extractor->process(@$args);
my @omitted = split /,/, $opt->omit;
my $graph = $extractor->model->callgraph(
group_by_module => $opt->modules,
omit => \@omitted,
);
if ($opt->output) {
open STDOUT, '>', $opt->output or die "$!";
}
my $stdout = \*STDOUT;
my $graph_writer = Graph::Writer::Dot->new(
cluster => ($opt->cluster ? 'group' : undef),
);
$graph_writer->write_graph($graph, $stdout);
close STDOUT;
}
=head1 DESCRIPTION
analizo graph reads the dependency information from one or more source code
directories passed as arguments, and produces as output the graph of
dependencies between the modules of the software in the graphviz(1) format.
analizo graph is part of the analizo suite.
=head1 REQUIRED ARGUMENTS
=over
=item <input>...
The input directories (or files) with source code to be processed.
Although you can pass individual files as input, this tool is more useful if
you pass entire source directories. If you pass just a couple of files, their
dependencies on modules that are not declared and/or implemented in those
files will not be calculated.
=back
=head1 OPTIONS
=over
( run in 0.715 second using v1.01-cache-2.11-cpan-d01c6094234 )