File Coverage

blib/lib/App/RecordStream/Operation/fromatomfeed.pm
Criterion Covered Total %
statement 19 19 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 26 100.0


line stmt bran cond sub pod time code
1             package App::RecordStream::Operation::fromatomfeed;
2              
3             our $VERSION = "4.0.23";
4              
5 2     2   658 use strict;
  2         5  
  2         51  
6 2     2   8 use warnings;
  2         4  
  2         48  
7              
8 2     2   10 use base qw(App::RecordStream::Operation);
  2         2  
  2         115  
9              
10 2     2   11 use App::RecordStream::Record;
  2         5  
  2         36  
11              
12 2     2   8 use App::RecordStream::OptionalRequire 'LWP::UserAgent';
  2         4  
  2         11  
13 2     2   10 use App::RecordStream::OptionalRequire 'XML::Twig';
  2         4  
  2         8  
14 2     2   9 BEGIN { App::RecordStream::OptionalRequire::require_done() }
15              
16             sub init
17             {
18             my $this = shift;
19             my $args = shift;
20              
21             my $follow = 1;
22             my $max = undef;
23              
24             my %options =
25             (
26             "follow!" => \$follow,
27             'max=s' => \$max,
28             );
29              
30             $this->parse_options($args, \%options);
31              
32             $this->{'COUNT'} = 0;
33             $this->{'FOLLOW'} = $follow;
34             $this->{'MAX'} = $max;
35             $this->{'URLS'} = $args;
36             }
37              
38             sub wants_input
39             {
40             return 0;
41             }
42              
43             sub stream_done
44             {
45             my ($this) = @_;
46              
47             my $ua = $this->make_user_agent();
48              
49             my $request = HTTP::Request->new();
50             $request->method('GET');
51              
52             my $twig_roots = { '/*/entry' => sub { $this->handle_entry_elem( @_ ) } };
53              
54             if ( $this->{'FOLLOW'} ) {
55             $twig_roots->{ '/*/link[ @rel="next" and @href ]' } = sub { $this->handle_link_elem( @_ ) };
56             }
57              
58             my $twig = XML::Twig->new(twig_roots => $twig_roots);
59              
60             while (my $url = shift @{ $this->{'URLS'} })
61             {
62             $this->update_current_filename($url);
63             $request->uri($url);
64             my $response = $ua->request($request);
65              
66             if (!$response->is_success)
67             {
68             warn "# $0 GET $url failed: " . $response->message;
69             $this->_set_exit_value(1);
70             next;
71             }
72              
73             $twig->parse( $response->content );
74             }
75             }
76              
77             sub handle_entry_elem {
78             my ($this, $twig, $entry_elem) = @_;
79              
80             $this->{'COUNT'}++;
81              
82             my $record = App::RecordStream::Record->new( $entry_elem->simplify );
83             $this->push_record($record);
84              
85             if (defined $this->{'MAX'} && $this->{'COUNT'} >= $this->{'MAX'}) {
86             $this->{'URLS'} = [];
87             $twig->finish_now;
88             }
89              
90             $twig->purge;
91             }
92              
93             # Follow the feed 'next' link if present. It is a proposed part
94             # of the standard - see http://www.ietf.org/rfc/rfc5005.txt
95             sub handle_link_elem {
96             my ($this, $twig, $link_elem) = @_;
97              
98             unshift @{ $this->{'URLS'} }, $link_elem->att('href');
99             $twig->purge;
100             }
101              
102             sub make_user_agent {
103             return LWP::UserAgent->new();
104             }
105              
106             sub usage
107             {
108             my $this = shift;
109              
110             my $options = [
111             [ '[no]follow', 'Follow atom feed next links (or not). Defaults on.'],
112             [ 'max=', 'Print at most entries and then exit.'],
113             ];
114              
115             my $args_string = $this->options_string($options);
116              
117             return <
118             Usage: recs-fromatomfeed []
119             __FORMAT_TEXT__
120             Produce records from atom feed entries.
121              
122             Recs from atom feed will get entries from paginated atom feeds and create
123             a record stream from the results. The keys of the record will be the fields
124             in the atom field entry. Recs from atom feed will follow the 'next' link in
125             a feed to retrieve all entries.
126             __FORMAT_TEXT__
127              
128             Arguments:
129             $args_string
130              
131             Examples:
132             Dump an entire feed
133             recs-fromatomfeed "http://my.xml.com"
134             Dumps just the first page of entries
135             recs-fromatomfeed --nofollow "http://my.xml.com"
136             Dumps just the first 10 entries
137             recs-fromatomfeed --max 10 "http://my.xml.com"
138             USAGE
139             }
140              
141             1;