File Coverage

blib/lib/PYX/GraphViz.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package PYX::GraphViz;
2              
3             # Pragmas.
4 3     3   36902 use strict;
  3         7  
  3         76  
5 3     3   14 use warnings;
  3         4  
  3         84  
6              
7             # Modules.
8 3     3   2310 use Class::Utils qw(set_params);
  3         71076  
  3         60  
9 3     3   196 use Error::Pure qw(err);
  3         5  
  3         111  
10 3     3   178549 use GraphViz;
  0            
  0            
11             use PYX::Parser;
12              
13             # Version.
14             our $VERSION = 0.04;
15              
16             # Constructor.
17             sub new {
18             my ($class, @params) = @_;
19              
20             # Object.
21             my $self = bless {}, $class;
22              
23             # Colors.
24             $self->{'colors'} = {
25             'a' => 'blue',
26             'blockquote' => 'orange',
27             'br' => 'orange',
28             'div' => 'green',
29             'form' => 'yellow',
30             'html' => 'black',
31             'img' => 'violet',
32             'input' => 'yellow',
33             'option' => 'yellow',
34             'p' => 'orange',
35             'select' => 'yellow',
36             'table' => 'red',
37             'td' => 'red',
38             'textarea' => 'yellow',
39             'tr' => 'red',
40             '*' => 'grey',
41             };
42              
43             # Layout.
44             $self->{'layout'} = 'neato';
45              
46             # Height and width.
47             $self->{'height'} = 10;
48             $self->{'width'} = 10;
49              
50             # Node height.
51             $self->{'node_height'} = 0.3;
52              
53             # Output handler.
54             $self->{'output_handler'} = \*STDOUT;
55              
56             # Process params.
57             set_params($self, @params);
58              
59             # GraphViz object.
60             $self->{'_g'} = GraphViz->new(
61             'layout' => $self->{'layout'},
62             'overlap' => 'scale',
63             'height' => $self->{'height'},
64             'width' => $self->{'width'},
65             );
66              
67             # Check to '*' color.
68             if (! exists $self->{'colors'}->{'*'}) {
69             err "Bad color define for '*' elements.";
70             }
71              
72             # PYX::Parser object.
73             $self->{'_pyx_parser'} = PYX::Parser->new(
74             'callbacks' => {
75             'end_element' => \&_end_element,
76             'final' => \&_final,
77             'start_element' => \&_start_element,
78             },
79             'non_parser_options' => {
80             'colors' => $self->{'colors'},
81             'g' => $self->{'_g'},
82             'node_height' => $self->{'node_height'},
83             'num' => 0,
84             'stack' => [],
85             },
86             'output_handler' => $self->{'output_handler'},
87             );
88              
89             # Object.
90             return $self;
91             }
92              
93             # Parse pyx text or array of pyx text.
94             sub parse {
95             my ($self, $pyx, $out) = @_;
96             $self->{'_pyx_parser'}->parse($pyx, $out);
97             return;
98             }
99              
100             # Parse file with pyx text.
101             sub parse_file {
102             my ($self, $file, $out) = @_;
103             $self->{'_pyx_parser'}->parse_file($file, $out);
104             return;
105             }
106              
107             # Parse from handler.
108             sub parse_handler {
109             my ($self, $input_file_handler, $out) = @_;
110             $self->{'_pyx_parser'}->parse_handler($input_file_handler, $out);
111             return;
112             }
113              
114             # Process element.
115             sub _start_element {
116             my ($pyx_parser_obj, $elem) = @_;
117             $pyx_parser_obj->{'non_parser_options'}->{'num'}++;
118             my $num = $pyx_parser_obj->{'non_parser_options'}->{'num'};
119             my $colors = $pyx_parser_obj->{'non_parser_options'}->{'colors'};
120             my $color;
121             if (exists $colors->{$elem}) {
122             $color = $colors->{$elem};
123             } else {
124             $color = $colors->{'*'};
125             }
126             my $g = $pyx_parser_obj->{'non_parser_options'}->{'g'};
127             my $node_height = $pyx_parser_obj->{'non_parser_options'}
128             ->{'node_height'};
129             $g->add_node($num,
130             'color' => $color,
131             'height' => $node_height,
132             'shape' => 'point'
133             );
134             my $stack_ar = $pyx_parser_obj->{'non_parser_options'}->{'stack'};
135             if (@{$stack_ar}) {
136             $g->add_edge(
137             $num=> $stack_ar->[-1]->[1],
138             'arrowhead' => 'none',
139             'weight' => 2,
140             );
141             }
142             push @{$stack_ar}, [$elem, $num];
143             return;
144             }
145              
146             # Process elements.
147             sub _end_element {
148             my ($pyx_parser_obj, $elem) = @_;
149             my $stack_ar = $pyx_parser_obj->{'non_parser_options'}->{'stack'};
150             if ($stack_ar->[-1]->[0] eq $elem) {
151             pop @{$stack_ar};
152             }
153             return;
154             }
155              
156             # Final.
157             sub _final {
158             my $pyx_parser_obj = shift;
159             my $g = $pyx_parser_obj->{'non_parser_options'}->{'g'};
160             my $out = $pyx_parser_obj->{'output_handler'};
161             $g->as_png($out);
162             return;
163             }
164              
165             1;
166              
167             __END__