File Coverage

blib/lib/WWW/Tumblr.pm
Criterion Covered Total %
statement 85 97 87.6
branch 9 24 37.5
condition n/a
subroutine 19 21 90.4
pod 0 4 0.0
total 113 146 77.4


line stmt bran cond sub pod time code
1             package WWW::Tumblr;
2              
3 16     16   23707 use strict;
  16         22  
  16         407  
4 16     16   57 use warnings;
  16         17  
  16         933  
5              
6             our $VERSION = '5.00_04';
7              
8             =pod
9              
10             =head1 NAME
11              
12             WWW::Tumblr - Perl bindings for the Tumblr API
13              
14             =head1 VERSION
15              
16             5.00_04 (experimental release)
17              
18             =head1 SYNOPSIS
19              
20             my $t = WWW::Tumblr->new(
21             consumer_key => $consumer_key,
22             secret_key => $secret_key,
23             token => $token,
24             token_secret => $token_secret,
25             );
26            
27             my $blog = $t->blog('perlapi.tumblr.com');
28              
29             print Dumper $blog->info;
30              
31             =head1 DESCRIPTION
32              
33             This module makes use of some sort of the same models as the upstream API,
34             meaning that you will have User, Blog and Tagged methods:
35              
36             my $t = WWW::Tumblr->new(
37             consumer_key => $consumer_key,
38             secret_key => $secret_key,
39             token => $token,
40             token_secret => $token_secret,
41             );
42              
43             # Once you have a WWW::Tumblr object, you can get a WWW::Tumblr::Blog object
44             # by calling the blog() method from the former object:
45            
46             my $blog = $t->blog('perlapi.tumblr.com');
47            
48             # And then just use WWW::Tumblr::Blog methods from it:
49             if ( my $post = $blog->post( type => 'text', body => 'Hell yeah, son!' ) ) {
50             say "I have published post id: " . $post->{id};
51             } else {
52             print STDERR Dumper $blog->error;
53             die "I couldn't post it :(";
54             }
55              
56             You can also work directly with a L<WWW::Tumblr::Blog> class for example:
57              
58             # You will need to set base_hostname:
59             my $blog = WWW::Tumblr::Blog->new(
60             %four_tokens,
61             base_hostname => 'myblogontumblr.com'
62             );
63              
64             All operation methods on the entire API will return false in case of an
65             upstream error and you can check the status with C<error()>:
66              
67             die Dumper $blog->error unless $blog->info();
68              
69             On success, methods will return a hash reference with the JSON representation
70             of the upstream response. This behavior has not changed from previous versions
71             of this module.
72              
73             =head1 METHOD PARAMETERS
74              
75             All methods require the same parameters as the upstream API, passed as hash
76             where the keys are the request parameters and the values the corresponding
77             data.
78              
79             =head1 DOCUMENTATION
80              
81             Please refer to each module for further tips, tricks and slightly more detailed
82             documentation:
83              
84             =over
85              
86             =item *
87              
88             L<WWW::Tumblr::Blog>
89              
90             =item *
91              
92             L<WWW::Tumblr::User>
93              
94             =item *
95              
96             L<WWW::Tumblr::Tagged>
97              
98             =item *
99              
100             L<WWW::Tumblr::ResponseError>
101              
102             =back
103              
104             Take also a look at the C<t/> directory inside the distribution. There you can see
105             how you can do a bunch of things: get posts, submissions, post quotes, text,
106             etc, etc.
107              
108             =head1 AUTHORIZATION
109              
110             It is possible to generate authorization URLs and do the whole OAuth dance. Please
111             refer to the C<examples/> directory within the distribution to learn more.
112              
113             =head1 CAVEATS
114              
115             This is considered an experimental version of the module. The request engine
116             needs a complete rewrite, as well as proper documentation. The main author of the
117             module wanted to release it like this to have people interested on Tumblr and Perl
118             give it a spin.
119              
120             =head1 BUGS
121              
122             Please report as many as you want/can. File them up at GitHub:
123             L<https://github.com/damog/www-tumblr/issues/new>. Please don't use the CPAN RT.
124              
125             =head1 MODULE AND TUMBLR API VERSION NOTE
126              
127             This module supports Tumblr API v2, starting from module version 5. Since the
128             previous API was deprecated upstream anyway, there's no backwards compatibility
129             with < 5 versions.
130              
131             =head1 AUTHOR(S)
132              
133             L<David Moreno|http://damog.net/> is the main author and maintainer of this module.
134             The following amazing people have also contributed from version 5 onwards: Artem
135             Krivopolenov, Squeeks, Fernando Vezzosi.
136              
137             =head1 SEE ALSO
138              
139             =over
140              
141             =item *
142              
143             L<Net::OAuth> because, you know, we're based off it.
144              
145             =item *
146              
147             L<Moose>, likewise.
148              
149             =back
150              
151             =head1 COPYRIGHT and LICENSE
152              
153             This software is copyright (c) 2013 by David Moreno.
154            
155             This is free software; you can redistribute it and/or modify it under
156             the same terms as the Perl 5 programming language system itself.
157              
158             =head1 DISCLAIMER
159              
160             The author is in no way affiliated to Tumblr or Yahoo! Inc. If either of them
161             want to show their appreciation for this work, they can contact the author directly
162             or donate a few of those billion dollars Yahoo! paid for Tumblr, to the Perl
163             Foundation at L<http://donate.perlfoundation.org/>.
164              
165             =cut
166              
167 16     16   7144 use Moose;
  16         5313317  
  16         122  
