blib/lib/WWW/Google/API/Base.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 19 | 21 | 90.4 |
branch | n/a | ||
condition | n/a | ||
subroutine | 7 | 7 | 100.0 |
pod | n/a | ||
total | 26 | 28 | 92.8 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package WWW::Google::API::Base; | ||||||
2 | |||||||
3 | 1 | 1 | 58153 | use strict; | |||
1 | 2 | ||||||
1 | 41 | ||||||
4 | 1 | 1 | 5 | use warnings; | |||
1 | 2 | ||||||
1 | 602 | ||||||
5 | |||||||
6 | =head1 NAME | ||||||
7 | |||||||
8 | WWW::Google::API::Base - Perl client to the Google Base API C<< |
||||||
9 | |||||||
10 | =head1 VERSION | ||||||
11 | |||||||
12 | version 0.001 | ||||||
13 | |||||||
14 | $Id$ | ||||||
15 | |||||||
16 | =head1 SYNOPSIS | ||||||
17 | |||||||
18 | use WWW::Google::API::Base; | ||||||
19 | |||||||
20 | my $file_conf = LoadFile($ENV{HOME}.'/.gapi'); | ||||||
21 | |||||||
22 | my $api_key = $ENV{gapi_key}; | ||||||
23 | my $api_user = $ENV{gapi_user}; | ||||||
24 | my $api_pass = $ENV{gapi_pass}; | ||||||
25 | |||||||
26 | my $gbase = WWW::Google::API::Base->new( { auth_type => 'ProgrammaticLogin', | ||||||
27 | api_key => $api_key, | ||||||
28 | api_user => $api_user, | ||||||
29 | api_pass => $api_pass }, | ||||||
30 | { } ); | ||||||
31 | |||||||
32 | =head1 METHODS | ||||||
33 | |||||||
34 | =cut | ||||||
35 | |||||||
36 | our $VERSION = '0.001'; | ||||||
37 | |||||||
38 | 1 | 1 | 8 | use base qw(Class::Accessor); | |||
1 | 2 | ||||||
1 | 1097 | ||||||
39 | |||||||
40 | 1 | 1 | 3506 | use HTTP::Request; | |||
1 | 25166 | ||||||
1 | 49 | ||||||
41 | 1 | 1 | 1069 | use LWP::UserAgent; | |||
1 | 26444 | ||||||
1 | 37 | ||||||
42 | 1 | 1 | 676 | use WWW::Google::API; | |||
1 | 3 | ||||||
1 | 8 | ||||||
43 | 1 | 1 | 427 | use XML::Atom::Entry; | |||
0 | |||||||
0 | |||||||
44 | use XML::Atom::Util qw( nodelist ); | ||||||
45 | |||||||
46 | __PACKAGE__->mk_ro_accessors(qw(namespaces)); | ||||||
47 | __PACKAGE__->mk_accessors(qw(client)); | ||||||
48 | |||||||
49 | sub new { | ||||||
50 | my $class = shift; | ||||||
51 | |||||||
52 | my $client; | ||||||
53 | eval { | ||||||
54 | $client = WWW::Google::API->new('gbase', @_); | ||||||
55 | }; | ||||||
56 | if ($@) { | ||||||
57 | my $e = $@; | ||||||
58 | warn $e; | ||||||
59 | } | ||||||
60 | my $self = { client => $client, | ||||||
61 | namespaces => { | ||||||
62 | gm => XML::Atom::Namespace->new( gm => 'http://base.google.com/ns-metadata/1.0'), | ||||||
63 | g => XML::Atom::Namespace->new( g => 'http://base.google.com/ns/1.0' ), | ||||||
64 | batch => XML::Atom::Namespace->new( batch => 'http://schemas.google.com/gdata/batch' ), | ||||||
65 | } | ||||||
66 | }; | ||||||
67 | |||||||
68 | bless($self, $class); | ||||||
69 | return $self; | ||||||
70 | } | ||||||
71 | |||||||
72 | sub _load_item_type { | ||||||
73 | my $self = shift; | ||||||
74 | my $type = shift; | ||||||
75 | |||||||
76 | |||||||
77 | my $ua = LWP::UserAgent->new( agent => 'WWW::Google::API' ); | ||||||
78 | |||||||
79 | my $response = $ua->get($type); | ||||||
80 | |||||||
81 | die $response->status_line unless $response->is_success; | ||||||
82 | |||||||
83 | my $entry = XML::Atom::Entry->new(\$response->content); | ||||||
84 | |||||||
85 | $type = $entry->get($self->{namespaces}{gm}, 'item_type'); | ||||||
86 | my @attributes = nodelist($entry->elem, $self->{namespaces}{gm}{uri}, 'attribute'); | ||||||
87 | my $attribute_types; | ||||||
88 | foreach my $attribute (@attributes) { | ||||||
89 | my $name = $attribute->getAttribute('name'); | ||||||
90 | my $type = $attribute->getAttribute('type'); | ||||||
91 | $name =~ s/\s/_/g; | ||||||
92 | $attribute_types->{$name} = $type; | ||||||
93 | } | ||||||
94 | $attribute_types->{'label'} = 'text'; | ||||||
95 | return $type, $attribute_types; | ||||||
96 | } | ||||||
97 | |||||||
98 | =head2 insert | ||||||
99 | |||||||
100 | $insert_entry = $gbase->insert( | ||||||
101 | 'http://www.google.com/base/feeds/itemtypes/en_US/Recipes', | ||||||
102 | { -title => 'He Jingxian\'s chicken', | ||||||
103 | -content => " Delectable Sichuan specialty ", |
||||||
104 | -link => [ | ||||||
105 | { rel => 'alternate', | ||||||
106 | type => 'text/html', | ||||||
107 | href => 'http://localhost/uniqueid' | ||||||
108 | }, | ||||||
109 | ], | ||||||
110 | cooking_time => 30, | ||||||
111 | label => [qw(foo bar baz)], | ||||||
112 | main_ingredient => [qw(chicken chili peanuts)], | ||||||
113 | servings => 5, | ||||||
114 | }, | ||||||
115 | ); | ||||||
116 | |||||||
117 | $new_id = $insert_entry->id; | ||||||
118 | |||||||
119 | =cut | ||||||
120 | |||||||
121 | sub insert { | ||||||
122 | my $self = shift; | ||||||
123 | my $item_type = shift; | ||||||
124 | my $item_parts = shift; | ||||||
125 | |||||||
126 | my ($type, $gpart_types) = $self->_load_item_type($item_type); | ||||||
127 | |||||||
128 | $self->client->ua->default_header('content-type', 'application/atom+xml'); | ||||||
129 | |||||||
130 | my $xml = < | ||||||
131 | |||||||
132 | | ||||||
133 | xmlns:g='http://base.google.com/ns/1.0'> | ||||||
134 | |
||||||
135 | |
||||||
136 | EOF | ||||||
137 | |||||||
138 | for my $key (keys %$item_parts) { | ||||||
139 | if ($key =~ /^-/) { | ||||||
140 | if ($key eq '-content') { | ||||||
141 | $xml .= " |
||||||
142 | $xml .= "$item_parts->{$key}\n"; | ||||||
143 | $xml .= "\n"; | ||||||
144 | } elsif ($key eq '-link') { | ||||||
145 | if (ref $item_parts->{$key} eq 'ARRAY') { | ||||||
146 | foreach (@{$item_parts->{$key}}) { | ||||||
147 | $xml .= "\n"; | ||||||
148 | } | ||||||
149 | } else { | ||||||
150 | $xml .= "\n"; | ||||||
151 | } | ||||||
152 | } elsif (ref $item_parts->{$key} eq 'ARRAY') { | ||||||
153 | for my $item (@{$item_parts->{$key}}) { | ||||||
154 | $key =~ s/^-//; | ||||||
155 | $xml .= "<$key type='text'>$item$key>\n"; | ||||||
156 | } | ||||||
157 | } else { | ||||||
158 | $key =~ s/^-//; | ||||||
159 | $xml .= "<$key type='text'>".$item_parts->{"-$key"}."$key>\n"; | ||||||
160 | } | ||||||
161 | } else { | ||||||
162 | if (ref $item_parts->{$key} eq 'ARRAY') { | ||||||
163 | for my $item (@{$item_parts->{$key}}) { | ||||||
164 | $xml .= " |
||||||
165 | } | ||||||
166 | } else { | ||||||
167 | $xml .= " |
||||||
168 | } | ||||||
169 | } | ||||||
170 | } | ||||||
171 | $xml .= "\n"; | ||||||
172 | |||||||
173 | my $insert_request = HTTP::Request->new( POST => 'http://www.google.com/base/feeds/items', | ||||||
174 | $self->client->ua->default_headers, | ||||||
175 | $xml); | ||||||
176 | my $response; | ||||||
177 | eval { | ||||||
178 | $response = $self->client->do($insert_request); | ||||||
179 | }; | ||||||
180 | if ($@) { | ||||||
181 | my $error = $@; | ||||||
182 | die $error; | ||||||
183 | } | ||||||
184 | |||||||
185 | my $atom = $response->content; | ||||||
186 | |||||||
187 | my $entry = XML::Atom::Entry->new(\$atom); | ||||||
188 | |||||||
189 | return $entry | ||||||
190 | } | ||||||
191 | |||||||
192 | =head2 update | ||||||
193 | |||||||
194 | $update_entry = $gbase->update( | ||||||
195 | $new_id, | ||||||
196 | { -title => 'He Jingxian\'s chicken', | ||||||
197 | -content => " Delectable Sichuan specialty ", |
||||||
198 | -link => [ | ||||||
199 | { rel => 'alternate', | ||||||
200 | type => 'text/html', | ||||||
201 | href => 'http://localhost/uniqueid' | ||||||
202 | }, | ||||||
203 | ], | ||||||
204 | cooking_time => 60, | ||||||
205 | label => [qw(fio bir biz)], | ||||||
206 | main_ingredient => [qw(chicken chili peanuts)], | ||||||
207 | servings => 15, | ||||||
208 | }, | ||||||
209 | ); | ||||||
210 | |||||||
211 | =cut | ||||||
212 | |||||||
213 | sub update { | ||||||
214 | my $self = shift; | ||||||
215 | my $item_id = shift; | ||||||
216 | my $item_parts = shift; | ||||||
217 | |||||||
218 | my $item = $self->select($item_id); | ||||||
219 | |||||||
220 | my $item_type = 'http://www.google.com/base/feeds/itemtypes/en_US/'; | ||||||
221 | $item_type .= $item->get($self->{namespaces}{g}, 'item_type'); | ||||||
222 | |||||||
223 | my ($type, $gpart_types) = $self->_load_item_type($item_type); | ||||||
224 | |||||||
225 | $self->client->ua->default_header('content-type', 'application/atom+xml'); | ||||||
226 | |||||||
227 | my $xml = < | ||||||
228 | |||||||
229 | | ||||||
230 | xmlns:g='http://base.google.com/ns/1.0'> | ||||||
231 | |
||||||
232 | |
||||||
233 | EOF | ||||||
234 | |||||||
235 | for my $key (keys %$item_parts) { | ||||||
236 | if ($key =~ /^-/) { | ||||||
237 | if ($key eq '-content') { | ||||||
238 | $xml .= " |
||||||
239 | $xml .= "$item_parts->{$key}\n"; | ||||||
240 | $xml .= "\n"; | ||||||
241 | } elsif ($key eq '-link') { | ||||||
242 | if (ref $item_parts->{$key} eq 'ARRAY') { | ||||||
243 | foreach (@{$item_parts->{$key}}) { | ||||||
244 | $xml .= "\n"; | ||||||
245 | } | ||||||
246 | } else { | ||||||
247 | $xml .= "\n"; | ||||||
248 | } | ||||||
249 | } elsif (ref $item_parts->{$key} eq 'ARRAY') { | ||||||
250 | for my $item (@{$item_parts->{$key}}) { | ||||||
251 | $key =~ s/^-//; | ||||||
252 | $xml .= "<$key type='text'>$item$key>\n"; | ||||||
253 | } | ||||||
254 | } else { | ||||||
255 | $key =~ s/^-//; | ||||||
256 | $xml .= "<$key type='text'>".$item_parts->{"-$key"}."$key>\n"; | ||||||
257 | } | ||||||
258 | |||||||
259 | } else { | ||||||
260 | if (ref $item_parts->{$key} eq 'ARRAY') { | ||||||
261 | for my $item (@{$item_parts->{$key}}) { | ||||||
262 | $xml .= " |
||||||
263 | } | ||||||
264 | } else { | ||||||
265 | $xml .= " |
||||||
266 | } | ||||||
267 | } | ||||||
268 | } | ||||||
269 | $xml .= "\n"; | ||||||
270 | |||||||
271 | my $update_request = HTTP::Request->new( PUT => $item_id, | ||||||
272 | $self->client->ua->default_headers, | ||||||
273 | $xml); | ||||||
274 | my $response; | ||||||
275 | eval { | ||||||
276 | $response = $self->client->do($update_request); | ||||||
277 | }; | ||||||
278 | if ($@) { | ||||||
279 | my $error = $@; | ||||||
280 | die $error; | ||||||
281 | } | ||||||
282 | |||||||
283 | my $atom = $response->content; | ||||||
284 | |||||||
285 | my $entry = XML::Atom::Entry->new(\$atom); | ||||||
286 | |||||||
287 | return $entry; | ||||||
288 | } | ||||||
289 | |||||||
290 | =head2 delete | ||||||
291 | |||||||
292 | my $delete_response; | ||||||
293 | eval { | ||||||
294 | $delete_response =$gbase->delete($new_id); | ||||||
295 | }; | ||||||
296 | if ($@) { | ||||||
297 | my $e = $@; | ||||||
298 | die $e->status_line; # HTTP::Response | ||||||
299 | } | ||||||
300 | |||||||
301 | die "Successfully deleted if $delete_response->code == 200; # HTTP::Response | ||||||
302 | |||||||
303 | =cut | ||||||
304 | |||||||
305 | sub delete { | ||||||
306 | my $self = shift; | ||||||
307 | my $item_id = shift; | ||||||
308 | my $delete_request = HTTP::Request->new( DELETE => $item_id, | ||||||
309 | $self->client->ua->default_headers ); | ||||||
310 | my $response; | ||||||
311 | eval { | ||||||
312 | $response = $self->client->do($delete_request); | ||||||
313 | }; | ||||||
314 | if ($@) { | ||||||
315 | my $error = $@; | ||||||
316 | die $error; | ||||||
317 | } | ||||||
318 | return $response; | ||||||
319 | } | ||||||
320 | |||||||
321 | =head2 select | ||||||
322 | |||||||
323 | Currently only supports querying by id | ||||||
324 | |||||||
325 | my $select_inserted_entry; | ||||||
326 | eval { | ||||||
327 | $select_inserted_entry =$gbase->select($new_id); | ||||||
328 | }; | ||||||
329 | if ($@) { | ||||||
330 | my $e = $@; | ||||||
331 | die $e->status_line; # HTTP::Response | ||||||
332 | } | ||||||
333 | |||||||
334 | =cut | ||||||
335 | |||||||
336 | sub select { | ||||||
337 | my $self = shift; | ||||||
338 | my $item_id = shift; | ||||||
339 | |||||||
340 | my $select_request = HTTP::Request->new( GET => $item_id, | ||||||
341 | $self->client->ua->default_headers ); | ||||||
342 | my $response; | ||||||
343 | eval { | ||||||
344 | $response = $self->client->do($select_request); | ||||||
345 | }; | ||||||
346 | if ($@) { | ||||||
347 | my $error = $@; | ||||||
348 | die $error; | ||||||
349 | } | ||||||
350 | |||||||
351 | my $atom = $response->content; | ||||||
352 | |||||||
353 | my $entry = XML::Atom::Entry->new(\$atom); | ||||||
354 | |||||||
355 | return $entry; | ||||||
356 | } | ||||||
357 | |||||||
358 | 1; |