File Coverage

blib/lib/Tree/Visualize/ASCII/BoundingBox.pm
Criterion Covered Total %
statement 99 100 99.0
branch 19 28 67.8
condition 9 30 30.0
subroutine 18 18 100.0
pod 14 14 100.0
total 159 190 83.6


line stmt bran cond sub pod time code
1              
2             package Tree::Visualize::ASCII::BoundingBox;
3              
4 5     5   25654 use strict;
  5         11  
  5         158  
5 5     5   24 use warnings;
  5         9  
  5         112  
6              
7 5     5   441 use Tree::Visualize::Exceptions;
  5         9  
  5         7541  
8              
9             our $VERSION = '0.01';
10              
11             ## constructor
12              
13             sub new {
14 101     101 1 687 my ($_class, $string) = @_;
15 101   33     331 my $class = ref($_class) || $_class;
16 101         418 my $box = {
17             string => [ split(/\n/, $string) ]
18             };
19 101         250 bless($box, $class);
20 101         398 return $box;
21             }
22              
23             ## accessors
24              
25             sub height {
26 164     164 1 783 my ($self) = @_;
27 164         132 scalar @{$self->{string}};
  164         431  
28             }
29              
30             sub width {
31 644     644 1 640 my ($self) = @_;
32 644 50       1151 defined($self->{string}->[0]) || return 0;
33 644         1430 length($self->{string}->[0]);
34             }
35              
36             sub getLinesAsArray {
37 160     160 1 178 my ($self) = @_;
38 160         142 return @{$self->{string}};
  160         497  
39             }
40              
41             sub getAsString {
42 15     15 1 332 my ($self) = @_;
43 15         20 join "\n" => @{$self->{string}};
  15         140  
44             }
45              
46             sub getFirstConnectionPointIndex {
47 14     14 1 15 my ($self) = @_;
48 14         57 my ($space, $top_line_of_box) = ($self->{string}->[0] =~ /(\s*)(\S*)/);
49 14         49 return length($space) + int(length($top_line_of_box) / 2);
50             }
51              
52             ## mutators
53              
54             sub flipVertical {
55 1     1 1 3 my ($self) = @_;
56 1         2 $self->{string} = [ reverse(@{$self->{string}}) ];
  1         4  
57 1         3 $self;
58             }
59              
60             sub flipHorizontal {
61 2     2 1 3 my ($self) = @_;
62 2         3 $self->{string} = [ map { join "" => reverse(split // => $_) } @{$self->{string}} ];
  6         34  
  2         6  
63 2         7 $self;
64             }
65              
66             sub padLeft {
67 13     13 1 20 my ($self, $padding) = @_;
68 13 50       47 ($padding =~ /^\s*$/)
69             || throw Tree::Visualize::InsufficientArguments "padding can not contain newlines and only be spaces ($padding)";
70 13         16 $self->{string} = [ map { ($padding . $_) } @{$self->{string}} ];
  39         78  
  13         24  
71 13         46 $self;
72             }
73              
74             sub padRight {
75 27     27 1 331 my ($self, $padding) = @_;
76 27 50       101 ($padding =~ /^\s*$/)
77             || throw Tree::Visualize::InsufficientArguments "padding can not contain newlines and only be spaces ($padding)";
78 27         26 $self->{string} = [ map { ($_ . $padding) } @{$self->{string}} ];
  130         225  
  27         46  
79 27         111 $self;
80             }
81              
82             sub pasteRight {
83 37     37 1 372 my ($self, $right) = @_;
84 37 50 33     282 (defined($right) && ref($right) && UNIVERSAL::isa($right, "Tree::Visualize::ASCII::BoundingBox"))
      33        
85             || throw Tree::Visualize::InsufficientArguments "right argument must be a Tree::Visualize::ASCII::BoundingBox ($right)";
86             # split the left
87 37         69 my @left = $self->getLinesAsArray();
88             # and the right
89 37         76 my @right = $right->getLinesAsArray();
90            
91             # figure out which has the most lines
92 37 100       74 my $num_lines = ($self->height() < $right->height()) ? $right->height() : $self->height();
93            
94             # get the widths of the first item in the list
95 37         75 my $first_left_width = $self->width();
96 37         58 my $first_right_width = $right->width();
97            
98 37         37 my @new_string;
99 37         68 foreach my $line_num (0 .. $num_lines - 1) {
100 185         348 push @new_string => (
101             _normalizeLine($left[$line_num], $first_left_width) .
102             _normalizeLine($right[$line_num], $first_right_width)
103             );
104             }
105             # and now paste it into the new string
106 37         62 $self->{string} = \@new_string;
107 37         143 $self;
108             }
109              
110             sub pasteLeft {
111 8     8 1 12 my ($self, $left) = @_;
112 8 50 33     66 (defined($left) && ref($left) && UNIVERSAL::isa($left, "Tree::Visualize::ASCII::BoundingBox"))
      33        
113             || throw Tree::Visualize::InsufficientArguments "left argument must be a Tree::Visualize::ASCII::BoundingBox ($left)";
114             # split the left
115 8         16 my @left = $left->getLinesAsArray();
116             # and the right
117 8         19 my @right = $self->getLinesAsArray();
118            
119             # figure out which has the most lines
120 8 50       19 my $num_lines = ($self->height() < $left->height()) ? $left->height() : $self->height();
121            
122             # get the widths of the first item in the list
123 8         24 my $first_left_width = $left->width();
124 8         13 my $first_right_width = $self->width();
125            
126 8         11 my @new_string;
127 8         18 foreach my $line_num (0 .. $num_lines - 1) {
128 24         43 push @new_string => (
129             _normalizeLine($left[$line_num], $first_left_width) .
130             _normalizeLine($right[$line_num], $first_right_width)
131             );
132             }
133             # and now paste it into the new string
134 8         15 $self->{string} = \@new_string;
135 8         32 $self;
136             }
137              
138             sub pasteTop {
139 18     18 1 26 my ($self, $top) = @_;
140 18 50 33     150 (defined($top) && ref($top) && UNIVERSAL::isa($top, "Tree::Visualize::ASCII::BoundingBox"))
      33        
141             || throw Tree::Visualize::InsufficientArguments "top argument must be a Tree::Visualize::ASCII::BoundingBox ($top)";
142 18 100       35 if ($top->width() < $self->width()) {
143 1         2 unshift @{$self->{string}} => map { _normalizeLine($_, $self->width()) } $top->getLinesAsArray();
  1         4  
  3         6  
144             }
145             else {
146 17         30 $self->{string} = [ $top->getLinesAsArray(), map { _normalizeLine($_, $top->width()) } @{$self->{string}} ];
  106         167  
  17         32  
147             }
148 18         130 $self;
149             }
150              
151             sub pasteBottom {
152 37     37 1 46 my ($self, $bottom) = @_;
153 37 50 33     256 (defined($bottom) && ref($bottom) && UNIVERSAL::isa($bottom, "Tree::Visualize::ASCII::BoundingBox"))
      33        
154             || throw Tree::Visualize::InsufficientArguments "bottom argument must be a Tree::Visualize::ASCII::BoundingBox ($bottom)";
155 37 100       61 if ($bottom->width() < $self->width()) {
156 21         18 push @{$self->{string}} => map { _normalizeLine($_, $self->width()) } $bottom->getLinesAsArray();
  21         45  
  69         108  
157             }
158             else {
159 16         13 $self->{string} = [ map { _normalizeLine($_, $bottom->width()) } @{$self->{string}}, $bottom->getLinesAsArray() ];
  121         253  
  16         37  
160             }
161 37         121 $self;
162             }
163              
164             ## private helper functions
165              
166             sub _normalizeLine {
167 717     717   808 my ($line, $width) = @_;
168 717 100       1640 unless ($line) {
    100          
    50          
169 63         84 $line = (" " x $width);
170             }
171             elsif ($width > length($line)) {
172 96         159 $line = $line . (" " x ($width - length($line)));
173             }
174             elsif ($width < length($line)) {
175             # strip any trailing spaces that are larger
176             # then the width of the first line of the
177             # left node
178 0   0     0 chop($line) while ($line =~ /\s$/o && $width < length($line));
179             }
180 717         1598 return $line;
181             }
182              
183             1;
184              
185             __END__