File Coverage

blib/lib/Data/Microformat/hFeed.pm
Criterion Covered Total %
statement 62 123 50.4
branch 33 68 48.5
condition 7 18 38.8
subroutine 12 14 85.7
pod 5 5 100.0
total 119 228 52.1


line stmt bran cond sub pod time code
1             package Data::Microformat::hFeed;
2              
3 4     4   7332 use strict;
  4         8  
  4         146  
4 4     4   20 use base qw(Data::Microformat);
  4         8  
  4         1662  
5 4     4   2261 use Data::Microformat::hFeed::hEntry;
  4         12  
  4         117  
6 4     4   34 use Data::Microformat::geo;
  4         6  
  4         5902  
7              
8 4     4 1 13 sub class_name { "hfeed" }
9 4     4 1 29 sub singular_fields { qw(id title base language geo link tagline description author modified copyright generator) }
10 4     4 1 23 sub plural_fields { qw(entries categories) }
11              
12             sub from_tree {
13 3     3 1 8 my $class = shift;
14 3         8 my $tree = shift;
15 3         8 my $url = shift;
16              
17 3         6 my @feeds;
18 3         37 foreach my $feed_tree ($tree->look_down('class', qr/hfeed/)) {
19 3         733 push @feeds, $class->_convert($feed_tree, $url);
20             }
21             # As per the spec :
22             # "the Feed element is optional and, if missing, is assumed to be the page"
23 3 100       261 push @feeds, $class->_convert($tree, $url) unless @feeds;
24              
25 3 100       20 return wantarray ? @feeds : $feeds[0];
26             }
27              
28 0 0   0 1 0 sub generator { shift->SUPER::generator(@_) || __PACKAGE__ }
29              
30             sub _convert {
31 4     4   10 my $class = shift;
32 4         11 my $tree = shift;
33 4         7 my $url = shift;
34 4         52 my $feed = $class->new;
35 4         39 $feed->{_no_dupe_keys} = 1;
36 4 50       20 if (defined $url) {
37 0         0 $feed->link($url);
38 0         0 $feed->base($url);
39             }
40 4         8 my %tags;
41             $tree->look_down(sub {
42 35     35   497 my $bit = shift;
43 35   50     124 my $feed_class = $bit->attr('class') || $bit->attr('rel') || $bit->attr('lang') || $bit->attr("http-equiv") || $bit->tag || return 0;
44 35 50 33     1063 if (!$feed_class) {
    100 33        
    100 66        
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
45 0         0 return 0;
46             } elsif (_match($feed_class, 'hentry')) {
47 3         17 $bit->detach;
48 3         275 $feed->entries(Data::Microformat::hFeed::hEntry->from_tree($bit, $url));
49 3         19 $bit->delete;
50             } elsif (_match($feed_class, 'feed-title')) {
51 3         16 $feed->title($bit->as_text);
52 3         7 foreach my $attr (qw(id lang)) {
53 6 50       47 $feed->$attr($bit->attr($attr)) if $bit->attr($attr);
54             }
55             } elsif (_match($feed_class, 'feed-language')) {
56 0   0     0 $feed->language($bit->attr('content') || $bit->as_text);
57             } elsif (_match($feed_class, 'Content-Language')) {
58 0         0 $feed->language($bit->attr('content'));
59             } elsif (_match($feed_class, 'lang') && $bit->tag eq 'body') {
60 0         0 $feed->language($bit->attr('lang'));
61             } elsif (_match($feed_class, 'self') && $bit->tag eq 'link') {
62 0         0 $feed->link($class->_url_decode($bit->attr('href')));
63             } elsif (_match($feed_class, 'bookmark')) {
64 0         0 $feed->link($class->_url_decode($bit->attr('href')));
65             } elsif (_match($feed_class, 'title')) {
66 1         6 $feed->title($bit->as_text);
67             } elsif (_match($feed_class, 'feed-tagline')) {
68 2         54 $feed->tagline($bit->as_text);
69             } elsif (_match($feed_class, 'feed-description')) {
70 2         11 $feed->description($bit->as_text);
71             } elsif (_match($feed_class, 'updated')) {
72 2         11 $feed->modified(_do_date($bit));
73             } elsif (_match($feed_class, 'license')) {
74 2         6 my $opts = {};
75 2 50       10 $opts->{href} = $class->_url_decode($bit->attr('href')) if $bit->attr('href');
76 2 50       13 $opts->{text} = $bit->as_text if $bit->as_text;
77 2         215 $feed->copyright($opts);
78             } elsif (_match($feed_class,'vcard')) {
79 2         13 $bit->detach;
80 2         50 my $card = Data::Microformat::hCard->from_tree($bit, $url);
81 2         23 $feed->author($card);
82 2         9 $bit->delete;
83             } elsif (_match($feed_class, 'geo')) {
84 0         0 $bit->detach;
85 0         0 my $geo = Data::Microformat::geo->from_tree($bit, $url);
86 0         0 $feed->geo($geo);
87 0         0 $bit->delete;
88             } elsif (_match($feed_class, 'tag') && _match($feed_class, 'directory')) {
89 4         45 $feed->categories($bit->as_text);
90             } else {
91             # print "Unknown class $feed_class\n";
92             }
93 35         1123 return 0;
94 4         77 });
95 4         195 $feed->{_no_dupe_keys} = 0;
96 4         20 return $feed;
97             }
98              
99             sub _do_date {
100 2     2   6 my $element = shift;
101 2   50     9 my $title = $element->attr('title') || return;
102 2         32 return DateTime::Format::W3CDTF->parse_datetime($title);
103             }
104              
105             sub _match {
106 401   50 401   870 my $field = shift || return 0;
107 401         443 my $target = shift;
108 401         8530 return $field =~ m!(^|\s)$target(\s|$)!;
109             }
110              
111             sub _to_hcard_elements {
112 0     0     my $feed = shift;
113              
114 0           my $root = HTML::Element->new('div', class => 'hfeed');
115 0 0         $root->attr('id', $feed->id) if defined $feed->id;
116 0 0         $root->attr('lang', $feed->language) if defined $feed->language;
117              
118             # title
119             # link
120 0 0         if (defined $feed->title) {
121 0           my $title = HTML::Element->new('div', class => 'feed-title');
122 0 0         if ($feed->link) {
123 0           my $link = HTML::Element->new('a', href => $feed->link, rel => 'bookmark');
124 0           $link->push_content($feed->title);
125 0           $title->push_content($link);
126             } else {
127 0           $title->push_content($feed->title);
128             }
129 0           $root->push_content($title);
130             }
131              
132             # updated
133 0 0         if ($feed->modified) {
134 0           my $div = HTML::Element->new('div');
135 0           my $abbr = HTML::Element->new('abbr', class => "updated", title => DateTime::Format::W3CDTF->format_datetime($feed->modified));
136 0           $abbr->push_content($feed->modified->strftime("%B %d, %Y"));
137 0           $div->push_content($abbr);
138 0           $root->push_content($div);
139             }
140              
141             # tagline
142             # description
143 0           foreach my $attr (qw(tagline description)) {
144 0 0         next unless $feed->$attr;
145 0           my $div = HTML::Element->new('div', class => "feed-$attr");
146 0           $div->push_content($feed->$attr);
147 0           $root->push_content($div);
148             }
149              
150             # license
151 0 0         if ($feed->copyright) {
152 0           my $license = $feed->copyright;
153 0           my $div = HTML::Element->new('div');
154 0           my $a = HTML::Element->new('a', rel => 'license');
155 0 0         $a->attr('href', $license->{href}) if defined $license->{href};
156 0 0         $a->push_content($license->{content}) if defined $license->{content};
157 0           $div->push_content($a);
158 0           $root->push_content($div);
159             }
160              
161             # author
162             # geo
163 0           foreach my $attr (qw(author geo)) {
164 0 0         next unless $feed->$attr;
165 0           my $div = HTML::Element->new('div');
166 0           $div->push_content($feed->$attr->_to_hcard_elements);
167 0           $root->push_content($div);
168             }
169              
170             # categories
171 0           my @categories = $feed->categories;
172 0 0         if (@categories) {
173 0           my $div = HTML::Element->new('div', class => 'feed-categories');
174 0           $div->push_content("Categories: ");
175 0           foreach my $category (@categories) {
176 0           my $a = HTML::Element->new('div', rel => 'tag directory');
177 0           $a->push_content($category);
178 0           $div->push_content($a);
179             }
180 0           $root->push_content($div);
181             }
182            
183             # entries
184 0           foreach my $entry ($feed->entries) {
185 0           $root->push_content($entry->_to_hcard_elements);
186             }
187 0           return $root;
188             }
189              
190             1;
191              
192             __END__