File Coverage

blib/lib/Net/Google/Search.pm
Criterion Covered Total %
statement 33 170 19.4
branch 0 80 0.0
condition 0 21 0.0
subroutine 11 25 44.0
pod 11 14 78.5
total 55 310 17.7


line stmt bran cond sub pod time code
1             {
2              
3             =head1 NAME
4              
5             Net::Google::Search - simple OOP-ish interface to the Google SOAP API for searching
6              
7             =head1 SYNOPSIS
8              
9             use Net::Google::Search;
10             my $search = Net::Google::Search->new(\%args);
11              
12             $search->query(qw(aaron cope));
13             map { print $_->title()."\n"; } @{$search->results()};
14              
15             # or
16              
17             foreach my $r (@{$search->response()}) {
18             print "Search time :".$r->searchTime()."\n";
19              
20             # returns an array ref of Result objects
21             # the same as the $search->results() method
22             map { print $_->URL()."\n"; } @{$r->resultElement()}
23             }
24              
25             =head1 DESCRIPTION
26              
27             Provides a simple OOP-ish interface to the Google SOAP API
28             for searching.
29              
30             This package is used by I.
31              
32             =head1 ENCODING
33              
34             According to the Google API docs :
35              
36             "In order to support searching documents in multiple languages
37             and character encodings the Google Web APIs perform all requests
38             and responses in the UTF-8 encoding. The parameters and
39             are required in client requests but their values are ignored.
40             Clients should encode all request data in UTF-8 and should expect
41             results to be in UTF-8."
42              
43             (This package takes care of setting both parameters in requests.)
44              
45             =cut
46              
47 1     1   4 use strict;
  1         2  
  1         36  
48              
49             package Net::Google::Search;
50 1     1   5 use base qw (Net::Google::tool);
  1         3  
  1         70  
51              
52 1     1   5 use Carp;
  1         2  
  1         54  
53 1     1   505 use Net::Google::Response;
  1         2  
  1         672  
54              
55             $Net::Google::Search::VERSION = '1.0';
56              
57 1     1   6 use constant RESTRICT_ENCODING => qw [ arabic gb big5 latin1 latin2 latin3 latin4 latin5 latin6 greek hebrew sjis euc-jp euc-kr cyrillic utf8 ];
  1         1  
  1         81  
58              
59 1     1   6 use constant RESTRICT_LANGUAGES => qw [ ar zh-CN zh-TW cs da nl en et fi fr de el iw hu is it ja ko lv lt no pt pl ro ru es sv tr ];
  1         2  
  1         190  
60              
61 1     1   7 use constant RESTRICT_COUNTRIES => qw [ AD AE AF AG AI AL AM AN AO AQ AR AS AT AU AW AZ BA BB BD BE BF BG BH BI BJ BM BN BO BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CN CO CR CU CV CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET EU FI FJ FK FM FO FR FX GA GD GE GF GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU ID IE IL IO IQ IR IS IT JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB LC LI LK LR LS LT LU LV LY MA MC MD MG MH MK ML MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI ML NO NP NR NU NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW PY QA RE RO RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR ST SV SY SZ TC TD TF TG TH TJ TK TM TN TO TP TR TT TV TW TZ UA UG UK UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT YU ZA ZM ZR ];
  1         2  
  1         192  
62              
63 1     1   6 use constant RESTRICT_TOPICS => qw [ unclesam linux mac bsd ];
  1         1  
  1         60  
64              
65 1     1   5 use constant WATCH => "__estimatedTotalResultsCount";
  1         2  
  1         1678  
66              
67             =head1 PACKAGE METHODS
68              
69             =cut
70              
71             =head2 __PACKAGE__->new(\%args)
72              
73             Valid arguments are :
74              
75             =over 4
76              
77             =item *
78              
79             B
80              
81             I. A Google API key.
82              
83             If none is provided then the key passed to the parent I
84             object will be used.
85              
86             =item *
87              
88             B
89              
90             I. First result number to display.
91              
92             Default is 0.
93              
94             =item *
95              
96             B
97              
98             I. Number of results to return.
99              
100             Default is 10.
101              
102             =item *
103              
104             B
105              
106             I or I. Language restrictions.
107              
108             =item *
109              
110             B
111              
112             I.
113              
114             =item *
115              
116             B
117              
118             I.
119              
120             =item *
121              
122             B
123              
124             I. A URL for proxy-ing HTTP requests.
125              
126             =item *
127              
128             B
129              
130             Valid options are:
131              
132             =over 4
133              
134             =item *
135              
136             I
137              
138             If true prints debugging information returned by SOAP::Lite
139             to STDERR
140              
141             =item *
142              
143             I.
144              
145             Your own subroutine for munging the debugging information
146             returned by SOAP::Lite.
147              
148             =back
149              
150             =back
151              
152             The object constructor in Net::Google 0.53, and earlier, expected
153             a I object as its first argument followed by
154             a hash reference of argument. Versions 0.6 and higher are backwards
155             compatible.
156              
157             Returns an object. Woot!
158              
159             =cut
160              
161             sub new {
162 1     1 1 2 my $pkg = shift;
163            
164 1         2 my $self = {};
165 1         2 bless $self,$pkg;
166              
167 1 0       3 if (! $self->init("search",@_)) {
168 0         0 return undef;
169             }
170              
171 0         0 return $self;
172             }
173              
174             sub init {
175 1     1 0 1 my $self = shift;
176              
177 1   0     7 my $args = $self->SUPER::init(@_)
178             || return 0;
179              
180             #
181              
182 0           $self->{'_query'} = [];
183 0           $self->{'_lr'} = [];
184 0           $self->{'_restrict'} = [];
185 0           $self->{'_safe'} = 0;
186 0           $self->{'_filter'} = 0;
187 0           $self->{'_starts_at'} = 0;
188 0           $self->{'_max_results'} = 10;
189              
190 0   0       $self->starts_at(($args->{'starts_at'} || 0));
191 0   0       $self->max_results(($args->{'max_results'}) || 10);
192              
193 0 0         if ($args->{lr}) {
194 0 0         defined($self->lr( ((ref($args->{'lr'}) eq "ARRAY") ? @{$args->{'lr'}} : $args->{'lr'}) )) || return 0;
  0 0          
195             }
196              
197 0 0         if ($args->{restrict}) {
198 0 0         defined($self->restrict( ((ref($args->{'restrict'}) eq "ARRAY") ? @{$args->{'restrict'}} : $args->{'restrict'}) )) || return 0;
  0 0          
199             }
200              
201 0 0         if (defined($args->{'filter'})) {
202 0 0         defined($self->filter($args->{'filter'})) || return 0;
203             }
204              
205 0 0         if (defined($args->{'safe'})) {
206 0 0         defined($self->safe($args->{'safe'})) || return 0;
207             }
208              
209 0 0         if (defined($args->{'starts_at'})) {
210 0 0         defined($self->starts_at($args->{'starts_at'})) || return 0;
211             }
212              
213 0 0         if (defined($args->{'max_results'})) {
214 0 0         defined($self->max_results($args->{'max_results'})) || return 0;
215             }
216              
217 0           return 1;
218             }
219              
220             =head1 OBJECT METHODS
221              
222             =cut
223              
224             sub ie {
225 0     0 0   carp "The 'ie' method has been deprecated";
226             }
227              
228             sub oe {
229 0     0 0   carp "The 'oe' method has been deprecated";
230             }
231              
232             =head2 $obj->key($string)
233              
234             Get/set the Google API key for this object.
235              
236             =cut
237              
238             # Defined in Net::Google::tool
239              
240             =head2 $obj->http_proxy($url)
241              
242             Get/set the HTTP proxy for this object.
243              
244             Returns a string.
245              
246             =cut
247              
248             # Defined in Net::Google::tool
249              
250             =head2 $obj->query(@data)
251              
252             If the first item in I<@data> is empty, then any existing
253             I data will be removed before the new data is added.
254              
255             Returns a string of words separated by white space. Returns
256             undef if there was an error.
257              
258             =cut
259              
260             sub query {
261 0     0 1   my $self = shift;
262 0           my @data = @_;
263              
264 0 0 0       if ((scalar(@data) > 1) && ($data[0] eq "")) {
265 0           $self->{'_query'} = [];
266             }
267              
268 0 0         if (@data) {
269 0           push @{$self->{'_query'}}, @data;
  0            
270             }
271              
272 0           return join(" ",@{$self->{'_query'}});
  0            
273             }
274              
275             =head2 $obj->starts_at($at)
276              
277             Returns an int. Default is 0.
278              
279             Returns undef if there was an error.
280              
281             =cut
282              
283             sub starts_at {
284 0     0 1   my $self = shift;
285 0           my $at = shift;
286              
287 0 0         if (defined($at)) {
288 0           $self->{'_starts_at'} = $at;
289             }
290              
291 0           return $self->{'_starts_at'};
292             }
293              
294             =head2 $obj->max_results($max)
295              
296             The default set by Google is 10 results. However, if
297             you pass a number greater than 10 the I method
298             will make multiple calls to Google API.
299              
300             Returns an int.
301              
302             Returns undef if there was an error.
303              
304             =cut
305              
306             sub max_results {
307 0     0 1   my $self = shift;
308 0           my $max = shift;
309              
310 0 0         if (defined($max)) {
311              
312 0 0         if (int($max) < 1) {
313 0           carp "'$max' must be a int greater than 0";
314 0           $max = 1;
315             }
316              
317 0           $self->{'_max_results'} = $max;
318             }
319              
320 0           return $self->{'_max_results'};
321             }
322              
323             =head2 $obj->restrict(@types)
324              
325             If the first item in I<@types> is empty, then any existing
326             I data will be removed before the new data is
327             added.
328              
329             Returns a string. Returns undef if there was an error.
330              
331             =cut
332              
333             sub restrict {
334 0     0 1   my $self = shift;
335 0           my @types = @_;
336              
337 0 0 0       if ((scalar(@types) > 1) && ($types[0] eq "")) {
338 0           $self->{'_restrict'} = [];
339 0           shift @types;
340             }
341              
342 0 0         if (@types) {
343 0           push @{$self->{'_restrict'}},@types;
  0            
344             }
345            
346 0           return join("",@{$self->{'_restrict'}});
  0            
347             }
348              
349             =head2 $obj->filter($bool)
350              
351             Returns true or false. Returns undef if there was an error.
352              
353             =cut
354              
355             sub filter {
356 0     0 1   my $self = shift;
357 0           my $bool = shift;
358              
359            
360 0 0         if (defined($bool)) {
361 0 0         $self->{'_filter'} = ($bool) ? 1 : 0;
362             }
363              
364 0           return $self->{'_filter'};
365             }
366              
367             =head2 $obj->safe($bool)
368              
369             Returns true or false. Returns undef if there was an error.
370              
371             =cut
372              
373             sub safe {
374 0     0 1   my $self = shift;
375 0           my $bool = shift;
376              
377 0 0         if (defined($bool)) {
378 0 0         $self->{'_safe'} = ($bool) ? 1 : 0;
379             }
380              
381 0           return $self->{'_safe'};
382             }
383              
384             =head2 $obj->lr(@lang)
385              
386             Language restriction.
387              
388             If the first item in I<@lang> is empty, then any existing
389             I data will be removed before the new data is added.
390              
391             Returns a string. Returns undef if there was an error.
392              
393             =cut
394              
395             sub lr {
396 0     0 1   my $self = shift;
397 0           my @lang = @_;
398              
399 0 0 0       if ((scalar(@lang) > 1) && ($lang[0] eq "")) {
400 0           $self->{'_lr'} = [];
401 0           shift @lang;
402             }
403              
404 0 0         if (@lang) {
405 0           push @{$self->{'_lr'}},@lang;
  0            
406             }
407            
408 0           return join("",@{$self->{'_lr'}});
  0            
409             }
410              
411             =head2 $obj->return_estimatedTotal($bool)
412              
413             Toggle whether or not to return all the results defined by the
414             '__estimatedTotalResultsCount' key.
415              
416             Default is false.
417              
418             =cut
419              
420             sub return_estimatedTotal {
421 0     0 1   my $self = shift;
422 0           my $bool = shift;
423              
424 0 0         if (defined($bool)) {
425 0 0         $self->{'__estimatedTotal'} = ($bool) ? 1 : 0;
426             }
427              
428 0           return $self->{'__estimatedTotal'};
429             }
430              
431             =head2 $obj->response()
432              
433             Returns an array ref of I objects,
434             from which the search response metadata as well as the
435             search results may be obtained.
436              
437             Use this method if you would like to receive a full response
438             as documented in the Google Web APIs Reference (the whole
439             of section 3).
440              
441             =cut
442              
443             sub response {
444 0     0 1   my $self = shift;
445              
446 0 0 0       if (defined($self->{'__state'}) &&
447             ($self->{'__state'} eq $self->_state())) {
448              
449 0           return $self->{'__response'};
450             }
451              
452 0           $self->{'__response'} = [];
453              
454 0           my $start_at = $self->starts_at();
455 0           my $to_fetch = $self->max_results();
456              
457 0           while ($to_fetch > 0) {
458 0 0         my $count = ($to_fetch > 10) ? 10 : $to_fetch;
459              
460             # Net::Google::Response will carp
461             # if there's a problem so we just
462             # move on if there's a problem.
463              
464 0           my $res = $self->_response($start_at,$count);
465              
466 0 0         if (! defined($res)) {
467 0           last;
468             }
469              
470             #
471              
472 0 0 0       if ((! $self->return_estimatedTotal()) &&
473             ($start_at >= $res->{__endIndex})) {
474              
475 0           last;
476             }
477              
478             #
479              
480 0 0         if ($self->return_estimatedTotal()) {
481              
482 0 0         if (($self->{'__possible'} + scalar(@{$res->resultElements()})) > $res->{'__estimatedTotalResultsCount'}) {
  0            
483              
484 0           my $justright = int($res->{'__estimatedTotalResultsCount'} - $self->{'__possible'});
485 0           @{$res->resultElements()} = @{$res->resultElements()}[0..($justright -1)];
  0            
  0            
486              
487 0           push @{$self->{'__response'}} , $res;
  0            
488 0           last;
489             }
490              
491 0           $self->{'__possible'} += scalar(@{$res->resultElements()});
  0            
492              
493 0 0         if (($self->{'__possible'} + scalar(@{$res->resultElements()})) == $res->{'__estimatedTotalResultsCount'}) {
  0            
494 0           last;
495             }
496             }
497              
498             #
499              
500 0           push @{$self->{'__response'}}, $res;
  0            
501              
502 0           $start_at += 10;
503 0           $to_fetch -= 10;
504             }
505              
506 0           return $self->{'__response'};
507             }
508              
509             =head2 $obj->results()
510              
511             Returns an array ref of I objects (see docs for
512             I), each of which represents one
513             result from the search.
514              
515             Use this method if you don't care about the search response
516             metadata, and only care about the resources that are found
517             by the search, as described in section 3.2 of the Google Web
518             APIs Reference.
519              
520             =cut
521              
522             sub results {
523 0     0 1   my $self = shift;
524 0           return [ map { @{ $_->resultElements() } } @{$self->response()} ];
  0            
  0            
  0            
525             }
526              
527             =head2 $obj->queries_exhausted()
528              
529             Returns true or false depending on whether or not the current in-memory
530             B has exhausted the Google API 1000 query limit.
531              
532             =cut
533              
534             # Defined in ::tool
535              
536             sub _response {
537 0     0     my $self = shift;
538 0           my $first = shift;
539 0           my $count = shift;
540              
541 0           $self->_queries(1);
542              
543 0 0         my $response =
    0          
544             $self->{'_service'}
545             ->doGoogleSearch(
546             $self->key(),
547             $self->query(),
548             $first,
549             $count,
550             SOAP::Data->type(boolean=>($self->filter()
551             ? "true" : "false")),
552             # I don't think I should need to
553             # do this but SOAP::Lite doesn't
554             # appear to be doing to right thing
555             # see also : RT bug #6167
556             # ? 1 : 0)),
557             $self->restrict(),
558             SOAP::Data->type(boolean=>($self->safe()
559             ? "true" : "false")),
560             # see above
561             # ? 1 : 0)),
562             $self->lr(),
563             # input encoding
564             undef,
565             # output encoding
566             undef,
567             );
568              
569 0 0         if (! $response) {
570 0           return undef;
571             }
572              
573 0           $self->{'__state'} = $self->_state();
574 0           return Net::Google::Response->new($response);
575             }
576              
577             sub _state {
578 0     0     my $self = shift;
579 0           my $state = undef;
580 0           map {$state .= $self->$_()} qw (query lr restrict safe filter starts_at max_results);
  0            
581 0           return $state;
582             }
583              
584             =head1 VERSION
585              
586             1.0
587              
588             =head1 DATE
589              
590             $Date: 2005/03/26 20:49:03 $
591              
592             =head1 AUTHOR
593              
594             Aaron Straup Cope
595              
596             =head1 CONTRIBUTORS
597              
598             Marc Hedlund
599              
600             =head1 TO DO
601              
602             =over 4
603              
604             =item *
605              
606             Add hooks to manage boolean searches and speacial query strings.
607              
608             =back
609              
610             =head1 SEE ALSO
611              
612             L
613              
614             =head1 LICENSE
615              
616             Copyright (c) 2002-2005, Aaron Straup Cope. All Rights Reserved.
617              
618             This is free software, you may use it and distribute it under
619             the same terms as Perl itself.
620              
621             =cut
622              
623             return 1;
624              
625             }