| 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; |