#!/usr/bin/perl use strict; use GraphViz; # A leading ':' is an abbreviation for 'HTML::Mason::' # If an object of one class has an object of another class as an entry # in $self, we note that here. my %has_a = ( ':Request::ApacheHandler' => [':ApacheHandler', ':Interp', 'Apache', 'CGI'], ':ApacheHandler' => [':Interp'], ':Interp' => [':Compiler', ':Resolver'], ':Compiler' => [':Lexer'], ':Component' => [':Interp'], ':Request' => [':Interp'], ); my %has_many = ( ':Request' => [':Buffer', ':Component'], ':Component' => [':Component'], ); # One class 'makes' another class by calling one of its constructor methods - usually new(). # (This list isn't finished yet - it's slow-going to figure this stuff out from the code.) my %makes_a = ( ':ApacheHandler' => [':Interp', ':Compiler', ':Request::ApacheHandler', 'CGI'], ':Interp' => [':Compiler', ':Resolver'], ':Compiler' => [':Lexer'], ); my %makes_many = ( ':Request' => [':Buffer'], ':Interp' => [':Request'], ); normalify(\%has_a, \%has_many, \%makes_a, \%makes_many); my $g = GraphViz->new( #rankdir => 1, random_start => 1, node => {fontname => "TIMESNR", fontsize => 9, shape => 'box'}, edge => {fontname => "TIMESNR", fontsize => 9}, ); add_data($g, \%has_a, style => 'solid'); add_data($g, \%has_many, style => 'solid', color => 'red'); add_data($g, \%makes_a, style => 'dashed'); add_data($g, \%makes_many, style => 'dashed', color => 'red'); # Could make an imagemap linking to class documentation... $g->as_gif("class_rels.gif"); ##################################################### # Add HTML::Mason:: to abbreviated package names sub normalify { foreach my $hashref (@_) { foreach my $key (keys %$hashref) { next unless $key =~ /^:/; my $val = $hashref->{"HTML::Mason:$key"} = delete $hashref->{$key}; foreach my $v (@$val) { $v =~ s/^:/HTML::Mason::/; } } } } sub add_data { my $g = shift; my $hashref = shift; while (my ($key, $val) = each %$hashref) { foreach my $class (@$val) { $g->add_edge($key => $class, @_); } } }