168 16     16   84543 use Carp;
  16         26  
  16         1176  
169 16     16   11130 use Data::Dumper;
  16         87606  
  16         1017  
170 16     16   7667 use HTTP::Request::Common;
  16         285664  
  16         1184  
171 16     16   7472 use Net::OAuth::Client;
  16         427332  
  16         93  
172 16     16   6809 use WWW::Tumblr::API;
  16         52  
  16         84  
173 16     16   16601 use WWW::Tumblr::Blog;
  16         41  
  16         536  
174 16     16   6927 use WWW::Tumblr::User;
  16         43  
  16         540  
175 16     16   6594 use WWW::Tumblr::Authentication;
  16         44  
  16         1163  
176 16     16   118 use LWP::UserAgent;
  16         18  
  16         14187  
177              
178             has 'consumer_key', is => 'rw', isa => 'Str';
179             has 'secret_key', is => 'rw', isa => 'Str';
180             has 'token', is => 'rw', isa => 'Str';
181             has 'token_secret', is => 'rw', isa => 'Str';
182              
183             has 'callback', is => 'rw', isa => 'Str';
184             has 'error', is => 'rw', isa => 'WWW::Tumblr::ResponseError';
185             has 'ua', is => 'rw', isa => 'LWP::UserAgent', default => sub { LWP::UserAgent->new };
186              
187             has 'session_store', is => 'rw', isa => 'HashRef', default => sub { {} };
188              
189             has 'oauth', is => 'rw', isa => 'Net::OAuth::Client', default => sub {
190             my $self = shift;
191             Net::OAuth::Client->new(
192             $self->consumer_key,
193             $self->secret_key,
194             request_token_path => 'http://www.tumblr.com/oauth/request_token',
195             authorize_path => 'http://www.tumblr.com/oauth/authorize',
196             access_token_path => 'http://www.tumblr.com/oauth/access_token',
197             callback => $self->callback,
198             session => sub { if (@_ > 1) { $self->_session($_[0] => $_[1]) }; return $self->_session($_[0]) },
199             );
200             };
201              
202             sub user {
203 6     6 0 16 my ( $self ) = shift;
204 6         192 return WWW::Tumblr::User->new({
205             consumer_key => $self->consumer_key,
206             secret_key => $self->secret_key,
207             token => $self->token,
208             token_secret => $self->token_secret,
209             });
210             }
211              
212             sub blog {
213 8     8 0 20 my ( $self ) = shift;
214 8 50       33 my $name = shift or croak "A blog host name is needed.";
215              
216 8         252 return WWW::Tumblr::Blog->new({
217             consumer_key => $self->consumer_key,
218             secret_key => $self->secret_key,
219             token => $self->token,
220             token_secret => $self->token_secret,
221             base_hostname => $name,
222             });
223             }
224              
225             sub tagged {
226 1     1 0 6 my $self = shift;
227 1         4 my $args = { @_ };
228              
229 1         8 return $self->_tumblr_api_request({
230             auth => 'apikey',
231             http_method => 'GET',
232             url_path => 'tagged',
233             extra_args => $args,
234             });
235             }
236              
237             sub oauth_tools {
238 0     0 0 0 my ( $self ) = shift;
239 0         0 return WWW::Tumblr::Authentication::OAuth->new(
240             consumer_key => $self->consumer_key,
241             secret_key => $self->secret_key,
242             callback => $self->callback,
243             );
244             }
245              
246             sub _tumblr_api_request {
247 21     21   41 my $self = shift;
248 21         32 my $r = shift; #args
249              
250 21         64 my $method_to_call = '_' . $r->{auth} . '_request';
251             return $self->$method_to_call(
252             $r->{http_method}, $r->{url_path}, $r->{extra_args}
253 21         140 );
254             }
255              
256             sub _none_request {
257 1     1   1 my $self = shift;
258 1         2 my $method = shift;
259 1         1 my $url_path = shift;
260 1         1 my $params = shift;
261              
262 1         2 my $req;
263 1 50       3 if ( $method eq 'GET' ) {
    0          
264 1         165 print "Requesting... " .'http://api.tumblr.com/v2/' . $url_path, "\n";
265 1         13 $req = HTTP::Request->new(
266             $method => 'http://api.tumblr.com/v2/' . $url_path,
267             );
268             } elsif ( $method eq 'POST' ) {
269 0         0 Carp::croak "Unimplemented";
270             } else {
271 0         0 die "dude, wtf.";
272             }
273              
274 1         5843 my $res = $self->ua->request( $req );
275              
276 1 50       178299 if ( my $prev = $res->previous ) {
277 0         0 return $prev;
278 1         12 } else { return $res };
279             }
280              
281             sub _apikey_request {
282 6     6   11 my $self = shift;
283 6         9 my $method = shift;
284 6         8 my $url_path = shift;
285 6         9 my $params = shift;
286              
287 6         7 my $req; # request object
288 6 50       19 if ( $method eq 'GET' ) {
    0          
289             $req = HTTP::Request->new(
290             $method => 'http://api.tumblr.com/v2/' . $url_path . '?api_key='.$self->consumer_key . '&' .
291 6         185 ( join '&', map { $_ .'='. $params->{ $_} } keys %$params )
  2         30  
292             );
293             } elsif ( $method eq 'POST' ) {
294 0         0 Carp::croak "Unimplemented";
295             } else {
296 0         0 die "$method misunderstood";
297             }
298              
299 6         24479 my $res = $self->ua->request( $req );
300              
301             }
302              
303             sub _oauth_request {
304 14     14   26 my $self = shift;
305 14         20 my $method = shift;
306 14         22 my $url_path= shift;
307 14         22 my $params = shift;
308              
309 14         25 my $data = delete $params->{data};
310              
311 14         396 my $request = $self->oauth->_make_request(
312             'protected resource',
313             request_method => uc $method,
314             request_url => 'http://api.tumblr.com/v2/' . $url_path,
315             consumer_key => $self->consumer_key,
316             consumer_secret => $self->secret_key,
317             token => $self->token,
318             token_secret => $self->token_secret,
319             extra_params => $params,
320             );
321 14         29257 $request->sign;
322              
323 14         139589 my $authorization_signature = $request->to_authorization_header;
324              
325 14         7080 my $message;
326 14 100       77 if ( $method eq 'GET' ) {
    50          
327 8         33 $message = GET 'http://api.tumblr.com/v2/' . $url_path . '?' . $request->normalized_message_parameters, 'Authorization' => $authorization_signature;
328             } elsif ( $method eq 'POST' ) {
329             $message = POST('http://api.tumblr.com/v2/' . $url_path,
330             Content_Type => 'form-data',
331             Authorization => $authorization_signature,
332             Content => [
333 6 100       59 %$params, ( $data ? do {
334 2         4 my $i = -1;
335 2         7 map { $i++; 'data[' . $i .']' => [ $_ ] } @$data
  3         4  
  3         26  
336             } : () )
337             ]);
338             }
339              
340 14         33734 return $self->ua->request( $message );
341             }
342              
343             sub _session {
344 0     0     my $self = shift;
345              
346 0 0         if ( ref $_[0] eq 'HASH' ) {
    0          
347 0           $self->session_store($_[0]);
348             } elsif ( @_ > 1 ) {
349 0           $self->session_store->{$_[0]} = $_[1]
350             }
351 0 0         return $_[0] ? $self->session_store->{$_[0]} : $self->session_store;
352             }
353              
354             1;
355