File Coverage

blib/lib/Markup/TreeNode.pm
Criterion Covered Total %
statement 18 139 12.9
branch 2 46 4.3
condition 3 17 17.6
subroutine 4 16 25.0
pod 11 13 84.6
total 38 231 16.4


line stmt bran cond sub pod time code
1             package Markup::TreeNode;
2             $VERSION = '1.1.6';
3            
4             ####################################################
5             # This module is protected under the terms of the
6             # GNU GPL. Please see
7             # http://www.opensource.org/licenses/gpl-license.php
8             # for more information.
9             ####################################################
10            
11 1     1   52544 use strict;
  1         3  
  1         40  
12 1     1   7 use Carp;
  1         1  
  1         2104  
13            
14             require Exporter;
15            
16             our @ISA = qw(Exporter);
17             our $empty = '(empty)';
18            
19             sub new {
20 1     1 0 918 my $invocant = shift();
21 1   33     10 my $class = ref($invocant) || $invocant;
22 1         14 $class = bless {
23             element_type => 'tag',
24             tagname => '',
25             attr => { },
26             level => 0,
27             parent => $empty,
28             child_num => 0,
29             children => [ ],
30             text => ''
31             }, $class;
32 1         7 $class->init (@_);
33 1         4 return $class;
34             }
35            
36             sub init {
37 1     1 0 2 my $self = shift();
38 1         5 my %args = @_;
39            
40 1         4 foreach (keys %args) {
41             # enforce integrity
42 2 50 33     7 if ($_ eq 'parent' && $args{$_} ne $empty) {
43 0         0 $self->attach_parent($args{$_});
44 0         0 next;
45             }
46            
47             # enforce integrity
48 2 0 50     6 if ($_ eq 'children' && scalar(@{$args{$_}})) {
  0         0  
49 0         0 $self->attach_children($args{$_});
50 0         0 next;
51             }
52            
53 2 50       13 if (exists $self->{$_}) {
54 2         8 $self->{$_} = $args{$_};
55             }
56             else {
57 0           croak ("unrecognized node option $_");
58             }
59             }
60             }
61            
62             sub attach_parent {
63 0     0 1   my ($self, $parent) = @_;
64            
65 0           $self->{'parent'} = $parent;
66             # if setting parent, add us to [bottom of] parent children
67 0 0         my $child_count = scalar(@{$self->{'parent'}->{'children'} || []});
  0            
68 0           $self->{'parent'}->{'children'}->[$child_count] = $self;
69 0           $self->{'child_num'} = $child_count;
70            
71 0           return $self;
72             }
73            
74             sub attach_child {
75 0     0 1   my ($self, $child) = @_;
76 0           my $child_count = scalar(@{ $self->{'children'} });
  0            
77            
78 0           $self->{'children'}->[$child_count] = $child;
79             # if setting child, add us as parent of child
80 0           $child->{'parent'} = $self;
81 0           $child->{'child_num'} = $child_count;
82            
83 0           return $self;
84             }
85            
86             sub attach_child_before {
87 0     0 1   my ($self, $child) = @_;
88 0           my $child_count = scalar(@{ $self->{'children'} });
  0            
89            
90 0           for (my $i = 0; $i < $child_count; $i++) {
91 0           $self->{'children'}->[($i + 1)] = $self->{'children'}->[$i];
92 0           $self->{'children'}->[($i + 1)]->{'child_num'}++;
93             }
94            
95 0           $self->{'children'}->[0] = $child;
96             # if setting child, add us as parent of child
97 0           $child->{'parent'} = $self;
98 0           $child->{'child_num'} = 0;
99            
100 0           return $self;
101             }
102            
103            
104             sub attach_children {
105 0     0 1   my ($self, $childref) = @_;
106 0           my $cnt = 0;
107            
108 0           $self->{'children'} = $childref;
109             # if setting children, add us as parent of all children
110 0           foreach (@{ $self->{'children'} }) {
  0            
111 0 0         if (!UNIVERSAL::isa($_, 'Markup::TreeNode')) {
112 0           croak ("$_ is not a recognized child");
113             }
114            
115 0           $_->{'parent'} = $self;
116 0           $_->{'child_num'} = $cnt++;
117             }
118            
119 0           return $self;
120             }
121            
122             sub get_text {
123 0     0 1   my $self = shift();
124            
125 0 0         if ($self->{'element_type'} eq '-->text') { return $self->{'text'}; }
  0            
126            
127 0           my $next_node = $self->next_node();
128            
129 0 0         return (($next_node->{'element_type'} eq '-->text') ? $next_node->{'text'} : undef);
130             }
131            
132             sub next_node {
133 0     0 1   my $self = shift();
134            
135 0 0         if (scalar(@{ $self->{'children'} })) {
  0            
136 0           return $self->{'children'}->[0];
137             }
138            
139             my $recurse = sub {
140 0     0     my ($me, $myself) = @_;
141 0 0         if ($myself->{'parent'} ne $empty) {
142 0 0         if ($myself->{'child_num'} < (scalar(@{ $myself->{'parent'}->{'children'} || [] }) - 1)) {
  0 0          
143 0           return ($myself->{'parent'}->{'children'}->[($myself->{'child_num'} + 1)]);
144             }
145            
146 0           return ($me->($me, $myself->{'parent'}));
147             }
148            
149 0           return undef;
150 0           };
151            
152 0           return ($recurse->($recurse, $self));
153             }
154            
155             sub previous_node {
156 0     0 1   my $self = shift();
157            
158 0 0         if ($self->{'parent'} ne $empty) {
159 0 0 0       if (($self->{'child_num'} > 0) && (scalar(@{ $self->{'parent'}->{'children'} }) >= 1)) {
  0            
160 0           my $ret = $self->{'parent'}->{'children'}->[($self->{'child_num'} - 1)];
161 0 0         while (scalar(@{$ret->{'children'} || []})) {
  0            
162 0           $ret = $ret->{'children'}->[(scalar(@{$ret->{'children'}}) - 1)];
  0            
163             }
164 0           return ($ret);
165             }
166            
167 0           return ($self->{'parent'});
168             }
169            
170 0           return undef;
171             }
172            
173             sub drop {
174 0     0 1   my $self = shift();
175 0           my $parent = $self->{'parent'};
176            
177 0 0         return ($self) if ($parent eq $empty);
178            
179 0           splice @{ $parent->{'children'} }, $self->{'child_num'}--, 1;
  0            
180            
181 0 0 0       if ($self->{'child_num'} < (scalar(@{ $parent->{'children'} || [] })) && $self->{'child_num'} > 0) {
  0 0          
182 0           for (my $i = $self->{'child_num'}; $i < scalar(@{ $parent->{'children'} }); $i++) {
  0            
183 0           $parent->{'children'}->[$i]->{'child_num'} = $i;
184             }
185             }
186            
187 0           $self->{'parent'} = $empty;
188            
189 0           return ($self);
190             }
191            
192             sub replace {
193 0     0 1   my ($self, $node) = @_;
194            
195 0 0         if (!UNIVERSAL::isa($node, 'Markup::TreeNode')) {
196 0           croak ("Node is not a Markup::TreeNode");
197             }
198            
199 0           $self->insert($node, 'after');
200 0           return ($self->drop());
201             }
202            
203             sub insert {
204 0     0 1   my ($self, $node, $position) = @_;
205 0 0         $position = 'after' if (!$position);
206 0           my $child_num;
207            
208 0 0 0       if (($position ne 'after') && ($position ne 'before')) {
209 0           croak ("Unknown position '$position'");
210             }
211            
212 0 0         if (!UNIVERSAL::isa($node, 'Markup::TreeNode')) {
213 0           croak ("Node is not a Markup::TreeNode");
214             }
215            
216 0           $child_num = $self->{'child_num'} + ($position eq 'after'); # yes, I know what that means :)
217 0 0         $child_num = 0 if ($child_num < 0);
218            
219 0 0         if ($self->{'parent'} eq $empty) {
220 0           return ($self->attach_child($node));
221             }
222            
223 0           for ($self->{'parent'}->{'children'}) {
224 0           my $oglen = scalar(@{ $_ });
  0            
225 0           for (my $i = $oglen; $i >= $child_num; $i--) {
226 0           $_->[($i + 1)] = $_->[$i];
227 0           $_->[($i + 1)]->{'child_num'}++;
228             }
229            
230 0           splice (@{$_}, ++$oglen);
  0            
231            
232 0           $_->[$child_num] = $node;
233 0           $_->[$child_num]->{'parent'} = $self->{'parent'};
234 0           $_->[$child_num]->{'child_num'} = $child_num;
235 0           return ($_->[$child_num]);
236             }
237             }
238            
239             sub copy_of {
240 0     0 1   my $self = shift();
241 0           my ($newbie => %options); # if you don't know you betta' axe somebody!
242            
243 0           foreach (keys %{ $self }) {
  0            
244 0           $options{$_} = $self->{$_};
245             }
246            
247 0           for ($self->{'children'}) {
248 0           my $a = scalar(@{$_});
  0            
249 0           for (my $i = 0; $i < $a; $i++) {
250 0           $options{'children'}->[$i] = $_->[$i]->copy_of();
251             }
252             }
253            
254 0           return ($self->new(%options));
255             }
256            
257             1;
258            
259             __END__