File Coverage

blib/lib/XML/Atom/Syndication/Object.pm
Criterion Covered Total %
statement 131 141 92.9
branch 52 78 66.6
condition 2 2 100.0
subroutine 29 30 96.6
pod 14 16 87.5
total 228 267 85.3


line stmt bran cond sub pod time code
1             package XML::Atom::Syndication::Object;
2 21     21   110 use strict;
  21         29  
  21         634  
3              
4 21     21   78 use base qw( Class::ErrorHandler );
  21         50  
  21         9722  
5              
6 21     21   4567 use constant XMLNS => 'http://www.w3.org/XML/1998/namespace';
  21         35  
  21         1605  
7              
8 21     21   92 use Carp;
  21         26  
  21         1477  
9 21     21   8495 use XML::Elemental;
  21         150210  
  21         3921  
10 21     21   13381 use XML::Elemental::Util qw( process_name );
  21         3962  
  21         3903  
11 21     21   9244 use XML::Atom::Syndication::Util qw( nodelist utf8_off );
  21         29  
  21         1822  
12 21     21   6587 use XML::Atom::Syndication::Writer;
  21         57  
  21         9120  
13              
14             sub new {
15 330     330 1 32962 my $class = shift;
16 330         527 my $atom = bless {}, $class;
17 330 50       1008 $atom->init(@_) or return $class->error($atom->errstr);
18 330         735 $atom;
19             }
20              
21             sub init {
22 123     123 0 143 my $atom = shift;
23 123 50       371 my %param = @_ == 1 ? (Elem => $_[0]) : @_;
24 123         333 $atom->set_ns(\%param);
25 123 100       307 unless ($atom->{elem} = $param{Elem}) {
26 4 50       15 unless ($atom->element_name) {
27             $atom->{name} = $param{Name}
28 0 0       0 or croak('An Elem or Name parameter is required.');
29             }
30 4         13 $atom->{elem} = XML::Elemental::Element->new;
31 4         34 $atom->{elem}->name('{' . $atom->ns . '}' . $atom->element_name);
32             } else {
33 119 100       295 unless ($atom->element_name) {
34 70         189 my ($ns, $name) = process_name($atom->{elem}->name);
35 70         1028 $atom->{name} = $name;
36             }
37             }
38 123         251 $atom;
39             }
40              
41 504     504 1 2165 sub ns { $_[0]->{ns} }
42 389     389 1 828 sub elem { $_[0]->{elem} }
43 70     70 1 180 sub element_name { $_[0]->{name} }
44              
45             sub remove {
46 1     1 1 2 my $atom = shift;
47 1         2 _remove($atom->elem, @_);
48             }
49              
50             sub as_xml {
51 0     0 1 0 my $w = XML::Atom::Syndication::Writer->new;
52 0         0 $w->set_prefix('', $_[0]->ns);
53 0         0 $w->as_xml($_[0]->elem, 1);
54             }
55              
56             #--- Atom common attributes
57              
58             sub base {
59 1 50   1 1 40 @_ > 1
60             ? $_[0]->set_attribute(XMLNS, 'base', @_[1 .. $#_])
61             : $_[0]->get_attribute(XMLNS, 'base');
62             }
63              
64             sub lang {
65 1 50   1 1 13 @_ > 1
66             ? $_[0]->set_attribute(XMLNS, 'lang', @_[1 .. $#_])
67             : $_[0]->get_attribute(XMLNS, 'lang');
68             }
69              
70             #--- accessors
71              
72             sub mk_accessors {
73 346     346 1 398 my $class = shift;
74 346         283 my $type = shift;
75 21     21   117 no strict 'refs';
  21         34  
  21         14712  
76 346         399 foreach my $e (@_) {
77 564         704 my $accessor = join '::', $class, $e;
78 564 100       969 if ($type eq 'element') {
    100          
79             *$accessor = sub {
80 37 100   37   8517 @_ > 1
81             ? $_[0]->set_element($_[0]->ns, $e, @_[1 .. $#_])
82             : $_[0]->get_element($_[0]->ns, $e);
83 229         1241 };
84             } elsif ($type eq 'attribute') {
85             *$accessor = sub {
86 84 100   84   13497 @_ > 1
87             ? $_[0]->set_attribute($_[0]->ns, $e, @_[1 .. $#_])
88             : $_[0]->get_attribute($_[0]->ns, $e);
89 77         495 };
90             } else { # type is the class to instaniate
91             *$accessor = sub {
92 125 100   125   7454 @_ > 1
93             ? $_[0]->set_element($_[0]->ns, $e, @_[1 .. $#_])
94             : $_[0]->get_class($type, $_[0]->ns, $e);
95 258         1543 };
96             }
97             }
98             }
99              
100             sub get_element {
101 33     33 1 50 my ($atom, $ns, $name) = @_;
102             my $ns_uri =
103 33 50       129 ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
104 33         89 my @nodes = nodelist($atom, $ns_uri, $name);
105 33 50       77 return unless @nodes;
106             wantarray
107 33 50       110 ? map { utf8_off($_->text_content) } @nodes
  0         0  
108             : utf8_off($nodes[0]->text_content);
109             }
110              
111             sub get_class {
112 116     116 1 194 my ($atom, $class, $ns, $name) = @_;
113             my $ns_uri =
114 116 50       247 ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
115 116         325 my @nodes = nodelist($atom, $ns_uri, $name);
116 116 50       244 return unless @nodes;
117 116         6355 eval "require $class";
118 116 50       418 croak("Error creating accessor {$ns}$name: $@") if $@;
119             wantarray
120 116 100       453 ? map { $class->new(Elem => $_, Namespace => $ns_uri) } @nodes
  20         50  
121             : $class->new(Elem => $nodes[0], Namespace => $ns_uri);
122             }
123              
124             sub get_attribute {
125 78     78 1 90 my $atom = shift;
126 78         73 my ($val);
127 78 50       258 if (@_ == 1) {
    50          
128 0         0 my ($attr) = @_;
129 0         0 $val = $atom->{elem}->attributes->{"{}$attr"};
130             } elsif (@_ == 2) {
131 78         108 my ($ns, $attr) = @_;
132 78 100       171 $ns = '' if $atom->ns eq $ns;
133 78         219 $val = $atom->{elem}->attributes->{"{$ns}$attr"};
134             }
135 78         586 utf8_off($val);
136             }
137              
138             sub set_element {
139 16     16 1 18 my $atom = shift;
140 16         33 my ($ns, $name, $val, $attr, $add) = @_;
141 16 100       44 $add = $attr if ref $val;
142             my $ns_uri =
143 16 50       39 ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
144 16 100       35 unless ($add) {
145 10         31 my @nodes = nodelist($atom, $ns_uri, $name);
146 10         22 foreach my $node (@nodes) {
147 0 0       0 _remove($node) || return $atom->error($node->errstr);
148             }
149             }
150 16 100       44 if (my $class = ref $val) {
    50          
151 7 100       82 $val = $val->elem if $class =~ /^XML::Atom::Syndication::/;
152 7         17 $val->parent($atom->elem);
153 7         28 push @{$atom->elem->contents}, $val;
  7         15  
154             } elsif (defined $val) {
155 9         27 my $elem = XML::Elemental::Element->new;
156 9         84 $elem->name("{$ns_uri}$name");
157 9 50       44 $elem->attributes($attr) if $attr;
158 9         17 $elem->parent($atom->elem);
159 9         32 push @{$atom->elem->contents}, $elem;
  9         17  
160 21     21   11729 use XML::Elemental::Characters;
  21         16895  
  21         8119  
161 9         73 my $chars = XML::Elemental::Characters->new;
162 9         48 $chars->data($val);
163 9         54 $chars->parent($elem);
164 9         29 push @{$elem->contents}, $chars;
  9         23  
165             }
166 16         130 $val;
167             }
168              
169             sub set_attribute {
170 8     8 1 11 my $atom = shift;
171 8 50       31 if (@_ == 2) {
    50          
172 0         0 my ($attr, $val) = @_;
173 0         0 $atom->{elem}->attributes->{"{}$attr"} = $val;
174             } elsif (@_ == 3) {
175 8         14 my ($ns, $attr, $val) = @_;
176             my $ns_uri =
177 8 50       17 ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
178 8 50       12 $ns_uri = '' if $atom->ns eq $ns_uri;
179 8         28 $atom->{elem}->attributes->{"{$ns_uri}$attr"} = $val;
180             }
181             }
182              
183             #--- utility
184              
185             sub _remove {
186 1     1   1 my $elem = shift;
187 1 50       4 my $parent = $elem->parent
188             or die 'Element parent is not defined';
189 1         6 my @contents = grep { $elem ne $_ } @{$parent->contents};
  7         14  
  1         2  
190 1         3 $parent->contents(\@contents);
191 1         5 $elem->parent(undef);
192 1         4 1;
193             }
194              
195             our %NS_MAP = (
196             '0.3' => 'http://purl.org/atom/ns#',
197             '1.0' => 'http://www.w3.org/2005/Atom',
198             );
199             our %NS_VERSION = reverse %NS_MAP;
200              
201             sub set_ns {
202 330     330 0 304 my $atom = shift;
203 330         271 my $param = shift;
204 330 100       663 if (my $ns = delete $param->{Namespace}) {
205 202         426 $atom->{ns} = $ns;
206 202         412 $atom->{version} = $NS_VERSION{$ns};
207             } else {
208 128   100     537 my $version = delete $param->{Version} || '1.0';
209 128 100       466 $version = '1.0' if $version == 1;
210 128 50       401 my $ns = $NS_MAP{$version}
211             or return $atom->error("Unknown version: $version");
212 128         340 $atom->{ns} = $ns;
213 128         337 $atom->{version} = $version;
214             }
215             }
216              
217             1;
218              
219             __END__