blib/lib/HTML/Latemp/News.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 16 | 29 | 55.1 |
branch | 0 | 2 | 0.0 |
condition | n/a | ||
subroutine | 6 | 8 | 75.0 |
pod | n/a | ||
total | 22 | 39 | 56.4 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package HTML::Latemp::News; | ||||||
2 | |||||||
3 | 1 | 1 | 28549 | use warnings; | |||
1 | 2 | ||||||
1 | 46 | ||||||
4 | 1 | 1 | 5 | use strict; | |||
1 | 2 | ||||||
1 | 38 | ||||||
5 | |||||||
6 | 1 | 1 | 31 | use 5.008; | |||
1 | 8 | ||||||
1 | 103 | ||||||
7 | |||||||
8 | =head1 NAME | ||||||
9 | |||||||
10 | HTML::Latemp::News - News Maintenance Module for Latemp (and possibly other | ||||||
11 | web frameworks) | ||||||
12 | |||||||
13 | =cut | ||||||
14 | |||||||
15 | our $VERSION = '0.1.8'; | ||||||
16 | |||||||
17 | =head1 SYNOPSIS | ||||||
18 | |||||||
19 | #!/usr/bin/perl | ||||||
20 | |||||||
21 | use strict; | ||||||
22 | use warnings; | ||||||
23 | |||||||
24 | use MyManageNews; | ||||||
25 | |||||||
26 | my @news_items = | ||||||
27 | ( | ||||||
28 | . | ||||||
29 | . | ||||||
30 | . | ||||||
31 | { | ||||||
32 | 'title' => "Changes of 18-April-2005", | ||||||
33 | 'id' => "changes-2005-04-18", | ||||||
34 | 'description' => q{Around 18 April, 2005, Jane's Site has seen a | ||||||
35 | lot of changes. Click the link for details on them.}, | ||||||
36 | 'date' => "2005-04-18", | ||||||
37 | 'author' => "Jane Smith", | ||||||
38 | 'category' => "Jane's Site", | ||||||
39 | }, | ||||||
40 | . | ||||||
41 | . | ||||||
42 | . | ||||||
43 | ); | ||||||
44 | |||||||
45 | my $news_manager = | ||||||
46 | HTML::Latemp::News->new( | ||||||
47 | 'news_items' => \@news_items, | ||||||
48 | 'title' => "Better SCM News", | ||||||
49 | 'link' => "http://janes-site.tld/", | ||||||
50 | 'language' => "en-US", | ||||||
51 | 'copyright' => "Copyright by Jane Smith, (c) 2005", | ||||||
52 | 'webmaster' => "Jane Smith |
||||||
53 | 'managing_editor' => "Jane Smith |
||||||
54 | 'description' => "News of Jane's Site - a personal site of " . | ||||||
55 | "Jane Smith", | ||||||
56 | ); | ||||||
57 | |||||||
58 | $news_manager->generate_rss_feed( | ||||||
59 | 'output_filename' => "dest/rss.xml" | ||||||
60 | ); | ||||||
61 | |||||||
62 | 1; | ||||||
63 | =cut | ||||||
64 | |||||||
65 | package HTML::Latemp::News::Base; | ||||||
66 | |||||||
67 | 1 | 1 | 6 | use base 'Class::Accessor'; | |||
1 | 3 | ||||||
1 | 1907 | ||||||
68 | 1 | 1 | 5365 | use CGI; | |||
1 | 21991 | ||||||
1 | 9 | ||||||
69 | |||||||
70 | sub new | ||||||
71 | { | ||||||
72 | 0 | 0 | my $class = shift; | ||||
73 | 0 | my $self = {}; | |||||
74 | 0 | bless $self, $class; | |||||
75 | 0 | $self->initialize(@_); | |||||
76 | 0 | return $self; | |||||
77 | } | ||||||
78 | |||||||
79 | package HTML::Latemp::News::Item; | ||||||
80 | |||||||
81 | our @ISA=(qw(HTML::Latemp::News::Base)); | ||||||
82 | |||||||
83 | __PACKAGE__->mk_accessors(qw(index title id description author date | ||||||
84 | category text)); | ||||||
85 | |||||||
86 | sub initialize | ||||||
87 | { | ||||||
88 | 0 | 0 | my $self = shift; | ||||
89 | |||||||
90 | 0 | my (%args) = (@_); | |||||
91 | |||||||
92 | 0 | foreach my $k (keys(%args)) | |||||
93 | { | ||||||
94 | 0 | 0 | if (! $self->can($k)) | ||||
95 | { | ||||||
96 | 0 | die "Unknown property for HTML::Latemp::News::Item - \"$k\"!"; | |||||
97 | } | ||||||
98 | 0 | $self->set($k, $args{$k}); | |||||
99 | } | ||||||
100 | } | ||||||
101 | |||||||
102 | package HTML::Latemp::News; | ||||||
103 | |||||||
104 | our @ISA=(qw(HTML::Latemp::News::Base)); | ||||||
105 | |||||||
106 | __PACKAGE__->mk_accessors(qw(copyright description docs generator items | ||||||
107 | language link managing_editor rating title ttl webmaster)); | ||||||
108 | |||||||
109 | 1 | 1 | 848 | use XML::RSS; | |||
0 | |||||||
0 | |||||||
110 | |||||||
111 | sub input_items | ||||||
112 | { | ||||||
113 | my $self = shift; | ||||||
114 | |||||||
115 | my $items = shift; | ||||||
116 | |||||||
117 | return | ||||||
118 | [ | ||||||
119 | map | ||||||
120 | { $self->input_single_item($_, $items->[$_]) } | ||||||
121 | (0 .. $#$items) | ||||||
122 | ]; | ||||||
123 | } | ||||||
124 | |||||||
125 | sub input_single_item | ||||||
126 | { | ||||||
127 | my $self = shift; | ||||||
128 | my ($index, $inputted_item) = (@_); | ||||||
129 | |||||||
130 | return | ||||||
131 | HTML::Latemp::News::Item->new( | ||||||
132 | %$inputted_item, | ||||||
133 | 'index' => $index, | ||||||
134 | ); | ||||||
135 | } | ||||||
136 | |||||||
137 | sub initialize | ||||||
138 | { | ||||||
139 | my $self = shift; | ||||||
140 | |||||||
141 | my %args = (@_); | ||||||
142 | |||||||
143 | my $items = $args{'news_items'}; | ||||||
144 | |||||||
145 | $self->items( | ||||||
146 | $self->input_items($items) | ||||||
147 | ); | ||||||
148 | |||||||
149 | $self->title($args{'title'}); | ||||||
150 | $self->link($args{'link'}); | ||||||
151 | $self->language($args{'language'}); | ||||||
152 | $self->rating($args{'rating'} || '(PICS-1.1 "http://www.classify.org/safesurf/" 1 r (SS~~000 1))'); | ||||||
153 | $self->copyright($args{'copyright'} || ""); | ||||||
154 | $self->docs($args{'docs'} || "http://blogs.law.harvard.edu/tech/rss"); | ||||||
155 | $self->ttl($args{'ttl'} || "360"); | ||||||
156 | $self->generator($args{'generator'} || "Perl and XML::RSS"); | ||||||
157 | $self->webmaster($args{'webmaster'}); | ||||||
158 | $self->managing_editor($args{'managing_editor'} || $self->webmaster()); | ||||||
159 | $self->description($args{'description'}); | ||||||
160 | |||||||
161 | return 0; | ||||||
162 | } | ||||||
163 | |||||||
164 | =head1 DESCRIPTION | ||||||
165 | |||||||
166 | This is a module that maintains news item for a web-site. It can generate | ||||||
167 | an RSS feed, as well as a news page, and an HTML newsbox, all from the same | ||||||
168 | data. | ||||||
169 | |||||||
170 | =head1 FUNCTION | ||||||
171 | |||||||
172 | =head2 HTML::Latemp::News->new(...) | ||||||
173 | |||||||
174 | This is the constructor for the news manager. It accepts the following named | ||||||
175 | parameters: | ||||||
176 | |||||||
177 | =over 8 | ||||||
178 | |||||||
179 | =item 'news_items' | ||||||
180 | |||||||
181 | This is a reference to a list of news_items. See below. | ||||||
182 | |||||||
183 | =item 'title' | ||||||
184 | |||||||
185 | The title of the RSS feed. | ||||||
186 | |||||||
187 | =item 'link' | ||||||
188 | |||||||
189 | The link to the homepage of the site. | ||||||
190 | |||||||
191 | =item 'language' | ||||||
192 | |||||||
193 | The language of the text. | ||||||
194 | |||||||
195 | =item 'copyright' | ||||||
196 | |||||||
197 | The copyright notice of the text. | ||||||
198 | |||||||
199 | =item 'webmaster' | ||||||
200 | |||||||
201 | The Webmaster. | ||||||
202 | |||||||
203 | =item 'managing_editor' | ||||||
204 | |||||||
205 | The managing editor. | ||||||
206 | |||||||
207 | =item 'description' | ||||||
208 | |||||||
209 | A description of the news feed as will be put in the RSS feed. | ||||||
210 | |||||||
211 | =back | ||||||
212 | |||||||
213 | =head3 Format of the news_items | ||||||
214 | |||||||
215 | The news_items is a reference to an array, of which each element is a hash | ||||||
216 | reference. The hash may contain the following keys: | ||||||
217 | |||||||
218 | =over 8 | ||||||
219 | |||||||
220 | =item 'title' | ||||||
221 | |||||||
222 | The title of the item. | ||||||
223 | |||||||
224 | =item 'id' | ||||||
225 | |||||||
226 | The ID of the item. This will also be used to calculate URLs. | ||||||
227 | |||||||
228 | =item 'description' | ||||||
229 | |||||||
230 | A text description explaining what the item is all about. | ||||||
231 | |||||||
232 | =item 'author' | ||||||
233 | |||||||
234 | The author of the item. | ||||||
235 | |||||||
236 | =item 'date' | ||||||
237 | |||||||
238 | A string representing the daet. | ||||||
239 | |||||||
240 | =item 'category' | ||||||
241 | |||||||
242 | The cateogry of the item. | ||||||
243 | |||||||
244 | =back | ||||||
245 | |||||||
246 | =cut | ||||||
247 | |||||||
248 | sub add_item_to_rss_feed | ||||||
249 | { | ||||||
250 | my $self = shift; | ||||||
251 | my %args = (@_); | ||||||
252 | |||||||
253 | my $item = $args{'item'}; | ||||||
254 | my $rss_feed = $args{'feed'}; | ||||||
255 | |||||||
256 | my $item_url = $self->get_item_url($item); | ||||||
257 | |||||||
258 | $rss_feed->add_item( | ||||||
259 | 'title' => $item->title(), | ||||||
260 | 'link' => $item_url, | ||||||
261 | 'permaLink' => $item_url, | ||||||
262 | 'enclosure' => { 'url' => $item_url, }, | ||||||
263 | 'description' => $item->description(), | ||||||
264 | 'author' => $item->author(), | ||||||
265 | 'pubDate' => $item->date(), | ||||||
266 | 'category' => $item->category(), | ||||||
267 | ); | ||||||
268 | } | ||||||
269 | |||||||
270 | sub get_item_url | ||||||
271 | { | ||||||
272 | my $self = shift; | ||||||
273 | my $item = shift; | ||||||
274 | return $self->link() . $self->get_item_rel_url($item); | ||||||
275 | } | ||||||
276 | |||||||
277 | sub get_item_rel_url | ||||||
278 | { | ||||||
279 | my $self = shift; | ||||||
280 | my $item = shift; | ||||||
281 | return "news/" . $item->id() . "/"; | ||||||
282 | } | ||||||
283 | |||||||
284 | sub get_items_to_include | ||||||
285 | { | ||||||
286 | my $self = shift; | ||||||
287 | my $args = shift; | ||||||
288 | |||||||
289 | my $num_items_to_include = $args->{'num_items'} || 10; | ||||||
290 | |||||||
291 | my $items = $self->items(); | ||||||
292 | |||||||
293 | if (@$items < $num_items_to_include) | ||||||
294 | { | ||||||
295 | $num_items_to_include = scalar(@$items); | ||||||
296 | } | ||||||
297 | |||||||
298 | return [ @$items[(-$num_items_to_include) .. (-1)] ]; | ||||||
299 | } | ||||||
300 | |||||||
301 | sub generate_rss_feed | ||||||
302 | { | ||||||
303 | my $self = shift; | ||||||
304 | |||||||
305 | my %args = (@_); | ||||||
306 | |||||||
307 | my $rss_feed = XML::RSS->new('version' => "2.0"); | ||||||
308 | $rss_feed->channel( | ||||||
309 | 'title' => $self->title(), | ||||||
310 | 'link' => $self->link(), | ||||||
311 | 'language' => $self->language(), | ||||||
312 | 'description' => $self->description(), | ||||||
313 | 'rating' => $self->rating(), | ||||||
314 | 'copyright' => $self->copyright(), | ||||||
315 | 'pubDate' => (scalar(localtime())), | ||||||
316 | 'lastBuildDate' => (scalar(localtime())), | ||||||
317 | 'docs' => $self->docs(), | ||||||
318 | 'ttl' => $self->ttl(), | ||||||
319 | 'generator' => $self->generator(), | ||||||
320 | 'managingEditor' => $self->managing_editor(), | ||||||
321 | 'webMaster' => $self->webmaster(), | ||||||
322 | ); | ||||||
323 | |||||||
324 | foreach my $single_item (@{$self->get_items_to_include(\%args)}) | ||||||
325 | { | ||||||
326 | $self->add_item_to_rss_feed( | ||||||
327 | 'item' => $single_item, | ||||||
328 | 'feed' => $rss_feed, | ||||||
329 | ); | ||||||
330 | } | ||||||
331 | |||||||
332 | my $filename = $args{'output_filename'} || "rss.xml"; | ||||||
333 | |||||||
334 | $rss_feed->save($filename); | ||||||
335 | } | ||||||
336 | |||||||
337 | =head2 $news_manager->generate_rss_feed('output_filename' => "rss.xml") | ||||||
338 | |||||||
339 | This generates an RSS feed. It accepts two named arguments. | ||||||
340 | C<'output_filename'> is the name of the RSS file to write to. C<'num_items'> | ||||||
341 | is the number of items to include, which defaults to 10. | ||||||
342 | |||||||
343 | =cut | ||||||
344 | |||||||
345 | sub get_navmenu_items | ||||||
346 | { | ||||||
347 | my $self = shift; | ||||||
348 | my %args = (@_); | ||||||
349 | |||||||
350 | my @ret; | ||||||
351 | |||||||
352 | foreach my $single_item (reverse(@{$self->get_items_to_include(\%args)})) | ||||||
353 | { | ||||||
354 | push @ret, | ||||||
355 | { | ||||||
356 | 'text' => $single_item->title(), | ||||||
357 | 'url' => $self->get_item_rel_url($single_item), | ||||||
358 | }; | ||||||
359 | } | ||||||
360 | return \@ret; | ||||||
361 | } | ||||||
362 | |||||||
363 | =head2 $news_manager->get_navmenu_items('num_items' => 5) | ||||||
364 | |||||||
365 | This generates navigation menu items for input to the navigation menu of | ||||||
366 | L |
||||||
367 | defaults to 10. | ||||||
368 | |||||||
369 | =cut | ||||||
370 | |||||||
371 | sub format_news_page_item | ||||||
372 | { | ||||||
373 | my $self = shift; | ||||||
374 | my (%args) = (@_); | ||||||
375 | |||||||
376 | my $item = $args{'item'}; | ||||||
377 | my $base_url = $args{'base_url'}; | ||||||
378 | |||||||
379 | return "id() . "/\">" . |
||||||
380 | CGI::escapeHTML($item->title()) . "\n" . | ||||||
381 | " \n" . $item->description() . "\n \n"; |
||||||
382 | } | ||||||
383 | |||||||
384 | sub get_news_page_entries | ||||||
385 | { | ||||||
386 | my $self = shift; | ||||||
387 | my %args = (@_); | ||||||
388 | |||||||
389 | my $html = ""; | ||||||
390 | |||||||
391 | my $base_url = exists($args{'base_url'}) ? $args{'base_url'} : ""; | ||||||
392 | |||||||
393 | foreach my $single_item (reverse(@{$self->get_items_to_include(\%args)})) | ||||||
394 | { | ||||||
395 | $html .= | ||||||
396 | $self->format_news_page_item( | ||||||
397 | 'item' => $single_item, | ||||||
398 | 'base_url' => $base_url, | ||||||
399 | ); | ||||||
400 | } | ||||||
401 | return $html; | ||||||
402 | } | ||||||
403 | |||||||
404 | =head2 $news_manager->get_news_page_entries('num_items' => 5, 'base_url' => "news/") | ||||||
405 | |||||||
406 | This generates HTML for the news page. 'base_url' points to a URL to be | ||||||
407 | appended to each item's ID. | ||||||
408 | |||||||
409 | =cut | ||||||
410 | |||||||
411 | sub get_news_box_contents | ||||||
412 | { | ||||||
413 | my $self = shift; | ||||||
414 | my (%args) = (@_); | ||||||
415 | |||||||
416 | my $html = ""; | ||||||
417 | foreach my $item (reverse(@{$self->get_items_to_include(\%args)})) | ||||||
418 | { | ||||||
419 | $html .= " | ||||||
420 | $self->get_item_rel_url($item) . "\">" . | ||||||
421 | CGI::escapeHTML($item->title()) . "\n"; | ||||||
422 | } | ||||||
423 | return $html; | ||||||
424 | } | ||||||
425 | |||||||
426 | |||||||
427 | sub get_news_box | ||||||
428 | { | ||||||
429 | my $self = shift; | ||||||
430 | |||||||
431 | my $html = ""; | ||||||
432 | |||||||
433 | $html .= qq{ \n}; |
||||||
434 | $html .= qq{News\n}; |
||||||
435 | $html .= qq{
|
||||||
436 | $html .= | ||||||
437 | $self->get_news_box_contents( | ||||||
438 | @_ | ||||||
439 | ); | ||||||
440 | $html .= qq{ |
||||||
441 | $html .= qq{\n}; | ||||||
442 | $html .= qq{\n}; | ||||||
443 | return $html; | ||||||
444 | } | ||||||
445 | |||||||
446 | =head2 $news_manager->get_news_box('num_items' => 5) | ||||||
447 | |||||||
448 | This generates an HTML news box with the recent headlines. | ||||||
449 | |||||||
450 | =cut | ||||||
451 | |||||||
452 | 1; | ||||||
453 | |||||||
454 | __END__ |