Add pod and coverage tests
[catagits/XML-Feed.git] / lib / XML / Feed / Format / Atom.pm
1 # $Id: Atom.pm 1958 2006-08-14 05:31:27Z btrott $
2
3 package XML::Feed::Format::Atom;
4 use strict;
5
6 use base qw( XML::Feed );
7 use XML::Atom::Feed;
8 use XML::Atom::Util qw( iso2dt );
9 use List::Util qw( first );
10 use DateTime::Format::W3CDTF;
11
12 use XML::Atom::Entry;
13 XML::Atom::Entry->mk_elem_accessors(qw( lat long ), ['http://www.w3.org/2003/01/geo/wgs84_pos#']);
14
15 use XML::Atom::Content;
16
17 sub init_empty {
18     my ($feed, %args) = @_;
19     $args{'Version'} ||= '1.0';
20     
21     $feed->{atom} = XML::Atom::Feed->new(%args);
22     $feed;
23 }
24
25 # monkey patch
26 {
27     my $sub =  sub {
28         my $item = shift;
29         if (XML::Atom::LIBXML) {
30             my $elem = $item->elem;
31             if (@_) {
32                 $elem->setAttributeNS('http://www.w3.org/XML/1998/namespace',
33                     'base', $_[0]);
34             }
35             return $elem->getAttributeNS('http://www.w3.org/XML/1998/namespace', 'base');
36         } else {
37             if (@_) {
38                 $item->elem->setAttribute('xml:base', $_[0]);
39             }
40             return $item->elem->getAttribute('xml:base');
41         }
42
43     };
44     no strict 'refs';
45     *XML::Atom::Feed::base    = $sub unless XML::Atom::Feed->can('base');
46     *XML::Atom::Entry::base   = $sub unless XML::Atom::Entry->can('base');
47     *XML::Atom::Content::base = $sub unless XML::Atom::Content->can('base');
48 }
49
50 sub init_string {
51     my $feed = shift;
52     my($str) = @_;
53     if ($str) {
54         $feed->{atom} = XML::Atom::Feed->new(Stream => $str)
55             or return $feed->error(XML::Atom::Feed->errstr);
56     }
57     $feed;
58 }
59
60 sub format { 'Atom' }
61
62 sub title { shift->{atom}->title(@_) }
63 sub link {
64     my $feed = shift;
65     if (@_) {
66         $feed->{atom}->add_link({ rel => 'alternate', href => $_[0],
67                                   type => 'text/html', });
68     } else {
69         my $l = first { !defined $_->rel || $_->rel eq 'alternate' } $feed->{atom}->link;
70         $l ? $l->href : undef;
71     }
72 }
73
74 sub self_link {
75     my $feed = shift;
76     if (@_) {
77         my $uri = shift;
78         $feed->{atom}->add_link({type => "application/atom+xml", rel => "self", href => $uri});
79         return $uri;
80     } 
81     else
82     {
83         my $l =
84             first
85             { !defined $_->rel || $_->rel eq 'self' }
86             $feed->{atom}->link;
87             ;
88
89         return $l ? $l->href : undef;
90     }
91 }
92
93 sub description { shift->{atom}->tagline(@_) }
94 sub copyright   { shift->{atom}->copyright(@_) }
95 sub language    { shift->{atom}->language(@_) }
96 sub generator   { shift->{atom}->generator(@_) }
97 sub id          { shift->{atom}->id(@_) }
98 sub updated     { shift->{atom}->updated(@_) }
99 sub add_link    { shift->{atom}->add_link(@_) }
100 sub base        { shift->{atom}->base(@_) }
101
102 sub author {
103     my $feed = shift;
104     if (@_ && $_[0]) {
105         my $person = XML::Atom::Person->new(Version => 1.0);
106         $person->name($_[0]);
107         $feed->{atom}->author($person);
108     } else {
109         $feed->{atom}->author ? $feed->{atom}->author->name : undef;
110     }
111 }
112
113
114
115
116 sub modified {
117     my $feed = shift;
118     if (@_) {
119         $feed->{atom}->modified(DateTime::Format::W3CDTF->format_datetime($_[0]));
120     } else {
121         return iso2dt($feed->{atom}->modified) if $feed->{atom}->modified;
122         return iso2dt($feed->{atom}->updated)  if $feed->{atom}->updated;
123         return undef;
124     }
125 }
126
127 sub entries {
128     my @entries;
129     for my $entry ($_[0]->{atom}->entries) {
130         push @entries, XML::Feed::Entry::Format::Atom->wrap($entry);
131     }
132
133     @entries;
134 }
135
136 sub add_entry {
137     my $feed  = shift;
138     my $entry = shift || return;
139     $entry    = $feed->_convert_entry($entry);
140     $feed->{atom}->add_entry($entry->unwrap);
141 }
142
143 sub as_xml { $_[0]->{atom}->as_xml }
144
145 package XML::Feed::Entry::Format::Atom;
146 use strict;
147
148 use base qw( XML::Feed::Entry );
149 use XML::Atom::Util qw( iso2dt );
150 use XML::Feed::Content;
151 use XML::Atom::Entry;
152 use List::Util qw( first );
153
154 sub init_empty {
155     my $entry = shift;
156     $entry->{entry} = XML::Atom::Entry->new(Version => 1.0);
157     1;
158 }
159
160 sub title { shift->{entry}->title(@_) }
161 sub source { shift->{entry}->source(@_) }
162 sub updated { shift->{entry}->updated(@_) }
163 sub base { shift->{entry}->base(@_) }
164
165 sub link {
166     my $entry = shift;
167     if (@_) {
168         $entry->{entry}->add_link({ rel => 'alternate', href => $_[0],
169                                     type => 'text/html', });
170     } else {
171         my $l = first { !defined $_->rel || $_->rel eq 'alternate' } $entry->{entry}->link;
172         $l ? $l->href : undef;
173     }
174 }
175
176 sub summary {
177     my $entry = shift;
178     if (@_) {
179                 my %param;
180                 if (ref($_[0]) eq 'XML::Feed::Content') {
181                         %param = (Body => $_[0]->body);
182                 } else {
183                          %param = (Body => $_[0]);
184                 }
185                 $entry->{entry}->summary(XML::Atom::Content->new(%param, Version => 1.0));
186     } else {
187                 my $s = $entry->{entry}->summary;
188         # map Atom types to MIME types
189         my $type = ($s && ref($s) eq 'XML::Feed::Content') ? $s->type : undef;
190         if ($type) {
191             $type = 'text/html'  if $type eq 'xhtml' || $type eq 'html';
192             $type = 'text/plain' if $type eq 'text';
193         }
194                 my $body = $s;  
195                 if (defined $s && ref($s) eq 'XML::Feed::Content') {
196                         $body = $s->body;
197                 }
198         XML::Feed::Content->wrap({ type => $type,
199                                    body => $body });
200     }
201 }
202
203 my %types = (
204         'text/xhtml' => 'xhtml',
205         'text/html'  => 'html',
206         'text/plain' => 'text',
207 );
208
209 sub content {
210     my $entry = shift;
211     if (@_) {
212         my %param;
213         my $base;
214         if (ref($_[0]) eq 'XML::Feed::Content') {
215                         if (defined $_[0]->type && defined $types{$_[0]->type}) {
216                     %param = (Body => $_[0]->body, Type => $types{$_[0]->type});
217                         } else {
218                     %param = (Body => $_[0]->body);
219                         }
220             $base = $_[0]->base if defined $_[0]->base;
221         } else {
222             %param = (Body => $_[0]);
223         }
224         $entry->{entry}->content(XML::Atom::Content->new(%param, Version => 1.0));
225         $entry->{entry}->content->base($base) if defined $base;
226     } else {
227         my $c = $entry->{entry}->content;
228
229         # map Atom types to MIME types
230         my $type = $c ? $c->type : undef;
231         if ($type) {
232             $type = 'text/html'  if $type eq 'xhtml' || $type eq 'html';
233             $type = 'text/plain' if $type eq 'text';
234         }
235
236         XML::Feed::Content->wrap({ type => $type,
237                                    base => $c ? $c->base : undef, 
238                                    body => $c ? $c->body : undef });
239     }
240 }
241
242 sub category {
243     my $entry = shift;
244     my $ns = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/');
245     if (@_) {
246         $entry->{entry}->add_category({ term => $_[0] });
247     } else {
248         my $category = $entry->{entry}->category;
249         my @return = $category ? ($category->label || $category->term) : $entry->{entry}->getlist($ns, 'subject');
250         return wantarray? @return : $return[0];
251     }
252 }
253
254 sub author {
255     my $entry = shift;
256     if (@_ && $_[0]) {
257         my $person = XML::Atom::Person->new(Version => 1.0);
258         $person->name($_[0]);
259         $entry->{entry}->author($person);
260     } else {
261         $entry->{entry}->author ? $entry->{entry}->author->name : undef;
262     }
263 }
264
265 sub id { shift->{entry}->id(@_) }
266
267 sub issued {
268     my $entry = shift;
269     if (@_) {
270         $entry->{entry}->issued(DateTime::Format::W3CDTF->format_datetime($_[0])) if $_[0];
271     } else {
272         $entry->{entry}->issued ? iso2dt($entry->{entry}->issued) : undef;
273     }
274 }
275
276 sub modified {
277     my $entry = shift;
278     if (@_) {
279         $entry->{entry}->modified(DateTime::Format::W3CDTF->format_datetime($_[0])) if $_[0];
280     } else {
281         return iso2dt($entry->{entry}->modified) if $entry->{entry}->modified;
282         return iso2dt($entry->{entry}->updated)  if $entry->{entry}->updated;
283         return undef;
284     }
285 }
286
287 sub lat {
288     my $entry = shift;
289     if (@_) {
290    $entry->{entry}->lat($_[0]) if $_[0];
291     } else {
292    $entry->{entry}->lat;
293     }
294 }
295
296 sub long {
297     my $entry = shift;
298     if (@_) {
299    $entry->{entry}->long($_[0]) if $_[0];
300     } else {
301    $entry->{entry}->long;
302     }
303 }
304
305 1;