File Coverage

blib/lib/SignalWire/CompatXML.pm
Criterion Covered Total %
statement 147 147 100.0
branch 35 40 87.5
condition 11 15 73.3
subroutine 24 25 96.0
pod 8 13 61.5
total 225 240 93.7


line stmt bran cond sub pod time code
1             package SignalWire::CompatXML;
2              
3 4     4   269202 use 5.008001;
  4         43  
4 4     4   21 use strict;
  4         9  
  4         79  
5 4     4   17 use warnings;
  4         9  
  4         154  
6 4     4   35 use Carp 'croak';
  4         7  
  4         211  
7 4     4   23 use Scalar::Util 'blessed';
  4         16  
  4         677  
8              
9             our $VERSION = '1.0';
10             our $AUTOLOAD;
11             our $NL = "\n";
12             our $STRICT = 0;
13             our %TAGS = ();
14              
15             sub new {
16 189     189 1 25621 my $class = shift;
17 189         324 my $self = {};
18 189         345 bless $self, $class;
19              
20 189         465 $self->{_name} = '';
21 189         338 $self->{_attributes} = {};
22 189         291 $self->{_parent} = undef;
23 189         287 $self->{_content} = '';
24              
25             {
26 4     4   27 no strict 'refs';
  4         8  
  4         4491  
  189         287  
27 189         319 my %args = @_;
28 189         438 for my $arg ( keys %args ) {
29 16 50       82 if( exists $self->{"_$arg"} ) {
30 16         39 $self->$arg($args{$arg});
31             }
32             }
33             }
34              
35 189         369 return $self;
36             }
37              
38             sub name {
39 692     692 1 942 my $self = shift;
40              
41 692 100       1283 if( @_ ) {
42 139         249 $self->{_name} = shift;
43             }
44              
45 692         1571 $self->{_name};
46             }
47              
48             sub parent {
49 281     281 1 392 my $self = shift;
50              
51 281 100       521 if( @_ ) {
52 135         193 $self->{_parent} = shift;
53             }
54              
55 281         580 $self->{_parent};
56             }
57              
58             sub content {
59 241     241 1 360 my $self = shift;
60 241         391 my @args = grep { defined $_ } @_;
  65         226  
61              
62 241 100       446 if( @args ) {
63 64         99 my $arg = shift;
64              
65             ## an object
66 64 100       123 if( ref($arg) ) {
67 3         8 $arg->parent($self);
68 3         22 $self->{_content} = [ $arg ];
69 3         8 return $arg;
70             }
71              
72             ## http://www.w3.org/TR/REC-xml/#syntax
73 61         127 $arg =~ s{\&}{&}g;
74 61         110 $arg =~ s{\<}{<}g;
75 61         97 $arg =~ s{\>}{>}g;
76 61         85 $arg =~ s{\"}{"}g;
77 61         94 $arg =~ s{\'}{'}g;
78              
79 61         111 $self->{_content} = $arg;
80             }
81              
82 238         515 $self->{_content};
83             }
84              
85             sub attributes {
86 162     162 1 238 my $self = shift;
87              
88 162 100       286 if( @_ ) {
89 31         59 $self->{_attributes} = shift;
90             }
91              
92 162         402 $self->{_attributes};
93             }
94              
95             sub add_child {
96 132     132 1 191 my $self = shift;
97 132         169 my $child = shift;
98              
99 132         276 $child->parent($self);
100 132   100     545 $self->{_content} ||= [];
101 132         192 push @{$self->{_content}}, $child;
  132         290  
102              
103 132         199 return $child;
104             }
105              
106             sub root {
107 26     26 1 41 my $self = shift;
108              
109 26 100       114 if( $self->{_parent} ) {
110 17         39 return $self->{_parent}->root;
111             }
112              
113 9         33 return $self;
114             }
115              
116             sub to_string {
117 50     50 1 97 my $self = shift;
118 50   100     162 my $hdrs = shift || {};
119              
120 50         95 my @headers = ();
121 50         144 for my $hdr ( sort keys %$hdrs ) {
122 4         14 push @headers, $hdr . ': ' . $hdrs->{$hdr};
123             }
124 50 100       106 push @headers, '' if scalar(@headers);
125              
126 50         109 join($NL, @headers, $self->to_list);
127             }
128              
129             sub to_list {
130 176     176 0 269 my $self = shift;
131 176   100     429 my $sp = shift || 0;
132              
133 176         244 my @str = ();
134              
135             ## named element
136 176 100       290 if( $self->name ) {
137 131 100       218 if( my $content = $self->content ) {
138 120         276 push @str, (' ' x $sp) . $self->otag;
139              
140 120         198 my $is_str = 0;
141              
142 120 100       232 if( ref($content) eq 'ARRAY' ) {
143 61         102 for my $child ( @$content ) {
144 82 50       150 push @str, $child->to_list($sp + ($child->parent->name ? 2 : 0));
145             }
146             }
147              
148             else {
149 59         89 $is_str = 1;
150 59   50     165 $str[$#str] .= $content || '';
151             }
152              
153 120 100       233 if( $is_str ) {
154 59         118 $str[$#str] .= $self->ctag;
155             }
156             else {
157 61         125 push @str, (' ' x $sp) . $self->ctag;
158             }
159             }
160              
161             ## no content; make a tidy tag
162             else {
163 11         24 push @str, (' ' x $sp) . $self->octag;
164             }
165             }
166              
167             ## unnamed (root) element
168             else {
169 45         80 push @str, qq!!;
170              
171 45         87 my $content = $self->content;
172              
173 45         69 my $is_str = 0;
174 45 100       131 if( ref($content) eq 'ARRAY' ) {
175 44         77 for my $child ( @$content ) {
176 44 50       89 push @str, $child->to_list($sp + ($child->parent->name ? 2 : 0));
177             }
178             }
179              
180             else {
181 1         3 $is_str = 1;
182 1   50     7 $str[$#str] .= $content || '';
183             }
184              
185 45         92 push @str, '';
186             }
187              
188 176         773 return @str;
189             }
190              
191             sub otag {
192 120     120 0 216 return '<' . $_[0]->name . $_[0]->_attr_str . '>';
193             }
194              
195             sub ctag {
196 120     120 0 202 return 'name . '>';
197             }
198              
199             sub octag {
200 11     11 0 22 return '<' . $_[0]->name . $_[0]->_attr_str . ' />';
201             }
202              
203             sub _attr_str {
204 131     131   190 my $self = shift;
205 131         191 my $str = '';
206              
207 131         213 my %attr = %{ $self->attributes };
  131         204  
208              
209 131         336 for my $key ( sort keys %attr ) {
210 45   50     114 my $val = $attr{$key} || '';
211 45         79 $str .= ' ';
212 45         105 $str .= qq!$key="$val"!;
213             }
214              
215 131         425 return $str;
216             }
217              
218             sub can {
219 44     44 0 91 my $self = shift;
220 44         126 my $method = shift;
221              
222             ## NOTE: this probably breaks inheritance
223 44 100 66     121 if( $STRICT and keys %TAGS ) {
224 3 50       9 unless( exists $TAGS{$method} ) {
225 4     4   31 no strict 'refs';
  4         7  
  4         696  
226 3         5 undef *{ $method };
  3         17  
227 3         36 return;
228             }
229             }
230              
231 41         137 my $meth_ref = $self->SUPER::can($method);
232 41 50       89 return $meth_ref if $meth_ref;
233              
234             $meth_ref = sub {
235 124     124   284 my $me = shift;
236              
237 124         397 my $child = new blessed $me;
238 124         312 $child->name($method);
239              
240 124         224 for my $arg ( @_ ) {
241 75 100       160 if( ref($arg) ) {
242 25         52 $child->attributes($arg);
243             }
244             else {
245 50         93 $child->content($arg);
246             }
247             }
248              
249 124         301 $me->add_child($child);
250              
251 124         536 return $child;
252 41         187 };
253              
254 4     4   30 no strict 'refs';
  4         7  
  4         779  
255 41         77 return *{ $method } = $meth_ref;
  41         208  
256             }
257              
258             sub AUTOLOAD {
259 41     41   127 my $self = $_[0];
260              
261 41         62 my $method = $AUTOLOAD;
262 41         237 $method =~ s/^(.*):://;
263              
264 41         108 my $meth_ref = $self->can($method);
265 41 100       262 croak "Undefined subroutine $method\n"
266             unless $meth_ref;
267              
268 40         140 goto &$meth_ref;
269             }
270              
271       0     sub DESTROY { }
272              
273             1;
274             __END__