File Coverage

blib/lib/Net/Safari.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Net::Safari;
2              
3             =head1 NAME
4              
5             Net::Safari - Wrapper for Safari Online Books API
6              
7             =head1 SYNOPSIS
8              
9             use Net::Safari
10            
11             my $ua = Net::Safari->new(token => 'YOUR_SAFARI_TOKEN');
12              
13             my $response = $ua->search();
14              
15             if($response->is_success()) {
16             print $response->as_string();
17             }
18             else {
19             print "Error:" . $response->message();
20             }
21              
22              
23             =head1 DESCRIPTION
24              
25             You can read more about Safari webservices here:
26             http://safari.oreilly.com/affiliates/?p=web_services
27              
28             =cut
29              
30              
31 13     13   669257 use strict;
  13         31  
  13         482  
32 13     13   6119 use XML::Simple;
  0            
  0            
33             use LWP::UserAgent;
34             use URI::Escape;
35             use Class::Accessor;
36             use Class::Fields;
37             use Data::Dumper;
38             use Net::Safari::Response;
39              
40             our $VERSION = 0.02;
41              
42             # hash of search operators and operator/term seperators
43             our %SEARCH_OPS = (
44             CODE => ' ',
45             NOTE => ' ',
46             TITLE => ' ',
47             BOOKTITLE => ' LIKE ',
48             CATEGORY => '=',
49             AUTHOR => '=',
50             ISBN => ' LIKE ',
51             PUBLDATE => ' ',
52             PUBLISHER => '=',
53             );
54              
55             use base qw(Class::Accessor Class::Fields);
56             use fields qw(token base_url ua);
57             Net::Safari->mk_accessors( Net::Safari->show_fields('Public') );
58              
59             =head1 METHODS
60              
61             =head2 new()
62              
63             $agent = Net::Safari->new( token => 'MY_SAFARI_TOKEN' );
64              
65             Construct a Safari object. Token seems optional.
66              
67             =cut
68              
69             sub new
70             {
71             my ($class, %args) = @_;
72              
73             my $self = bless ({}, ref ($class) || $class);
74              
75             $self->token($args{token});
76             $self->base_url("http://my.safaribooksonline.com/xmlapi/");
77             $self->ua( LWP::UserAgent->new( agent => "Net::Safari $VERSION", ) );
78              
79             return ($self);
80             }
81              
82             =head1 SEARCH
83              
84             =head2 BOOKTITLE
85            
86             $res = $ua->search( BOOKTITLE => 'samba' );
87              
88             Search book titles. This is currently broken in Safari.
89             See: http://safari.oreilly.com/xmlapi/?search=BOOKTITLE%20LIKE%20XML
90              
91             =head2 TITLE
92              
93             $res = $ua->search( TITLE => 'samba' );
94              
95             Searches section titles. Will sometimes return book titles if it can't find
96             any sections. I consider this a bug.
97            
98             =head2 ISBN
99              
100             $res = $ua->search( ISBN => '059600415X' );
101              
102             ISBN must be a complete ISBN, partial ISBN searches don't work.
103              
104             =head2 CODE
105              
106             $res = $ua->search( CODE => 'Test::More' );
107              
108             Search within code fragments. This is usually a lot more than programlistings. Code snippets that appear within a sentence are usually semanticly tagged as code. So you're just as likely to get text as you are to get program listings with this search.
109              
110             =head2 NOTE
111            
112             $res = $ua->search( NOTE => "web services" );
113              
114             The documentation says, "Finds matches within Tips and How-Tos." However the results seem to indicate hits in the content.
115              
116             =head2 CATEGORY
117              
118             $res = $ua->search( CATEGORY => "itbooks.security" );
119              
120             Search within a category. The list of categories is here:
121             http://safari.oreilly.com/affiliates/portals/safari/2004-07-30_Safari_Books_Category_Metadata_Abbreviations.doc
122              
123             =head2 AUTHOR
124              
125             $res = $ua->search( AUTHOR => 'Wall' );
126             $res = $ua->search( AUTHOR => 'Wall, Larry' );
127             $res = $ua->search( AUTHOR => 'Larry Wall' );
128              
129             Search by author.
130              
131             =head2 PUBLDATE
132              
133             $res = $ua->search( PUBLDATE => '> 20041001' );
134             $res = $ua->search( PUBLDATE => '< 20030101' );
135              
136             Search before or after a given publish date. The comparison operator, > or < is required.
137              
138             =head2 PUBLISHER
139              
140             $res = $ua->search( PUBLISHER => "O'Reilly" );
141              
142             Search by publisher.
143              
144             =cut
145              
146             sub search
147             {
148             my $self = shift;
149             my %args = @_;
150              
151             my $token = $self->token || "";
152              
153             my $url = $self->base_url ."?";
154             $url .= "token=$token&" if $token;
155             $url .= "search=" . $self->_build_search_string(%args);
156              
157             my $saf_resp = $self->ua->get($url);
158             my $response = Net::Safari::Response->new(xml => $saf_resp->content);
159              
160             return $response;
161             }
162              
163             sub _build_search_clause {
164             my $self = shift;
165             my $boolean = shift;
166             my $operator = shift;
167             my $terms = shift;
168              
169             return join ( ' $boolean ',
170             map { $operator . $self->_quote_search_term($_) }
171             @$terms
172             );
173             }
174              
175             sub _build_search_string {
176             my $self = shift;
177             my %args = @_;
178              
179             my $search_string;
180             my $terms;
181              
182             foreach my $op (keys(%SEARCH_OPS)) {
183             next unless $args{$op};
184              
185             if ($args{$op} && ( ref($args{$op}) eq "ARRAY" )) {
186             $terms = $args{$op};
187             }
188             else {
189             $terms = [$args{$op}];
190             }
191             $search_string .= $self->_build_search_clause(
192             "OR",
193             $op . $SEARCH_OPS{$op},
194             $terms,
195             );
196             }
197             my $uri = uri_escape($search_string);
198             return $uri;
199             }
200              
201             sub _quote_search_term {
202             my $self = shift;
203             my $term = shift;
204              
205             #$term =~ s/'//g;
206              
207             #$term = qq{"$term"} if $term =~ m/\s/;
208              
209             return $term;
210             }
211             =head1 BUGS
212              
213              
214              
215             =head1 SUPPORT
216              
217              
218              
219             =head1 AUTHOR
220              
221             Tony Stubblebine
222             cpan@tonystubblebine.com
223              
224              
225             =head1 COPYRIGHT
226              
227             This program is free software; you can redistribute
228             it and/or modify it under the same terms as Perl itself.
229              
230             The full text of the license can be found in the
231             LICENSE file included with this module.
232              
233              
234             =head1 SEE ALSO
235              
236              
237             =cut
238              
239              
240             1;
241             __END__