File Coverage

blib/lib/GraphViz/Graph.pm
Criterion Covered Total %
statement 49 74 66.2
branch 8 16 50.0
condition 1 2 50.0
subroutine 10 14 71.4
pod 1 7 14.2
total 69 113 61.0


line stmt bran cond sub pod time code
1             #_{ Encoding and name
2             =encoding utf8
3              
4             =head1 NAME
5              
6             GraphViz::Graph - Object Oriented interface to graphviz.
7             =cut
8              
9             package GraphViz::Graph;
10              
11 8     8   72380 use strict;
  8         26  
  8         758  
12 8     8   56 use warnings;
  8         24  
  8         264  
13 8     8   7084 use utf8;
  8         146  
  8         53  
14             #_}
15             #_{ Version
16             =head1 VERSION
17              
18             Version 0.01
19              
20             =cut
21              
22             our $VERSION = '0.01';
23             #_}
24             #_{ Synopsis
25             =head1 SYNOPSIS
26              
27             use GraphViz::Graph;
28              
29             my $graph = GraphViz::Graph->new('filename-without-suffix');
30              
31             # Create nodes:
32             my $nd_1 = $graph->node(…);
33             my $nd_2 = $graph->node(…);
34              
35             # Connect nodes:
36             $graph->edge($nd_1, $nd_2);
37              
38             # Create .dot file, run graphviz/dot to
39             # create filename-without-suffix.png:
40             $graph->create('png');
41             =cut
42             #_}
43             #_{ use …
44              
45 8     8   499 use Carp;
  8         23  
  8         747  
46 8     8   3448 use GraphViz::Graph::Edge;
  8         30  
  8         353  
47 8     8   3470 use GraphViz::Graph::Label;
  8         40  
  8         300  
48 8     8   3607 use GraphViz::Graph::Node;
  8         34  
  8         6337  
49              
50             #_}
51             #_{ Methods
52             =head1 METHODS
53             =cut
54              
55             sub new { #_{
56              
57             =head2 new
58              
59             my $graph = GraphViz::Graph->new('FileNameBase');
60              
61             Start a graph. C<'FileNameBase'> is the base name for the produced dot and png/pdf/svg… etc. output file.
62             =cut
63              
64 5     5 1 4258 my $class = shift;
65 5         16 my $file_base_name = shift;
66 5   50     39 my $opts = shift // {};
67              
68 5         63 my $self = {};
69              
70 5 100       39 croak 'File base name must be passed' unless defined $file_base_name;
71 4 100       339 croak 'File base name must be sclar' unless ref \$file_base_name eq 'SCALAR';
72              
73 2         8 $self -> {file_base_name} = $file_base_name;
74              
75             # $opts->{file_base_name} = $file_base_name;
76              
77 2 50       13 croak "Unrecognized opts " . join "/", keys %$opts if keys %$opts;
78              
79 2         10 $self->{nodes} = [];
80 2         7 $self->{edges} = [];
81              
82 2         8 bless $self, $class;
83 2         12 return $self;
84              
85             } #_}
86             sub label { #_{
87             #_{ POD
88             =head2 label
89              
90             GraphViz::Graph->label({text => 'Graph Title'}');
91             GraphViz::Graph->label({html => 'Say Hello World'}');
92              
93             Add a label to a graph. Most probably used as a title.
94              
95             =cut
96             #_}
97 0     0 0 0 my $self = shift;
98 0         0 my $opts = shift;
99              
100 0         0 $self -> {label} = GraphViz::Graph::Label->new($opts);
101              
102             } #_}
103             sub node { #_{
104             #_{
105             =head2 node
106              
107             my $nd_foo = GraphViz::Graph->node();
108             # … later:
109             $nd_foo -> label({html=>"BoldItalic"});
110              
111             Add a node to a graph
112              
113             =cut
114             #_}
115 0     0 0 0 my $self = shift;
116 0         0 my $opts = shift;
117              
118              
119 0         0 my $node = GraphViz::Graph::Node -> new($opts);
120              
121 0         0 push @{$self->{nodes}}, $node;
  0         0  
122              
123 0         0 return $node;
124              
125             } #_}
126             sub edge { #_{
127             #_{
128             =head2 edge
129              
130             Add an edge to a graph.
131              
132             my $nd_one = $graph->node();
133             my $nd_two = $graph->node();
134             my $nd_three = $graph->node();
135              
136             $nd_one->label({html=>"…"});
137              
138             $nd_two->label({html=>"
139            
fg
140            
"});
141              
142             $graph->edge($nd_one, $nd_two->port('port_f')):
143             $graph->edge($nd_two, $nd_three);
144              
145             =cut
146             #_}
147 0     0 0 0 my $self = shift;
148 0         0 my $from = shift;
149 0         0 my $to = shift;
150              
151 0         0 my $edge = GraphViz::Graph::Edge -> new($from, $to);
152              
153 0         0 push @{$self->{edges}}, $edge;
  0         0  
154              
155 0         0 return $edge;
156              
157             } #_}
158             sub write_dot { #_{
159              
160 1     1 0 3 my $self = shift;
161 1         133 open my $out, '>', "$self->{file_base_name}.dot";
162              
163 1         9 print $out "digraph {\n";
164              
165 1         4 for my $node (@{$self->{nodes}}) {
  1         5  
166 0         0 print $out $node -> dot_text();
167             }
168 1         5 for my $edge (@{$self->{edges}}) {
  1         5  
169 0         0 print $out $edge -> dot_text();
170             }
171              
172             # Define the graph label end of your dot file,
173             # otherwise subgraphs will inherit those properties.
174             # https://stackoverflow.com/a/4716607/180275
175 1 50       7 if ($self->{label}) {
176 0         0 print $out $self->{label}->dot_text;
177             }
178              
179 1         54 print $out "}\n";
180              
181             } #_}
182             sub create { #_{
183              
184 1     1 0 16 my $self = shift;
185 1         3 my $filetype = shift;
186              
187 1 50       7 croak "unspecified filetype" unless $filetype;
188              
189 1         7 $self->write_dot();
190              
191 1         10 my $command = "dot $self->{file_base_name}.dot -T$filetype -o$self->{file_base_name}.$filetype";
192              
193 1         2819 my $rc = system ($command);
194              
195 1 50       392 croak "rc = $rc, command=$command" if $rc;
196              
197             } #_}
198             sub node_or_port_to_string_ { #_{
199             #_{ POD
200             =head2 node_or_port_to_string_
201              
202             This function is internally used by the constructur (C) of L.
203              
204             =cut
205             #_}
206              
207 0     0 0   my $node_or_port = shift;
208              
209 0 0         if (ref $node_or_port eq 'GraphViz::Graph::Node') {
210 0           return $node_or_port->{id};
211             }
212 0 0         unless (ref $node_or_port) {
213             # String ???
214 0           return $node_or_port;
215             }
216              
217 0           croak "node_or_port neither Node nor string";
218             } #_}
219              
220             #_}
221             #_{ POD: Copyright
222              
223             =head1 Copyright
224              
225             Copyright © 2017 René Nyffenegger, Switzerland. All rights reserved.
226              
227             This program is free software; you can redistribute it and/or modify it
228             under the terms of the the Artistic License (2.0). You may obtain a
229             copy of the full license at: L
230              
231             =cut
232              
233             #_}
234             #_{ Testing
235              
236             =head1 Testing
237              
238             The tests need L.
239              
240             =cut
241              
242             #_}
243             'tq84'