File Coverage

blib/lib/XML/Atom/Syndication/Object.pm
Criterion Covered Total %
statement 134 141 95.0
branch 52 78 66.6
condition 2 2 100.0
subroutine 30 30 100.0
pod 14 16 87.5
total 232 267 86.8


line stmt bran cond sub pod time code
1             package XML::Atom::Syndication::Object;
2 22     22   142 use strict;
  22         40  
  22         953  
3              
4 22     22   192 use base qw( Class::ErrorHandler );
  22         47  
  22         31138  
5              
6 22     22   26243 use constant XMLNS => 'http://www.w3.org/XML/1998/namespace';
  22         51  
  22         3565  
7              
8 22     22   137 use Carp;
  22         77  
  22         2163  
9 22     22   27295 use XML::Elemental 2.01;
  22         334399  
  22         954  
10 22     22   34359 use XML::Elemental::Util qw( process_name );
  22         7372  
  22         1896  
11 22     22   16845 use XML::Atom::Syndication::Util qw( nodelist utf8_off );
  22         70  
  22         1646  
12 22     22   14407 use XML::Atom::Syndication::Writer;
  22         203  
  22         20570  
13              
14             sub new {
15 339     339 1 72424 my $class = shift;
16 339         1069 my $atom = bless {}, $class;
17 339 50       1801 $atom->init(@_) or return $class->error($atom->errstr);
18 339         1587 $atom;
19             }
20              
21             sub init {
22 126     126 0 229 my $atom = shift;
23 126 50       663 my %param = @_ == 1 ? (Elem => $_[0]) : @_;
24 126         505 $atom->set_ns(\%param);
25 126 100       566 unless ($atom->{elem} = $param{Elem}) {
26 5 50       22 unless ($atom->element_name) {
27 0 0       0 $atom->{name} = $param{Name}
28             or croak('An Elem or Name parameter is required.');
29             }
30 5         18 $atom->{elem} = XML::Elemental::Element->new;
31 5         61 $atom->{elem}->name('{' . $atom->ns . '}' . $atom->element_name);
32             } else {
33 121 100       642 unless ($atom->element_name) {
34 71         400 my ($ns, $name) = process_name($atom->{elem}->name);
35 71         1522 $atom->{name} = $name;
36             }
37             }
38 126         559 $atom;
39             }
40              
41 524     524 1 3601 sub ns { $_[0]->{ns} }
42 413     413 1 1702 sub elem { $_[0]->{elem} }
43 71     71 1 348 sub element_name { $_[0]->{name} }
44              
45             sub remove {
46 1     1 1 3 my $atom = shift;
47 1         4 _remove($atom->elem, @_);
48             }
49              
50             sub as_xml {
51 6     6 1 2418 my $w = XML::Atom::Syndication::Writer->new;
52 6         26 $w->set_prefix('', $_[0]->ns);
53 6         27 $w->as_xml($_[0]->elem, 1);
54             }
55              
56             #--- Atom common attributes
57              
58             sub base {
59 1 50   1 1 17 @_ > 1
60             ? $_[0]->set_attribute(XMLNS, 'base', @_[1 .. $#_])
61             : $_[0]->get_attribute(XMLNS, 'base');
62             }
63              
64             sub lang {
65 1 50   1 1 17 @_ > 1
66             ? $_[0]->set_attribute(XMLNS, 'lang', @_[1 .. $#_])
67             : $_[0]->get_attribute(XMLNS, 'lang');
68             }
69              
70             #--- accessors
71              
72             sub mk_accessors {
73 367     367 1 930 my $class = shift;
74 367         565 my $type = shift;
75 22     22   339 no strict 'refs';
  22         46  
  22         27102  
76 367         891 foreach my $e (@_) {
77 596         1695 my $accessor = join '::', $class, $e;
78 596 100       1838 if ($type eq 'element') {
    100          
79             *$accessor = sub {
80 37 100   37   14073 @_ > 1
81             ? $_[0]->set_element($_[0]->ns, $e, @_[1 .. $#_])
82             : $_[0]->get_element($_[0]->ns, $e);
83 242         2744 };
84             } elsif ($type eq 'attribute') {
85             *$accessor = sub {
86 85 100   85   27470 @_ > 1
87             ? $_[0]->set_attribute($_[0]->ns, $e, @_[1 .. $#_])
88             : $_[0]->get_attribute($_[0]->ns, $e);
89 81         10715 };
90             } else { # type is the class to instaniate
91             *$accessor = sub {
92 129 100   129   13634 @_ > 1
93             ? $_[0]->set_element($_[0]->ns, $e, @_[1 .. $#_])
94             : $_[0]->get_class($type, $_[0]->ns, $e);
95 273         3051 };
96             }
97             }
98             }
99              
100             sub get_element {
101 33     33 1 71 my ($atom, $ns, $name) = @_;
102 33 50       102 my $ns_uri =
103             ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
104 33         134 my @nodes = nodelist($atom, $ns_uri, $name);
105 33 50       104 return unless @nodes;
106             wantarray
107 33 50       225 ? map { utf8_off($_->text_content) } @nodes
  0         0  
108             : utf8_off($nodes[0]->text_content);
109             }
110              
111             sub get_class {
112 119     119 1 441 my ($atom, $class, $ns, $name) = @_;
113 119 50       467 my $ns_uri =
114             ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
115 119         614 my @nodes = nodelist($atom, $ns_uri, $name);
116 119 50       485 return unless @nodes;
117 119         14893 eval "require $class";
118 119 50       645 croak("Error creating accessor {$ns}$name: $@") if $@;
119             wantarray
120 119 100       1127 ? map { $class->new(Elem => $_, Namespace => $ns_uri) } @nodes
  20         116  
121             : $class->new(Elem => $nodes[0], Namespace => $ns_uri);
122             }
123              
124             sub get_attribute {
125 78     78 1 143 my $atom = shift;
126 78         132 my ($val);
127 78 50       534 if (@_ == 1) {
    50          
128 0         0 my ($attr) = @_;
129 0         0 $val = $atom->{elem}->attributes->{"{}$attr"};
130             } elsif (@_ == 2) {
131 78         172 my ($ns, $attr) = @_;
132 78 100       190 $ns = '' if $atom->ns eq $ns;
133 78         364 $val = $atom->{elem}->attributes->{"{$ns}$attr"};
134             }
135 78         1192 utf8_off($val);
136             }
137              
138             sub set_element {
139 17     17 1 29 my $atom = shift;
140 17         36 my ($ns, $name, $val, $attr, $add) = @_;
141 17 100       48 $add = $attr if ref $val;
142 17 50       47 my $ns_uri =
143             ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
144 17 100       46 unless ($add) {
145 11         45 my @nodes = nodelist($atom, $ns_uri, $name);
146 11         114 foreach my $node (@nodes) {
147 0 0       0 _remove($node) || return $atom->error($node->errstr);
148             }
149             }
150 17 100       67 if (my $class = ref $val) {
    50          
151 8 100       54 $val = $val->elem if $class =~ /^XML::Atom::Syndication::/;
152 8         20 $val->parent($atom->elem);
153 8         46 push @{$atom->elem->contents}, $val;
  8         19  
154             } elsif (defined $val) {
155 9         31 my $elem = XML::Elemental::Element->new;
156 9         181 $elem->name("{$ns_uri}$name");
157 9 50       66 $elem->attributes($attr) if $attr;
158 9         22 $elem->parent($atom->elem);
159 9         48 push @{$atom->elem->contents}, $elem;
  9         22  
160 22     22   45616 use XML::Elemental::Characters;
  22         49248  
  22         21164  
161 9         91 my $chars = XML::Elemental::Characters->new;
162 9         65 $chars->data($val);
163 9         73 $chars->parent($elem);
164 9         43 push @{$elem->contents}, $chars;
  9         28  
165             }
166 17         180 $val;
167             }
168              
169             sub set_attribute {
170 9     9 1 14 my $atom = shift;
171 9 50       45 if (@_ == 2) {
    50          
172 0         0 my ($attr, $val) = @_;
173 0         0 $atom->{elem}->attributes->{"{}$attr"} = $val;
174             } elsif (@_ == 3) {
175 9         19 my ($ns, $attr, $val) = @_;
176 9 50       26 my $ns_uri =
177             ref($ns) eq 'XML::Atom::Syndication::Namespace' ? $ns->{uri} : $ns;
178 9 50       20 $ns_uri = '' if $atom->ns eq $ns_uri;
179 9         31 $atom->{elem}->attributes->{"{$ns_uri}$attr"} = $val;
180             }
181             }
182              
183             #--- utility
184              
185             sub _remove {
186 1     1   2 my $elem = shift;
187 1 50       5 my $parent = $elem->parent
188             or die 'Element parent is not defined';
189 1         9 my @contents = grep { $elem ne $_ } @{$parent->contents};
  7         27  
  1         4  
190 1         5 $parent->contents(\@contents);
191 1         10 $elem->parent(undef);
192 1         6 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 339     339 0 665 my $atom = shift;
203 339         469 my $param = shift;
204 339 100       1271 if (my $ns = delete $param->{Namespace}) {
205 207         1002 $atom->{ns} = $ns;
206 207         876 $atom->{version} = $NS_VERSION{$ns};
207             } else {
208 132   100     834 my $version = delete $param->{Version} || '1.0';
209 132 100       821 $version = '1.0' if $version == 1;
210 132 50       628 my $ns = $NS_MAP{$version}
211             or return $atom->error("Unknown version: $version");
212 132         633 $atom->{ns} = $ns;
213 132         538 $atom->{version} = $version;
214             }
215             }
216              
217             1;
218              
219             __END__