File Coverage

blib/lib/Mojo/Feed/Item.pm
Criterion Covered Total %
statement 49 55 89.0
branch 17 20 85.0
condition 11 13 84.6
subroutine 9 11 81.8
pod 2 2 100.0
total 88 101 87.1


line stmt bran cond sub pod time code
1             package Mojo::Feed::Item;
2 12     12   92 use Mojo::Base '-base';
  12         28  
  12         89  
3 12     12   2270 use Mojo::Util qw( trim );
  12         28  
  12         572  
4              
5 12     12   71 use HTTP::Date 'str2time';
  12         26  
  12         678  
6              
7 12     12   5928 use Mojo::Feed::Item::Enclosure;
  12         33  
  12         79  
8              
9             use overload
10 0     0   0 bool => sub {1},
11 0     0   0 '""' => sub { shift->to_string },
12 12     12   996 fallback => 1;
  12         28  
  12         128  
13              
14              
15             has [qw(title link content id description published author)];
16              
17             has tags => sub {
18             shift->dom->find('category, dc\:subject')
19             ->map(sub { $_[0]->text || $_[0]->attr('term') });
20             };
21              
22             has 'dom';
23             has feed => undef, weak => 1;
24              
25             has summary => sub { shift->description };
26              
27             my %selector = (
28             content => ['content', 'content|encoded', 'xhtml|body', 'description'],
29             description => ['description', 'summary'],
30             published => [
31             'published', 'pubDate', 'dc|date', 'created',
32             'issued', 'updated', 'modified'
33             ],
34             author => ['|author', 'atom|author', 'dc|creator'],
35             id => ['id', 'guid', 'link'],
36             title => ['title'],
37             link => ['link']
38             );
39              
40             sub _get_selector {
41 1238     1238   6090 my ($self, $k) = @_;
42 1238         2128 for my $selector (@{$selector{$k}}) {
  1238         3017  
43 2046 100       456034 if (my $p = $self->dom->at($selector, %{$self->feed->namespaces})) {
  2046         8885  
44 1080 100 100     332952 if ($k eq 'author' && $p->at('name')) {
45 36         6932 return trim $p->at('name')->text;
46             }
47 1044         7533 my ($text) = grep $_, map trim($_), grep $_, $p->text, $p->content;
48 1044   100     208483 $text ||= '';
49 1044 100       2475 if ($k eq 'published') {
50 194         732 return str2time($text);
51             }
52 850         7570 return $text;
53             }
54             }
55             };
56              
57             sub _set_selector {
58 10     10   65 my ($self, $k, $val) = @_;
59 10         21 for my $selector (@{$selector{$k}}) {
  10         32  
60 11 100       432 if (my $p = $self->dom->at($selector, %{$self->feed->namespaces})) {
  11         87  
61 10 50 33     2813 if ($k eq 'author' && $p->at('name')) {
62 0         0 return $p->at('name')->content($val);
63             }
64 10 100       26 if ($k eq 'published') {
65 2         25 return $p->content(Mojo::Date->new($val)->to_datetime()); # let's pretend we're all OK with Atom dates
66             }
67 8         29 return $p->content($val);
68             }
69             }
70             # still here? I guess the element is missing, so add it?
71             # THIS is another reason to move being feed-type specific:
72 0 0       0 if ($k eq 'author') {
73 0         0 return $self->dom->append_content($self->dom->new_tag('author', $val));
74             }
75 0         0 return $self->dom->append_content($self->dom->new_tag($selector{$k}[0], $val));
76             };
77              
78              
79              
80             foreach my $k (keys %selector) {
81             has $k => sub { return shift->_get_selector($k) || undef }
82             }
83              
84             has enclosures => sub {
85             my $self = shift;
86             my @enclosures;
87             $self->dom->find('enclosure')->each(sub {
88             push @enclosures, $_;
89             });
90             $self->dom->find('link')->each(sub {
91             my $l = shift;
92             if ($l->attr('href') && $l->attr('rel') && $l->attr('rel') eq 'enclosure') {
93             push @enclosures, $l;
94             }
95             });
96             return Mojo::Collection->new(
97             map { Mojo::Feed::Item::Enclosure->new(dom => $_) } @enclosures);
98             };
99              
100             has link => sub {
101              
102             # let's handle links seperately, because ATOM loves these buggers:
103             my $link;
104             shift->dom->find('link')->each(sub {
105             my $l = shift;
106             if ($l->attr('href')
107             && (!$l->attr('rel') || $l->attr('rel') eq 'alternate'))
108             {
109             $link = trim $l->attr('href');
110             }
111             else {
112             if ($l->text =~ /\w+/) {
113             $link = trim $l->text; # simple link
114             }
115             }
116             });
117             return $link;
118             };
119              
120             sub to_string {
121 31     31 1 69 my $self = shift;
122 31         127 foreach my $k (keys %selector) {
123 217 100 100     9228 if ($self->$k && $self->$k ne $self->_get_selector($k)) {
124             # write it to the DOM:
125 10         248 $self->_set_selector($k, $self->$k);
126             }
127             }
128 31         133 $self->dom->to_string;
129             }
130              
131             sub to_hash {
132 146     146 1 1816 my $self = shift;
133 146   100     593 my $hash = {map { $_ => '' . ($self->$_ || '') } keys %selector};
  1022         176687  
134 146 100       1383 if ($self->enclosures->size) {
135 6         119 $hash->{'enclosures'} = $self->enclosures->map('to_hash')->to_array;
136             }
137 146 100       1925 if ($self->tags->size) {
138 88         4581 $hash->{'tags'} = $self->tags->to_array;
139             }
140 146         81968 return $hash;
141             }
142              
143             1;
144              
145             __END__