File Coverage

blib/lib/WWW/Twilio/TwiML.pm
Criterion Covered Total %
statement 148 149 99.3
branch 35 40 87.5
condition 11 15 73.3
subroutine 24 25 96.0
pod 8 13 61.5
total 226 242 93.3


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