File Coverage

blib/lib/WWW/OhNoRobotCom/Search.pm
Criterion Covered Total %
statement 33 98 33.6
branch 1 24 4.1
condition 2 26 7.6
subroutine 9 14 64.2
pod 2 2 100.0
total 47 164 28.6


line stmt bran cond sub pod time code
1             package WWW::OhNoRobotCom::Search;
2              
3 1     1   146231 use warnings;
  1         4  
  1         49  
4 1     1   7 use strict;
  1         3  
  1         69  
5              
6             our $VERSION = '0.003';
7              
8 1     1   5 use Carp;
  1         8  
  1         78  
9 1     1   5 use URI;
  1         2  
  1         34  
10 1     1   6 use LWP::UserAgent;
  1         2  
  1         25  
11 1     1   6 use HTML::TokeParser::Simple;
  1         2  
  1         53  
12 1     1   7 use HTML::Entities;
  1         2  
  1         71  
13 1     1   6 use base 'Class::Accessor::Grouped';
  1         2  
  1         1338  
14             __PACKAGE__->mk_group_accessors( simple =>
15             qw/ua
16             error
17             results
18             /);
19              
20             sub new {
21 1     1 1 196 my $class = shift;
22 1 50       5 croak "Must have even number of arguments to new()"
23             if @_ & 1;
24              
25 1         3 my %args = @_;
26 1         5 $args{ +lc } = delete $args{ $_ } for keys %args;
27              
28 1   50     9 $args{timeout} ||= 30;
29 1   33     14 $args{ua} ||= LWP::UserAgent->new(
30             timeout => $args{timeout},
31             agent => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12)'
32             .' Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12',
33             );
34              
35 1         57469 my $self = bless {}, $class;
36 1         14 $self->ua( $args{ua} );
37              
38 1         518 return $self;
39             }
40              
41             sub search {
42 0     0 1   my $self = shift;
43 0           my %args = ( term => shift );
44              
45 0 0         if ( @_ ) {
46 0           %args = ( @_, %args );
47             }
48              
49 0           $args{ +lc } = delete $args{ $_ } for keys %args;
50              
51 0           my $valid_include = $self->_make_valid_include;
52 0           %args = (
53             comic_id => '',
54             include => [ keys %$valid_include ],
55             max_results => 10,
56              
57             %args,
58             );
59              
60 0           $self->$_(undef) for qw(results error);
61              
62 0 0         if ( grep { not exists $valid_include->{$_} } @{ $args{include} } ) {
  0            
  0            
63 0           carp "Invalid include parameter was specified";
64             }
65              
66 0 0 0       return $self->_set_error('No term was given')
67             unless defined $args{term} and length $args{term};
68              
69 0           my %request_args = (
70             ( $args{lucky} ? ( lucky => 'Let the Robot Decide!' ) : () ),
71             's' => $args{term},
72             comic => $args{comic_id},
73 0 0         map( { $valid_include->{$_} => 1 } @{ delete $args{include} } ),
  0            
74             );
75              
76 0           my $results_ref = $self->_fetch_results(
77             \%request_args,
78             @args{ qw(lucky max_results) },
79             );
80              
81 0           return $self->results( $results_ref );
82             }
83              
84             sub _fetch_results {
85 0     0     my ( $self, $request_args_ref, $is_lucky, $max_results ) = @_;
86              
87 0           my %results;
88              
89 0           my $ua = $self->ua;
90 0           $ua->requests_redirectable([]);
91              
92 0           my $uri = URI->new('http://www.ohnorobot.com/index.pl');
93 0           $uri->query_form( %$request_args_ref );
94 0           my $response = $ua->get( $uri, );
95              
96 0 0 0       if ( $is_lucky and $response->code == 302 ) {
    0          
97 0           return URI->new( $response->header('Location') );
98             }
99             elsif ( $response->is_success ) {
100 0           my $results_ref = $self->_parse_results( $response->content );
101              
102 0 0         return unless $results_ref;
103              
104 0           %results = %$results_ref;
105              
106 0           my $has_results = scalar keys %$results_ref;
107 0           my $result_count = $has_results;
108              
109 0   0       while ( $max_results >= $result_count and $has_results ) {
110 0           ++$request_args_ref->{p}; # p for page DUH!
111 0           $uri->query_form( %$request_args_ref );
112              
113 0           my $response = $ua->get( $uri );
114 0 0         unless ( $response->is_success ) {
115 0           $result_count += 10;
116 0           next;
117             }
118              
119 0           my %new_results = %{ $self->_parse_results($response->content) };
  0            
120 0           %results = (
121             %results,
122             %new_results,
123             );
124 0           $has_results = keys %new_results;
125 0           $result_count += $has_results;
126             }
127             }
128             else {
129 0           return $self->_set_error('Network error: ' . $response->status_line);
130             }
131              
132 0 0 0       return $self->_set_error('Nothing was found')
133             if $is_lucky and not %results;
134 0           return \%results;
135             }
136              
137             sub _parse_results {
138 0     0     my ( $self, $content ) = @_;
139              
140 0           my $parser = HTML::TokeParser::Simple->new( \$content );
141              
142 0           my %results;
143 0           my $get_link = 0;
144 0           my $current_link;
145 0           while ( my $t = $parser->get_token ) {
146 0 0 0       if ( $t->is_start_tag('a')
    0 0        
      0        
147             and defined $t->get_attr('class')
148             and $t->get_attr('class') eq 'searchlink'
149             ) {
150 0           $get_link = 1;
151 0           $current_link = $t->get_attr('href');
152             }
153             elsif ( $get_link and $t->is_text ) {
154 0           $results{ $current_link } = decode_entities($t->as_is);
155 0           $results{ $current_link } =~ s/^\s+|\s+$//g;
156 0           $results{ $current_link } =~ s/\s+/ /g;
157 0           $get_link = 0;
158             }
159             }
160 0           return \%results;
161             }
162              
163             sub _make_valid_include {
164             return {
165 0     0     all_text => 'b',
166             speakers => 'n',
167             scene => 'd',
168             sound => 'e',
169             link => 't',
170             meta => 'm',
171             };
172             }
173              
174             sub _set_error {
175 0     0     my ( $self, $error ) = @_;
176 0           $self->error( $error );
177 0           return;
178             }
179              
180              
181             1;
182              
183             __END__